Exemple #1
0
        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();
        }
Exemple #2
0
        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);
     }
 }
Exemple #4
0
        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();
        }
Exemple #5
0
        public void ReleaseToPool_NoDelete()
        {
            var pool          = new FakeSessionPool();
            var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName);

            pooledSession.ReleaseToPool(false);
            Assert.False(pool.ReleasedSessionDeleted);
        }
Exemple #6
0
        public void ReleaseToPool_ForceDelete()
        {
            var pool          = new FakeSessionPool();
            var pooledSession = PooledSession.FromSessionName(pool, s_sampleSessionName);

            pooledSession.ReleaseToPool(true);
            Assert.True(pool.ReleasedSessionDeleted);
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        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));
        }
Exemple #9
0
        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);
        }
Exemple #10
0
        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);
            }
        }
Exemple #11
0
        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);
        }
Exemple #12
0
        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);
        }
Exemple #13
0
        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);
        }
Exemple #14
0
        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);
        }
Exemple #15
0
        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);
        }
Exemple #16
0
        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);
            }
        }
Exemple #17
0
        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));
            }
        }
Exemple #21
0
 public void Release(PooledSession session, ByteString transactionId, bool deleteSession) => throw new NotImplementedException();
Exemple #22
0
 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();
Exemple #26
0
 public void Release(PooledSession session, bool deleteSession) => throw new NotImplementedException();