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(); }
internal SpannerDataReaderWithChecksum( SpannerRetriableTransaction transaction, SpannerDataReader spannerDataReader, SpannerCommand command) { Transaction = transaction; _spannerDataReader = spannerDataReader; _spannerCommand = (SpannerCommand)command.Clone(); }
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(); } }
async Task IRetriableStatement.RetryAsync(SpannerRetriableTransaction transaction, CancellationToken cancellationToken, int timeoutSeconds) { try { _command.Transaction = transaction; if (!_updateCounts.SequenceEqual(await _command.CreateSpannerBatchCommand().ExecuteNonQueryAsync(cancellationToken))) { throw new SpannerAbortedDueToConcurrentModificationException(); } } catch (SpannerException e) when(e.ErrorCode != ErrorCode.Aborted) { throw new SpannerAbortedDueToConcurrentModificationException(); } }
async Task IRetriableStatement.RetryAsync(SpannerRetriableTransaction transaction, CancellationToken cancellationToken, int timeoutSeconds) { try { _command.Transaction = transaction.SpannerTransaction; // The DML statement should return the same update count as during the initial attempt // for the retry to be deemed successful. if (await _command.ExecuteNonQueryAsync(cancellationToken) != _updateCount) { throw new SpannerAbortedDueToConcurrentModificationException(); } } catch (SpannerException e) when(e.ErrorCode != ErrorCode.Aborted) { throw new SpannerAbortedDueToConcurrentModificationException(); } }
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(); }