public async Task ExecuteSqlAsync_RequestTransactionIsLeftAlonePopulatedWhenPresent() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Make a successful request var request = new ExecuteSqlRequest { Transaction = new TransactionSelector { Begin = new TransactionOptions { ReadOnly = new TransactionOptions.Types.ReadOnly() } } }; pool.Mock.Setup(client => client.ExecuteSqlAsync(request, It.IsAny <CallSettings>())) .ReturnsAsync(new ResultSet()) .Verifiable(); await pooledSession.ExecuteSqlAsync(request, 5, CancellationToken.None); // The call modifies the request's session, but not transaction. Assert.Equal(s_sampleSessionName, request.SessionAsSessionName); Assert.Equal(TransactionSelector.SelectorOneofCase.Begin, request.Transaction.SelectorCase); Assert.Equal(new TransactionOptions.Types.ReadOnly(), request.Transaction.Begin.ReadOnly); pool.Mock.Verify(); }
public void Expiry() { var pool = new FakeSessionPool(); var options = pool.Options; var clock = pool.Clock; var originalTime = clock.GetCurrentDateTimeUtc(); // If we evict sessions before we refresh them, things get weird. Assert.True(options.IdleSessionRefreshDelay < options.PoolEvictionDelay); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); Assert.False(pooledSession.ShouldBeEvicted); Assert.False(pooledSession.RequiresRefresh); // Detect the need for a refresh clock.AdvanceTo(originalTime + options.IdleSessionRefreshDelay + OneTick); Assert.False(pooledSession.ShouldBeEvicted); Assert.True(pooledSession.RequiresRefresh); // Detect the need for eviction clock.AdvanceTo(originalTime + options.PoolEvictionDelay + OneTick); Assert.True(pooledSession.ShouldBeEvicted); Assert.True(pooledSession.RequiresRefresh); }
public override void Release(PooledSession session, bool deleteSession) { if (deleteSession) { Parent.DeleteSessionFireAndForget(session); } }
public async Task AutoRefreshOnSuccessfulRpc() { var pool = new FakeSessionPool(); var options = pool.Options; var clock = pool.Clock; var originalTime = clock.GetCurrentDateTimeUtc(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); var halfRefresh = TimeSpan.FromTicks(options.IdleSessionRefreshDelay.Ticks / 2); clock.Advance(halfRefresh); // Make a successful request var request = new BeginTransactionRequest(); var response = new Transaction(); pool.Mock.Setup(client => client.BeginTransactionAsync(request, It.IsAny <CallSettings>())) .ReturnsAsync(response) .Verifiable(); await pooledSession.BeginTransactionAsync(request, 5, CancellationToken.None); // The request will have extended the refresh time. Assert.Equal(clock.GetCurrentDateTimeUtc() + options.IdleSessionRefreshDelay, pooledSession.RefreshTimeForTest); pool.Mock.Verify(); }
public void ReleaseToPool_NoDelete() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); pooledSession.ReleaseToPool(false); Assert.False(pool.ReleasedSessionDeleted); }
public void ReleaseToPool_ForceDelete() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); pooledSession.ReleaseToPool(true); Assert.True(pool.ReleasedSessionDeleted); }
public void WithTransaction() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); var transactionId = ByteString.CopyFromUtf8("transaction"); var mode = TransactionOptions.ModeOneofCase.PartitionedDml; var sessionWithTransaction = pooledSession.WithTransaction(transactionId, mode); Assert.Equal(mode, sessionWithTransaction.TransactionMode); Assert.Equal(transactionId, sessionWithTransaction.TransactionId); Assert.Equal(s_sampleSessionName, sessionWithTransaction.SessionName); }
public async Task ReleaseToPool_FurtherRpcsInvalid() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Release the session immediately pooledSession.ReleaseToPool(false); // We now can't make RPCs await Assert.ThrowsAsync <ObjectDisposedException>( () => pooledSession.BeginTransactionAsync(new BeginTransactionRequest(), 5, CancellationToken.None)); }
public void FromSessionName_BasicProperties() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); Assert.Same(s_sampleSessionName, pooledSession.SessionName); Assert.False(pooledSession.ShouldBeEvicted); Assert.False(pooledSession.RequiresRefresh); Assert.False(pooledSession.ServerExpired); Assert.Null(pooledSession.TransactionId); Assert.Equal(TransactionOptions.ModeOneofCase.None, pooledSession.TransactionMode); }
public Task <ReliableStreamReader> ExecuteQueryAsync(ExecuteSqlRequest request, CancellationToken cancellationToken, int timeoutSeconds) { return(ExecuteHelper.WithErrorTranslationAndProfiling(Impl, "EphemeralTransaction.ExecuteQuery", _connection.Logger)); async Task <ReliableStreamReader> Impl() { PooledSession session = await _connection.AcquireSessionAsync(_transactionOptions, cancellationToken).ConfigureAwait(false); var reader = session.ExecuteSqlStreamReader(request, timeoutSeconds); reader.StreamClosed += delegate { session.ReleaseToPool(forceDelete: false); }; return(reader); } }
public async Task RequestSessionIsPopulated() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Make a successful request var request = new BeginTransactionRequest(); pool.Mock.Setup(client => client.BeginTransactionAsync(request, It.IsAny <CallSettings>())).ReturnsAsync(new Transaction()); await pooledSession.BeginTransactionAsync(request, 5, CancellationToken.None); // The call modifies the request. (We can't easily check that it was modified before the RPC) Assert.Equal(s_sampleSessionName, request.SessionAsSessionName); }
public async Task DetectSessionExpiry() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Make a request which fails due to the session not being found (because it has expired). var request = new BeginTransactionRequest(); pool.Mock.Setup(client => client.BeginTransactionAsync(request, It.IsAny <CallSettings>())) .ThrowsAsync(new RpcException(new Status(StatusCode.NotFound, "Session not found"))); await Assert.ThrowsAsync <RpcException>(() => pooledSession.BeginTransactionAsync(request, 5, CancellationToken.None)); Assert.True(pooledSession.ServerExpired); }
public void ReleaseToPool_SessionExpired() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Let it go past its eviction time var clock = pool.Clock; clock.Advance(pool.Options.PoolEvictionDelay + OneTick); // When we release the session, the pool should delete it even if we didn't ask it to. pooledSession.ReleaseToPool(false); Assert.True(pool.ReleasedSessionDeleted); }
public void TransactionConstructor() { var connection = new SpannerConnection(); var pool = new FakeSessionPool(); var session = PooledSession.FromSessionName(pool, new SessionName("project", "instance", "database", "session")); var transaction = new SpannerTransaction(connection, TransactionMode.ReadWrite, session: session, timestampBound: null); var command = new SpannerBatchCommand(transaction); Assert.Empty(command.Commands); Assert.Same(connection, command.Connection); Assert.Same(transaction, command.Transaction); Assert.Equal(SpannerBatchCommandType.None, command.CommandType); }
public async Task ReleaseToPool_SessionInvalidatedByServer() { var pool = new FakeSessionPool(); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); // Make a request which fails due to the session not being found (because it has expired). var request = new BeginTransactionRequest(); pool.Mock.Setup(client => client.BeginTransactionAsync(request, It.IsAny <CallSettings>())) .ThrowsAsync(new RpcException(new Status(StatusCode.NotFound, "Session not found"))); await Assert.ThrowsAsync <RpcException>(() => pooledSession.BeginTransactionAsync(request, 5, CancellationToken.None)); // When we release the session, the pool should delete it even if we didn't ask it to. pooledSession.ReleaseToPool(false); Assert.True(pool.ReleasedSessionDeleted); }
public Task <ReliableStreamReader> ExecuteReadOrQueryAsync(ReadOrQueryRequest request, CancellationToken cancellationToken, int timeoutSeconds /* ignored */) { return(ExecuteHelper.WithErrorTranslationAndProfiling(Impl, "EphemeralTransaction.ExecuteReadOrQuery", _connection.Logger)); async Task <ReliableStreamReader> Impl() { PooledSession session = await _connection.AcquireSessionAsync(_transactionOptions, cancellationToken).ConfigureAwait(false); var callSettings = _connection.CreateCallSettings( request.GetCallSettings, cancellationToken); var reader = request.ExecuteReadOrQueryStreamReader(session, callSettings); reader.StreamClosed += delegate { session.ReleaseToPool(forceDelete: false); }; return(reader); } }
public async Task ExecuteSqlAsync_RequestTransactionIsPopulatedWhenPresent() { var pool = new FakeSessionPool(); var transactionId = ByteString.CopyFromUtf8("transaction"); var mode = TransactionOptions.ModeOneofCase.ReadWrite; var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); var sessionWithTransaction = pooledSession.WithTransaction(transactionId, mode); // Make a successful request var request = new ExecuteSqlRequest(); pool.Mock.Setup(client => client.ExecuteSqlAsync(request, It.IsAny <CallSettings>())).ReturnsAsync(new ResultSet()); await sessionWithTransaction.ExecuteSqlAsync(request, 5, CancellationToken.None); // The call modifies the request. (We can't easily check that it was modified before the RPC) Assert.Equal(s_sampleSessionName, request.SessionAsSessionName); Assert.Equal(transactionId, request.Transaction.Id); }
public async Task ExecuteBatchDmlAsync_RequestTransactionIsPopulatedWhenNotPresent() { var pool = new FakeSessionPool(); var transactionId = ByteString.CopyFromUtf8("transaction"); var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName); var sessionWithTransaction = pooledSession.WithTransaction(transactionId, ReadWrite); // Make a successful request var request = new ExecuteBatchDmlRequest(); pool.Mock.Setup(client => client.ExecuteBatchDmlAsync(request, It.IsAny <CallSettings>())) .ReturnsAsync(new ExecuteBatchDmlResponse()) .Verifiable(); await sessionWithTransaction.ExecuteBatchDmlAsync(request, null); // The call modifies the request. (We can't easily check that it was modified before the RPC) Assert.Equal(s_sampleSessionName, request.SessionAsSessionName); Assert.Equal(transactionId, request.Transaction.Id); pool.Mock.Verify(); }
public async Task <long> CustomTimeoutsAndRetriesAsync(string projectId, string instanceId, string databaseId) { // Create a SessionPool. SpannerClient client = SpannerClient.Create(); SessionPool sessionPool = new SessionPool(client, new SessionPoolOptions()); // Acquire a session with a read-write transaction to run a query. DatabaseName databaseName = DatabaseName.FromProjectInstanceDatabase(projectId, instanceId, databaseId); TransactionOptions transactionOptions = new TransactionOptions { ReadWrite = new ReadWrite() }; using PooledSession session = await sessionPool.AcquireSessionAsync( databaseName, transactionOptions, CancellationToken.None); ExecuteSqlRequest request = new ExecuteSqlRequest { Sql = "INSERT Singers (SingerId, FirstName, LastName) VALUES (20, 'George', 'Washington')" }; // Prepare the call settings with custom timeout and retry settings. CallSettings settings = CallSettings .FromExpiration(Expiration.FromTimeout(TimeSpan.FromSeconds(60))) .WithRetry(RetrySettings.FromExponentialBackoff( maxAttempts: 12, initialBackoff: TimeSpan.FromMilliseconds(500), maxBackoff: TimeSpan.FromMilliseconds(6400), backoffMultiplier: 1.5, retryFilter: RetrySettings.FilterForStatusCodes( new StatusCode[] { StatusCode.Unavailable, StatusCode.DeadlineExceeded }))); ResultSet result = await session.ExecuteSqlAsync(request, settings); await session.CommitAsync(new CommitRequest(), null); return(result.Stats.RowCountExact); }
internal async Task <TResult> RunAsync <TResult>(Func <SpannerTransaction, Task <TResult> > asyncWork, CancellationToken cancellationToken = default) { GaxPreconditions.CheckNotNull(asyncWork, nameof(asyncWork)); // Session will be initialized and subsequently modified by CommitAttempt. PooledSession session = null; try { return(await ExecuteWithRetryAsync(CommitAttempt, cancellationToken).ConfigureAwait(false)); } finally { session?.Dispose(); } async Task <TResult> CommitAttempt() { return(await ExecuteHelper.WithErrorTranslationAndProfiling( async() => { SpannerTransaction transaction = null; try { session = await(session?.WithFreshTransactionOrNewAsync(SpannerConnection.s_readWriteTransactionOptions, cancellationToken) ?? _connection.AcquireReadWriteSessionAsync(cancellationToken)).ConfigureAwait(false); transaction = new SpannerTransaction(_connection, TransactionMode.ReadWrite, session, null); TResult result = await asyncWork(transaction).ConfigureAwait(false); await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); return result; } // We only catch to attempt a rollback, and that is possible if we have a transaction already. // If the exception was thrown when refreshing the session the we don't have a transaction yet. catch when(transaction != null) { try { await transaction.RollbackAsync(cancellationToken).ConfigureAwait(false); } catch (Exception e) { // If the commit failed, calling Rollback will fail as well. // We don't want that or any other rollback exception to propagate, // it will not trigger the retry _connection.Logger.Warn("A rollback attempt failed on RetriableTransaction.RunAsync.CommitAttempt", e); } // Throw, the retry helper will know when to retry. throw; } finally { if (transaction != null) { // Let's make sure that the associated session is not released to the pool // because we'll be attempting to get a fresh transaction for this same session first. // If that fails will attempt a new session acquisition. // This session will be disposed of by the pool if it can't be refreshed or by the RunAsync method // if we are not retrying anymore. transaction.DisposeBehavior = DisposeBehavior.Detach; transaction.Dispose(); } } }, "RetriableTransaction.RunAsync.CommitAttempt", _connection.Logger).ConfigureAwait(false)); } }
public void Release(PooledSession session, ByteString transactionId, bool deleteSession) => throw new NotImplementedException();
public void Release(PooledSession session, bool deleteSession) { ReleasedSessionDeleted = deleteSession; }
private PooledSession CreateWithTransaction(SessionPool.ISessionPool pool, TransactionOptions.ModeOneofCase mode) { ByteString transactionId = ByteString.CopyFromUtf8(Guid.NewGuid().ToString()); return(PooledSession.FromSessionName(pool, s_sampleSessionName).WithTransaction(transactionId, mode)); }
public void Release(PooledSession session, ByteString transactionToRollback, bool deleteSession) { RolledBackTransaction = transactionToRollback; ReleasedSessionDeleted = deleteSession; }
public Task <PooledSession> WithFreshTransactionOrNewAsync(PooledSession session, TransactionOptions transactionOptions, CancellationToken cancellationToken) => throw new NotImplementedException();
public void Release(PooledSession session, bool deleteSession) => throw new NotImplementedException();