Ejemplo n.º 1
0
 public void Dispose()
 {
     try
     {
         _transaction?.Dispose();
         // Protect against multiple disposals
         _transaction = null;
     }
     catch (Exception e)
     {
         Logger.Error("Error disposing", e);
     }
 }
Ejemplo n.º 2
0
 public void Dispose()
 {
     _transaction?.Dispose();
 }
        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));
            }
        }