use of com.mongodb.internal.async.function.RetryState in project mongo-java-driver by mongodb.
the class CommandOperationHelper method executeRetryableWriteAsync.
static <T, R> void executeRetryableWriteAsync(final AsyncWriteBinding binding, final String database, final ReadPreference readPreference, final FieldNameValidator fieldNameValidator, final Decoder<T> commandResultDecoder, final CommandCreator commandCreator, final CommandWriteTransformerAsync<T, R> transformer, final Function<BsonDocument, BsonDocument> retryCommandModifier, final SingleResultCallback<R> callback) {
RetryState retryState = initialRetryState(true);
binding.retain();
AsyncCallbackSupplier<R> asyncWrite = CommandOperationHelper.<R>decorateWriteWithRetries(retryState, funcCallback -> {
logRetryExecute(retryState);
boolean firstAttempt = retryState.isFirstAttempt();
if (!firstAttempt && binding.getSessionContext().hasActiveTransaction()) {
binding.getSessionContext().clearTransactionContext();
}
withAsyncSourceAndConnection(binding::getWriteConnectionSource, true, funcCallback, (source, connection, releasingCallback) -> {
int maxWireVersion = connection.getDescription().getMaxWireVersion();
SingleResultCallback<R> addingRetryableLabelCallback = firstAttempt ? releasingCallback : addingRetryableLabelCallback(releasingCallback, maxWireVersion);
if (retryState.breakAndCompleteIfRetryAnd(() -> !canRetryWrite(source.getServerDescription(), connection.getDescription(), binding.getSessionContext()), addingRetryableLabelCallback)) {
return;
}
BsonDocument command;
try {
command = retryState.attachment(AttachmentKeys.command()).map(previousAttemptCommand -> {
assertFalse(firstAttempt);
return retryCommandModifier.apply(previousAttemptCommand);
}).orElseGet(() -> commandCreator.create(source.getServerDescription(), connection.getDescription()));
// attach `maxWireVersion`, `retryableCommandFlag` ASAP because they are used to check whether we should retry
retryState.attach(AttachmentKeys.maxWireVersion(), maxWireVersion, true).attach(AttachmentKeys.retryableCommandFlag(), isRetryWritesEnabled(command), true).attach(AttachmentKeys.commandDescriptionSupplier(), command::getFirstKey, true).attach(AttachmentKeys.command(), command, false);
logRetryExecute(retryState);
} catch (Throwable t) {
addingRetryableLabelCallback.onResult(null, t);
return;
}
connection.commandAsync(database, command, fieldNameValidator, readPreference, commandResultDecoder, binding.getSessionContext(), binding.getServerApi(), binding.getRequestContext(), transformingWriteCallback(transformer, connection, addingRetryableLabelCallback));
});
}).whenComplete(binding::release);
asyncWrite.get(exceptionTransformingCallback(errorHandlingCallback(callback, LOGGER)));
}
use of com.mongodb.internal.async.function.RetryState in project mongo-java-driver by mongodb.
the class FindOperation method execute.
@Override
public BatchCursor<T> execute(final ReadBinding binding) {
RetryState retryState = initialRetryState(retryReads);
Supplier<BatchCursor<T>> read = decorateReadWithRetries(retryState, () -> {
logRetryExecute(retryState);
return withSourceAndConnection(binding::getReadConnectionSource, false, (source, connection) -> {
retryState.breakAndThrowIfRetryAnd(() -> !canRetryRead(source.getServerDescription(), connection.getDescription(), binding.getSessionContext()));
if (serverIsAtLeastVersionThreeDotTwo(connection.getDescription())) {
try {
return createReadCommandAndExecute(retryState, binding, source, namespace.getDatabaseName(), getCommandCreator(binding.getSessionContext()), CommandResultDocumentCodec.create(decoder, FIRST_BATCH), transformer(), connection);
} catch (MongoCommandException e) {
throw new MongoQueryException(e);
}
} else {
retryState.markAsLastAttempt();
validateFindOptions(connection, binding.getSessionContext().getReadConcern(), collation, allowDiskUse);
QueryResult<T> queryResult = connection.query(namespace, asDocument(connection.getDescription(), binding.getReadPreference()), projection, skip, limit, batchSize, isSecondaryOk() || binding.getReadPreference().isSecondaryOk(), isTailableCursor(), isAwaitData(), isNoCursorTimeout(), isPartial(), isOplogReplay(), decoder, binding.getRequestContext());
return new QueryBatchCursor<>(queryResult, limit, batchSize, getMaxTimeForCursor(), decoder, source, connection);
}
});
});
return read.get();
}
use of com.mongodb.internal.async.function.RetryState in project mongo-java-driver by mongodb.
the class ListIndexesOperation method execute.
@Override
public BatchCursor<T> execute(final ReadBinding binding) {
RetryState retryState = initialRetryState(retryReads);
Supplier<BatchCursor<T>> read = decorateReadWithRetries(retryState, () -> {
logRetryExecute(retryState);
return withSourceAndConnection(binding::getReadConnectionSource, false, (source, connection) -> {
retryState.breakAndThrowIfRetryAnd(() -> !canRetryRead(source.getServerDescription(), connection.getDescription(), binding.getSessionContext()));
if (serverIsAtLeastVersionThreeDotZero(connection.getDescription())) {
try {
return createReadCommandAndExecute(retryState, binding, source, namespace.getDatabaseName(), getCommandCreator(), createCommandDecoder(), transformer(), connection);
} catch (MongoCommandException e) {
return rethrowIfNotNamespaceError(e, createEmptyBatchCursor(namespace, decoder, source.getServerDescription().getAddress(), batchSize));
}
} else {
retryState.markAsLastAttempt();
return new QueryBatchCursor<>(connection.query(getIndexNamespace(), asQueryDocument(connection.getDescription(), binding.getReadPreference()), null, 0, 0, batchSize, binding.getReadPreference().isSecondaryOk(), false, false, false, false, false, decoder, binding.getRequestContext()), 0, batchSize, decoder, source);
}
});
});
return read.get();
}
use of com.mongodb.internal.async.function.RetryState in project mongo-java-driver by mongodb.
the class ListIndexesOperation method executeAsync.
@Override
public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback<AsyncBatchCursor<T>> callback) {
RetryState retryState = initialRetryState(retryReads);
binding.retain();
AsyncCallbackSupplier<AsyncBatchCursor<T>> asyncRead = CommandOperationHelper.<AsyncBatchCursor<T>>decorateReadWithRetries(retryState, funcCallback -> {
logRetryExecute(retryState);
withAsyncSourceAndConnection(binding::getReadConnectionSource, false, funcCallback, (source, connection, releasingCallback) -> {
if (retryState.breakAndCompleteIfRetryAnd(() -> !canRetryRead(source.getServerDescription(), connection.getDescription(), binding.getSessionContext()), releasingCallback)) {
return;
}
if (serverIsAtLeastVersionThreeDotZero(connection.getDescription())) {
createReadCommandAndExecuteAsync(retryState, binding, source, namespace.getDatabaseName(), getCommandCreator(), createCommandDecoder(), asyncTransformer(), connection, (result, t) -> {
if (t != null && !isNamespaceError(t)) {
releasingCallback.onResult(null, t);
} else {
releasingCallback.onResult(result != null ? result : emptyAsyncCursor(source), null);
}
});
} else {
retryState.markAsLastAttempt();
connection.queryAsync(getIndexNamespace(), asQueryDocument(connection.getDescription(), binding.getReadPreference()), null, 0, 0, batchSize, binding.getReadPreference().isSecondaryOk(), false, false, false, false, false, decoder, binding.getRequestContext(), new SingleResultCallback<QueryResult<T>>() {
@Override
public void onResult(final QueryResult<T> result, final Throwable t) {
if (t != null) {
releasingCallback.onResult(null, t);
} else {
releasingCallback.onResult(new AsyncQueryBatchCursor<T>(result, 0, batchSize, 0, decoder, source, connection), null);
}
}
});
}
});
}).whenComplete(binding::release);
asyncRead.get(errorHandlingCallback(callback, LOGGER));
}
use of com.mongodb.internal.async.function.RetryState in project mongo-java-driver by mongodb.
the class MixedBulkWriteOperation method executeAsync.
public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback<BulkWriteResult> callback) {
// see the comment in `execute(WriteBinding)` explaining the manual tracking of attempts
RetryState retryState = new RetryState();
BulkWriteTracker.attachNew(retryState, retryWrites);
binding.retain();
AsyncCallbackSupplier<BulkWriteResult> retryingBulkWrite = this.<BulkWriteResult>decorateWriteWithRetries(retryState, funcCallback -> {
logRetryExecute(retryState);
withAsyncSourceAndConnection(binding::getWriteConnectionSource, true, funcCallback, (source, connection, releasingCallback) -> {
ConnectionDescription connectionDescription = connection.getDescription();
int maxWireVersion = connectionDescription.getMaxWireVersion();
// attach `maxWireVersion` ASAP because it is used to check whether we can retry
retryState.attach(AttachmentKeys.maxWireVersion(), maxWireVersion, true);
BulkWriteTracker bulkWriteTracker = retryState.attachment(AttachmentKeys.bulkWriteTracker()).orElseThrow(Assertions::fail);
SessionContext sessionContext = binding.getSessionContext();
WriteConcern writeConcern = getAppliedWriteConcern(sessionContext);
if (!retryState.isFirstAttempt() && !isRetryableWrite(retryWrites, writeConcern, source.getServerDescription(), connectionDescription, sessionContext)) {
Throwable prospectiveFailedResult = retryState.exception().orElse(null);
if (retryState.breakAndCompleteIfRetryAnd(() -> !(prospectiveFailedResult instanceof MongoWriteConcernWithResponseException), releasingCallback)) {
return;
}
bulkWriteTracker.batch().ifPresent(bulkWriteBatch -> {
assertTrue(prospectiveFailedResult instanceof MongoWriteConcernWithResponseException);
bulkWriteBatch.addResult((BsonDocument) ((MongoWriteConcernWithResponseException) prospectiveFailedResult).getResponse());
BulkWriteTracker.attachNext(retryState, bulkWriteBatch);
});
}
if (validateWriteRequestsAndCompleteIfInvalid(connectionDescription, bypassDocumentValidation, writeRequests, writeConcern, releasingCallback)) {
return;
}
if (writeConcern.isAcknowledged() || serverIsAtLeastVersionThreeDotSix(connectionDescription)) {
try {
if (!bulkWriteTracker.batch().isPresent()) {
BulkWriteTracker.attachNew(retryState, BulkWriteBatch.createBulkWriteBatch(namespace, source.getServerDescription(), connectionDescription, ordered, writeConcern, bypassDocumentValidation, retryWrites, writeRequests, sessionContext));
}
} catch (Throwable t) {
releasingCallback.onResult(null, t);
return;
}
logRetryExecute(retryState);
executeBulkWriteBatchAsync(retryState, binding, connection, maxWireVersion, releasingCallback);
} else {
retryState.markAsLastAttempt();
executeLegacyBatchesAsync(binding, connection, releasingCallback);
}
});
}).whenComplete(binding::release);
retryingBulkWrite.get(exceptionTransformingCallback(errorHandlingCallback(callback, LOGGER)));
}
Aggregations