public async Task ScheduledMaintenanceEvictsSessions_DifferentEvictionTimes() { var client = new SessionTestingSpannerClient(); var options = new SessionPoolOptions { // We'll never actually hit a refresh, as the eviction delay is shorter. IdleSessionRefreshDelay = TimeSpan.FromMinutes(30), PoolEvictionDelay = TimeSpan.FromMinutes(3), MaintenanceLoopDelay = TimeSpan.FromMinutes(1), SessionEvictionJitter = RetrySettings.NoJitter, MinimumPooledSessions = 10, MaximumConcurrentSessionCreates = 20, WriteSessionsFraction = 0 }; var sessionPool = new SessionPool(client, options); var acquisitionTask = sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default); await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); // Our session should be ready, the pool should be up to size, and we should // have created 11 sessions in total. var session = await acquisitionTask; var stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.Equal(10, stats.ReadPoolCount); Assert.Equal(11, client.SessionsCreated); Assert.Equal(0, client.SessionsDeleted); // Force the creation of a newer session by acquiring one. // The new one will be created to satisfy the minimum size of the pool // and will sit on top of the stack. // First move the pool to T=2, so that the new session will be created in T=3 // so that its eviction time will be T=6 so as to make sure that it's not // being evicted when we check at T=5. await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); acquisitionTask = sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default); await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); session = await acquisitionTask; stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.Equal(10, stats.ReadPoolCount); Assert.Equal(12, client.SessionsCreated); Assert.Equal(0, client.SessionsDeleted); // If we allow the maintenance pool to run until T=5 minutes, we should have evicted // all the old 9 sessions in the pool and replaced them with 9 new ones. await client.Scheduler.RunAsync(TimeSpan.FromMinutes(2)); stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.Equal(10, stats.ReadPoolCount); Assert.Equal(21, client.SessionsCreated); Assert.Equal(9, client.SessionsDeleted); }
public async Task GetStatisticsSnapshot_MultipleDatabases() { var client = new SessionTestingSpannerClient(); var options = new SessionPoolOptions { MinimumPooledSessions = 10, }; var sessionPool = new SessionPool(client, options); var acquisitionTask1 = sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default); var acquisitionTask2 = sessionPool.AcquireSessionAsync(s_sampleDatabaseName2, new TransactionOptions(), default); var stats = sessionPool.GetStatisticsSnapshot(); Assert.Equal(2, stats.PerDatabaseStatistics.Count); Assert.Equal(2, stats.TotalActiveSessionCount); Assert.Equal(0, stats.TotalReadPoolCount); // We've asked for 2 sessions, and the databases "know" they need 10 in the pool (each), so // there will be 22 in-flight requests in total. Assert.Equal(22, stats.TotalInFlightCreationCount); Assert.Contains(stats.PerDatabaseStatistics, s => s.DatabaseName == s_sampleDatabaseName); Assert.Contains(stats.PerDatabaseStatistics, s => s.DatabaseName == s_sampleDatabaseName2); // xUnit waits until tasks registered in its synchronization context have completed before considering the // test itself complete, so we need to let the pool complete the acquisition tasks. await client.Scheduler.RunAsync(TimeSpan.FromMinutes(2)); }
public void GetStatisticsSnapshot_UnrepresentedDatabase() { var client = new SessionTestingSpannerClient(); var options = new SessionPoolOptions(); var sessionPool = new SessionPool(client, options); // We haven't used the database in this session pool, so there are no statistics for it. Assert.Null(sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName)); }
public async Task ScheduledMaintenanceEvictsSessions() { var client = new SessionTestingSpannerClient(); var options = new SessionPoolOptions { // We'll never actually hit a refresh, as the eviction delay is shorter. IdleSessionRefreshDelay = TimeSpan.FromMinutes(30), PoolEvictionDelay = TimeSpan.FromMinutes(3), MaintenanceLoopDelay = TimeSpan.FromMinutes(1), SessionEvictionJitter = RetrySettings.NoJitter, MinimumPooledSessions = 10, MaximumConcurrentSessionCreates = 20, WriteSessionsFraction = 0 }; var sessionPool = new SessionPool(client, options); var acquisitionTask = sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default); await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); // Our session should be ready, the pool should be up to size, and we should // have created 11 sessions in total. var session = await acquisitionTask; var stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.Equal(10, stats.ReadPoolCount); Assert.Equal(11, client.SessionsCreated); Assert.Equal(0, client.SessionsDeleted); // If we allow the maintenance pool to run until T=5 minutes, we should have evicted // all the 10 sessions in the pool and replaced them. await client.Scheduler.RunAsync(TimeSpan.FromMinutes(4)); stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.Equal(10, stats.ReadPoolCount); Assert.Equal(21, client.SessionsCreated); Assert.Equal(10, client.SessionsDeleted); }
public async Task ShutdownPoolAsync() { var client = new SessionTestingSpannerClient(); var options = new SessionPoolOptions { IdleSessionRefreshDelay = TimeSpan.FromMinutes(30), PoolEvictionDelay = TimeSpan.FromMinutes(30), MaintenanceLoopDelay = TimeSpan.FromMinutes(1), MinimumPooledSessions = 10, MaximumConcurrentSessionCreates = 20, WriteSessionsFraction = 0 }; var sessionPool = new SessionPool(client, options); var acquisitionTask = sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default); // After a minute, we should have a session. Release it immediately for simplicity. await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); var session = await acquisitionTask; session.ReleaseToPool(false); // Shut the pool down, and wait a minute. (It won't take that long, as nothing's pending.) var shutdownTask = sessionPool.ShutdownPoolAsync(s_sampleDatabaseName, default); await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); // Now the shutdown task should have completed, and the stats will know that it's shut down. await shutdownTask; var stats = sessionPool.GetStatisticsSnapshot(s_sampleDatabaseName); Assert.True(stats.Shutdown); // We can't get sessions any more for this database await Assert.ThrowsAsync <InvalidOperationException>(() => sessionPool.AcquireSessionAsync(s_sampleDatabaseName, new TransactionOptions(), default)); // But we can for a different database. (It shuts down a single database pool, not the whole session pool.) var acquisitionTask2 = sessionPool.AcquireSessionAsync(s_sampleDatabaseName2, new TransactionOptions(), default); await client.Scheduler.RunAsync(TimeSpan.FromMinutes(1)); await acquisitionTask2; }