public async Task MaxPoolSizeNotViolated() { using (var pool = new SessionPool()) { pool.Options.MaximumPooledSessions = 2; var client = CreateMockClient(); var sessions = await Task.WhenAll( pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None), pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None), pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None)) .ConfigureAwait(false); pool.ReleaseToPool(client.Object, sessions[0]); pool.ReleaseToPool(client.Object, sessions[1]); pool.ReleaseToPool(client.Object, sessions[2]); Assert.Equal( 2, pool.GetPoolSize( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId)); } }
/// <summary> /// Creates <paramref name="parallelCount"/> read sessions simultaneously over /// <paramref name="iterations"/> number of iterations. /// </summary> private async Task CreateReleaseReadSessions( SessionPool pool, SpannerClient client, int iterations, int parallelCount) { // We yield to increase contention among parallel tasks that are kicked off. // This increases the amount of work they are doing on another thread. await Task.Yield(); for (var i = 0; i < iterations; i++) { var readOptions = new TransactionOptions { ReadOnly = new TransactionOptions.Types.ReadOnly() }; var readSessions = await Task.WhenAll( DuplicateTaskAsync(() => CreateSessionAsync(pool, client, readOptions), parallelCount)); await Task.Delay(TimeSpan.FromMilliseconds(10)); foreach (var session in readSessions) { pool.ReleaseToPool(client, session); } } }
/// <summary> /// Creates <paramref name="parallelCount"/> write sessions simultaneously over /// <paramref name="iterations"/> number of iterations. /// </summary> private async Task CreateReleaseWriteSessions( SessionPool pool, SpannerClient client, int iterations, int parallelCount) { // We yield to increase contention among parallel tasks that are kicked off. // This increases the amount of work they are doing on another thread. await Task.Yield(); for (var i = 0; i < iterations; i++) { var readWriteOptions = new TransactionOptions { ReadWrite = new TransactionOptions.Types.ReadWrite() }; var writeSessions = await Task.WhenAll( DuplicateTaskAsync(() => CreateSessionAsync(pool, client, readWriteOptions), parallelCount)); await Task.Delay(TimeSpan.FromMilliseconds(10)); foreach (var session in writeSessions) { var transaction = await TransactionPool.BeginPooledTransactionAsync(client, session, readWriteOptions); await TransactionPool.CommitAsync(transaction, session, new Mutation[0], SpannerOptions.Instance.Timeout, CancellationToken.None); pool.ReleaseToPool(client, session); } } }
public async Task MaxActiveViolation_WaitOnResourcesExhausted_Blocks() { using (var pool = new SessionPool()) { pool.Options.WaitOnResourcesExhausted = true; pool.Options.MaximumActiveSessions = 2; var client = new FakeClient(); var session1 = await CreateSessionAsync(pool, client); var session2 = await CreateSessionAsync(pool, client); var createTask = CreateSessionAsync(pool, client); await Task.WhenAll(createTask, ReleaseAfterDelay(session1)); Assert.Same(session1, await createTask); async Task ReleaseAfterDelay(Session session) { await Task.Delay(TimeSpan.FromMilliseconds(10)); pool.ReleaseToPool(client, session); } } }
public async Task MaxActiveViolationBlocks() { using (var pool = new SessionPool()) { pool.Options.WaitOnResourcesExhausted = true; pool.Options.MaximumActiveSessions = 2; var client = CreateMockClient(); var session1 = await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); async Task ReleaseTask() { await Task.Delay(TimeSpan.FromMilliseconds(10)); pool.ReleaseToPool(client.Object, session1); } var createTask = pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None); await Task.WhenAll(createTask, ReleaseTask()).ConfigureAwait(false); Assert.Same(session1, createTask.ResultWithUnwrappedExceptions()); } }
public async Task ClientsHaveDifferentPools() { using (var pool = new SessionPool()) { var client1 = CreateMockClient(); var client2 = CreateMockClient(); var session = await pool.CreateSessionFromPoolAsync( client1.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); pool.ReleaseToPool(client1.Object, session); var session2 = await pool.CreateSessionFromPoolAsync( client2.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); Assert.NotSame(session, session2); Assert.Equal(2, _createdSessions.Count); Assert.Equal(1, _createdSessions[client1].Count); Assert.Equal(1, _createdSessions[client2].Count); } }
/// <summary> /// Creates <paramref name="parallelCount"/> read sessions simultaneously over /// <paramref name="iterations"/> number of iterations. /// </summary> private async Task CreateReleaseReadSessions( SessionPool pool, SpannerClient client, int iterations, int parallelCount) { // We yield to increase contention among parallel tasks that are kicked off. // This increases the amount of work they are doing on another thread. await Task.Yield(); for (var i = 0; i < iterations; i++) { var readOptions = new TransactionOptions { ReadOnly = new TransactionOptions.Types.ReadOnly() }; var readSessions = await Task.WhenAll( DuplicateTaskAsync( () => pool.CreateSessionFromPoolAsync( client, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, readOptions, CancellationToken.None), parallelCount)) .ConfigureAwait(false); await Task.Delay(TimeSpan.FromMilliseconds(10)).ConfigureAwait(false); foreach (var session in readSessions) { pool.ReleaseToPool(client, session); } } }
public async Task MaxPoolSizeNotViolated() { using (var pool = new SessionPool()) { pool.Options.MaximumPooledSessions = 2; var client = new FakeClient(); var sessions = await Task.WhenAll( CreateSessionAsync(pool, client), CreateSessionAsync(pool, client), CreateSessionAsync(pool, client)); pool.ReleaseToPool(client, sessions[0]); pool.ReleaseToPool(client, sessions[1]); pool.ReleaseToPool(client, sessions[2]); var actualSize = pool.GetPoolSize(client, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId); Assert.Equal(2, actualSize); } }
public async Task TransactionOptionsAreMatched() { using (var pool = new SessionPool()) { var client = new FakeClient(); var readWriteOptions = new TransactionOptions { ReadWrite = new TransactionOptions.Types.ReadWrite() }; // First acquire and use a session with a read/write transaction var rwSession = await CreateSessionAsync(pool, client, readWriteOptions); var transaction = await TransactionPool.BeginPooledTransactionAsync(client, rwSession, readWriteOptions); // Acquire a second session using the default transaction options var readOnlySession = await CreateSessionAsync(pool, client, s_defaultTransactionOptions); Assert.NotSame(rwSession, readOnlySession); // Finish with the read-only session pool.ReleaseToPool(client, readOnlySession); // Finish with the read/write session await TransactionPool.CommitAsync(transaction, rwSession, new Mutation[0], SpannerOptions.Instance.Timeout, CancellationToken.None); pool.ReleaseToPool(client, rwSession); // At this point, our MRU list has: // - The r/w session // - The read-only session // If we ask for another read-only session, we should skip the r/w one, and get back the read-only one. // This test needs the r/w session to be there, as if the match attempt doesn't find anything, we just return // the most recently used session. var readOnlySession2 = await CreateSessionAsync(pool, client, s_defaultTransactionOptions); Assert.Same(readOnlySession, readOnlySession2); } }
public async Task SynchronousRelease() { using (var pool = new SessionPool()) { var client = new FakeClient(); var session1 = await CreateSessionAsync(pool, client); pool.ReleaseToPool(client, session1); var session2 = await CreateSessionAsync(pool, client); Assert.Same(session1, session2); } }
public async Task ExpiredSessionsNotPooled() { using (var pool = new SessionPool()) { var client = new FakeClient(); var session = await CreateSessionAsync(pool, client); SessionPool.MarkSessionExpired(session); pool.ReleaseToPool(client, session); var session2 = await CreateSessionAsync(pool, client); Assert.NotSame(session, session2); Assert.Equal(2, client.Sessions.Count); } }
public async Task DatabasesHaveDifferentPools() { using (var pool = new SessionPool()) { var client = new FakeClient(); var session1 = await CreateSessionAsync(pool, client); pool.ReleaseToPool(client, session1); var session2 = await pool.CreateSessionFromPoolAsync( client, "newproject", "newinstance", "newdbid", s_defaultTransactionOptions, CancellationToken.None); Assert.NotSame(session1, session2); Assert.Equal(2, client.Sessions.Count); } }
public async Task SessionPreWarmTx() { using (var pool = new SessionPool()) { var client = CreateMockClient(); var txOptions = new TransactionOptions { ReadWrite = new TransactionOptions.Types.ReadWrite() }; var session1 = await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, txOptions, CancellationToken.None) .ConfigureAwait(false); var transactionAwaited = await client.Object.BeginPooledTransactionAsync(session1, txOptions) .ConfigureAwait(false); Transaction transaction; Assert.True(_transactions.TryPop(out transaction)); Assert.Same(transaction, transactionAwaited); await transaction.CommitAsync(session1, null, SpannerOptions.Instance.Timeout).ConfigureAwait(false); //Releasing should start the tx prewarm pool.ReleaseToPool(client.Object, session1); Transaction preWarmTx; var stopwatch = Stopwatch.StartNew(); while (!_transactions.TryPop(out preWarmTx)) { await Task.Yield(); //everything is simulated, so the prewarm should be immediate. Assert.True(stopwatch.Elapsed < TimeSpan.FromMilliseconds(500)); } var session2 = await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, txOptions, CancellationToken.None) .ConfigureAwait(false); var transaction2 = await client.Object.BeginPooledTransactionAsync(session2, txOptions) .ConfigureAwait(false); Assert.Same(preWarmTx, transaction2); Assert.True(_transactions.IsEmpty); } }
public async Task ClientsHaveDifferentPools() { using (var pool = new SessionPool()) { var client1 = new FakeClient(); var client2 = new FakeClient(); var session1 = await CreateSessionAsync(pool, client1); pool.ReleaseToPool(client1, session1); var session2 = await CreateSessionAsync(pool, client2); Assert.NotSame(session1, session2); Assert.Equal(1, client1.Sessions.Count); Assert.Equal(1, client2.Sessions.Count); } }
public async Task SynchronousRelease() { using (var pool = new SessionPool()) { var client = CreateMockClient(); var session = await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); pool.ReleaseToPool(client.Object, session); var session2 = await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); Assert.Same(session, session2); } }
public async Task SessionPreWarmTx() { using (var pool = new SessionPool()) { var client = new FakeClient(); var txOptions = new TransactionOptions { ReadWrite = new TransactionOptions.Types.ReadWrite() }; var session1 = await CreateSessionAsync(pool, client, txOptions); var transactionAwaited = await TransactionPool.BeginPooledTransactionAsync(client, session1, txOptions); Transaction transaction; Assert.True(client.Transactions.TryPop(out transaction)); Assert.Same(transaction, transactionAwaited); await TransactionPool.CommitAsync(transaction, session1, new Mutation[0], SpannerOptions.Instance.Timeout, CancellationToken.None); // Releasing should create a new transaction as a prewarm pool.ReleaseToPool(client, session1); Transaction preWarmTx; var stopwatch = Stopwatch.StartNew(); while (!client.Transactions.TryPop(out preWarmTx)) { await Task.Yield(); //everything is simulated, so the prewarm should be immediate. Assert.True(stopwatch.Elapsed < TimeSpan.FromMilliseconds(500)); } var session2 = await CreateSessionAsync(pool, client, txOptions); var transaction2 = await TransactionPool.BeginPooledTransactionAsync(client, session2, txOptions); Assert.Same(preWarmTx, transaction2); Assert.True(client.Transactions.IsEmpty); } }