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)); } }
public async Task MaxActiveViolationThrows() { using (var pool = new SessionPool()) { pool.Options.WaitOnResourcesExhausted = false; pool.Options.MaximumActiveSessions = 2; var exceptionThrown = false; var client = CreateMockClient(); 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); try { await pool.CreateSessionFromPoolAsync( client.Object, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None) .ConfigureAwait(false); } catch (RpcException e) { Assert.Equal(StatusCode.ResourceExhausted, e.Status.StatusCode); exceptionThrown = true; } Assert.True(exceptionThrown); } }
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 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 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 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 EmptyPoolCreatesNewSession() { 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); Assert.Equal(1, _createdSessions.Count); Assert.Equal(1, _createdSessions[client].Count); Assert.Same(session, _createdSessions[client][0]); client.Verify( x => x.CreateSessionAsync( It.Is <DatabaseName>(y => y.Equals(s_defaultName)), It.IsAny <CancellationToken>()), Times.Once); } }
public async Task SessionCreateIsThrottled() { using (var pool = new SessionPool()) { pool.Options.MaximumConcurrentSessionCreates = 2; //we use a specially designed mock that records simultaneous create calls. //Moq actually does internal synchronization that disallows parallel calls. var mockClient = new ParallelSpannerClient(); var sessionList = Enumerable.Range(0, 100).Select( x => pool.CreateSessionFromPoolAsync( mockClient, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, null, CancellationToken.None)).ToList(); await Task.WhenAll(sessionList).ConfigureAwait(false); Assert.True(mockClient.MaxConcurrentRequests <= pool.Options.MaximumConcurrentSessionCreates); } }
/// <summary> /// Helper to create a session with default project/instance/database arguments. /// (Most tests use these.) /// </summary> private static Task <Session> CreateSessionAsync(SessionPool pool, SpannerClient client, TransactionOptions options = null) => pool.CreateSessionFromPoolAsync( client, s_defaultName.ProjectId, s_defaultName.InstanceId, s_defaultName.DatabaseId, options ?? s_defaultTransactionOptions, CancellationToken.None);