async Task IRetriableStatement.RetryAsync(SpannerRetriableTransaction transaction, CancellationToken cancellationToken, int timeoutSeconds)
        {
            try
            {
                await _command.CreateSpannerBatchCommand().ExecuteNonQueryAsync(cancellationToken);

                // Fallthrough and throw the exception at the end of the method.
            }
            catch (SpannerBatchNonQueryException e)
            {
                // Check that we got the exact same exception and results this time as the previous time.
                if (_exception is SpannerBatchNonQueryException batchException &&
                    e.ErrorCode == _exception.ErrorCode &&
                    e.Message.Equals(_exception.Message)
                    // A Batch DML statement returns the update counts of the first N statements and the error
                    // that occurred for statement N+1.
                    && e.SuccessfulCommandResults.SequenceEqual(batchException.SuccessfulCommandResults)
                    )
                {
                    return;
                }
            }
            catch (SpannerException e) when(e.ErrorCode != ErrorCode.Aborted)
            {
                // Check that we got the exact same exception during the retry as during the initial attempt.
                // This happens if the Batch DML RPC itself failed, and not one of the DML statements.
                if (!(_exception is SpannerBatchNonQueryException) && SpannerRetriableTransaction.SpannerExceptionsEqualForRetry(e, _exception))
                {
                    return;
                }
            }
            throw new SpannerAbortedDueToConcurrentModificationException();
        }
        async Task IRetriableStatement.RetryAsync(SpannerRetriableTransaction transaction, CancellationToken cancellationToken, int timeoutSeconds)
        {
            _spannerCommand.Transaction = transaction.SpannerTransaction;
            var reader = await _spannerCommand.ExecuteReaderAsync(cancellationToken);

            int  counter = 0;
            bool read    = true;

            byte[]           newChecksum  = new byte[0];
            SpannerException newException = null;

            while (read && counter < _numberOfReadCalls)
            {
                try
                {
                    read = await reader.ReadAsync(cancellationToken);

                    newChecksum = CalculateNextChecksum(reader, newChecksum, read);
                    counter++;
                }
                catch (SpannerException e) when(e.ErrorCode == ErrorCode.Aborted)
                {
                    // Propagate Aborted errors to trigger a new retry.
                    throw;
                }
                catch (SpannerException e)
                {
                    newException = e;
                    counter++;
                    break;
                }
            }
            if (counter == _numberOfReadCalls &&
                newChecksum.SequenceEqual(_currentChecksum) &&
                SpannerRetriableTransaction.SpannerExceptionsEqualForRetry(newException, _firstException))
            {
                // Checksum is ok, we only need to replace the delegate result set if it's still open.
                if (IsClosed)
                {
                    reader.Close();
                }
                else
                {
                    _spannerDataReader = reader;
                }
            }
            else
            {
                // The results are not equal, there is an actual concurrent modification, so we cannot
                // continue the transaction.
                throw new SpannerAbortedDueToConcurrentModificationException();
            }
        }
示例#3
0
        async Task IRetriableStatement.RetryAsync(SpannerRetriableTransaction transaction, CancellationToken cancellationToken, int timeoutSeconds)
        {
            try
            {
                _command.Transaction = transaction.SpannerTransaction;
                await _command.ExecuteNonQueryAsync(cancellationToken);

                // Fallthrough and throw the exception at the end of the method.
            }
            catch (SpannerException e) when(e.ErrorCode != ErrorCode.Aborted)
            {
                // Check that we got the exact same exception this time as the previous time.
                if (SpannerRetriableTransaction.SpannerExceptionsEqualForRetry(e, _exception))
                {
                    return;
                }
            }
            throw new SpannerAbortedDueToConcurrentModificationException();
        }