use of com.mongodb.internal.connection.MongoWriteConcernWithResponseException in project mongo-java-driver by mongodb.
the class MixedBulkWriteOperation method executeBulkWriteBatch.
private BulkWriteResult executeBulkWriteBatch(final RetryState retryState, final WriteBinding binding, final Connection connection, final int maxWireVersion) {
BulkWriteTracker currentBulkWriteTracker = retryState.attachment(AttachmentKeys.bulkWriteTracker()).orElseThrow(Assertions::fail);
BulkWriteBatch currentBatch = currentBulkWriteTracker.batch().orElseThrow(Assertions::fail);
while (currentBatch.shouldProcessBatch()) {
try {
BsonDocument result = executeCommand(connection, currentBatch, binding);
if (currentBatch.getRetryWrites() && !binding.getSessionContext().hasActiveTransaction()) {
MongoException writeConcernBasedError = ProtocolHelper.createSpecialException(result, connection.getDescription().getServerAddress(), "errMsg");
if (writeConcernBasedError != null) {
if (currentBulkWriteTracker.lastAttempt()) {
addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion);
addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), writeConcernBasedError.getErrorLabels());
} else if (CommandOperationHelper.shouldAttemptToRetryWrite(retryState, writeConcernBasedError)) {
throw new MongoWriteConcernWithResponseException(writeConcernBasedError, result);
}
}
}
currentBatch.addResult(result);
currentBulkWriteTracker = BulkWriteTracker.attachNext(retryState, currentBatch);
currentBatch = currentBulkWriteTracker.batch().orElseThrow(Assertions::fail);
} catch (MongoException exception) {
if (!(retryState.isFirstAttempt() || (exception instanceof MongoWriteConcernWithResponseException))) {
addRetryableWriteErrorLabel(exception, maxWireVersion);
}
throw exception;
}
}
try {
return currentBatch.getResult();
} catch (MongoException e) {
retryState.markAsLastAttempt();
throw e;
}
}
use of com.mongodb.internal.connection.MongoWriteConcernWithResponseException 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)));
}
use of com.mongodb.internal.connection.MongoWriteConcernWithResponseException in project mongo-java-driver by mongodb.
the class MixedBulkWriteOperation method executeBulkWriteBatchAsync.
private void executeBulkWriteBatchAsync(final RetryState retryState, final AsyncWriteBinding binding, final AsyncConnection connection, final int maxWireVersion, final SingleResultCallback<BulkWriteResult> callback) {
LoopState loopState = new LoopState();
AsyncCallbackRunnable loop = new AsyncCallbackLoop(loopState, iterationCallback -> {
BulkWriteTracker currentBulkWriteTracker = retryState.attachment(AttachmentKeys.bulkWriteTracker()).orElseThrow(Assertions::fail);
loopState.attach(AttachmentKeys.bulkWriteTracker(), currentBulkWriteTracker, true);
BulkWriteBatch currentBatch = currentBulkWriteTracker.batch().orElseThrow(Assertions::fail);
if (loopState.breakAndCompleteIf(() -> !currentBatch.shouldProcessBatch(), iterationCallback)) {
return;
}
executeCommandAsync(binding, connection, currentBatch, (result, t) -> {
if (t == null) {
if (currentBatch.getRetryWrites() && !binding.getSessionContext().hasActiveTransaction()) {
MongoException writeConcernBasedError = ProtocolHelper.createSpecialException(result, connection.getDescription().getServerAddress(), "errMsg");
if (writeConcernBasedError != null) {
if (currentBulkWriteTracker.lastAttempt()) {
addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion);
addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), writeConcernBasedError.getErrorLabels());
} else if (CommandOperationHelper.shouldAttemptToRetryWrite(retryState, writeConcernBasedError)) {
iterationCallback.onResult(null, new MongoWriteConcernWithResponseException(writeConcernBasedError, result));
return;
}
}
}
currentBatch.addResult(result);
BulkWriteTracker.attachNext(retryState, currentBatch);
iterationCallback.onResult(null, null);
} else {
if (t instanceof MongoException) {
MongoException exception = (MongoException) t;
if (!(retryState.isFirstAttempt() || (exception instanceof MongoWriteConcernWithResponseException))) {
addRetryableWriteErrorLabel(exception, maxWireVersion);
}
}
iterationCallback.onResult(null, t);
}
});
});
loop.run((voidResult, t) -> {
if (t != null) {
callback.onResult(null, t);
} else {
BulkWriteResult result;
try {
result = loopState.attachment(AttachmentKeys.bulkWriteTracker()).flatMap(BulkWriteTracker::batch).orElseThrow(Assertions::fail).getResult();
} catch (Throwable loopResultT) {
if (loopResultT instanceof MongoException) {
retryState.markAsLastAttempt();
}
callback.onResult(null, loopResultT);
return;
}
callback.onResult(result, null);
}
});
}
use of com.mongodb.internal.connection.MongoWriteConcernWithResponseException in project mongo-java-driver by mongodb.
the class MixedBulkWriteOperation method execute.
/**
* Executes a bulk write operation.
*
* @param binding the WriteBinding for the operation
* @return the bulk write result.
* @throws MongoBulkWriteException if a failure to complete the bulk write is detected based on the server response
*/
@Override
public BulkWriteResult execute(final WriteBinding binding) {
/* We cannot use the tracking of attempts built in the `RetryState` class because conceptually we have to maintain multiple attempt
* counters while executing a single bulk write operation:
* - a counter that limits attempts to select server and checkout a connection before we created a batch;
* - a counter per each batch that limits attempts to execute the specific batch.
* Fortunately, these counters do not exist concurrently with each other. While maintaining the counters manually,
* we must adhere to the contract of `RetryingSyncSupplier`. When the retry timeout is implemented, there will be no counters,
* and the code related to the attempt tracking in `BulkWriteTracker` will be removed. */
RetryState retryState = new RetryState();
BulkWriteTracker.attachNew(retryState, retryWrites);
Supplier<BulkWriteResult> retryingBulkWrite = decorateWriteWithRetries(retryState, () -> {
logRetryExecute(retryState);
return withSourceAndConnection(binding::getWriteConnectionSource, true, (source, connection) -> {
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)) {
RuntimeException prospectiveFailedResult = (RuntimeException) retryState.exception().orElse(null);
retryState.breakAndThrowIfRetryAnd(() -> !(prospectiveFailedResult instanceof MongoWriteConcernWithResponseException));
bulkWriteTracker.batch().ifPresent(bulkWriteBatch -> {
assertTrue(prospectiveFailedResult instanceof MongoWriteConcernWithResponseException);
bulkWriteBatch.addResult((BsonDocument) ((MongoWriteConcernWithResponseException) prospectiveFailedResult).getResponse());
BulkWriteTracker.attachNext(retryState, bulkWriteBatch);
});
}
validateWriteRequests(connectionDescription, bypassDocumentValidation, writeRequests, writeConcern);
if (writeConcern.isAcknowledged() || serverIsAtLeastVersionThreeDotSix(connectionDescription)) {
if (!bulkWriteTracker.batch().isPresent()) {
BulkWriteTracker.attachNew(retryState, BulkWriteBatch.createBulkWriteBatch(namespace, source.getServerDescription(), connectionDescription, ordered, writeConcern, bypassDocumentValidation, retryWrites, writeRequests, sessionContext));
}
logRetryExecute(retryState);
return executeBulkWriteBatch(retryState, binding, connection, maxWireVersion);
} else {
retryState.markAsLastAttempt();
return executeLegacyBatches(binding, connection);
}
});
});
try {
return retryingBulkWrite.get();
} catch (MongoException e) {
throw transformWriteException(e);
}
}
Aggregations