diff --git a/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java b/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java index 8332ad916f..4bd56d1d02 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java +++ b/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java @@ -237,10 +237,13 @@ private static boolean decideRetryableAndAddRetryableWriteErrorLabel(final Throw return exception.hasErrorLabel(RETRYABLE_WRITE_ERROR_LABEL); } + static boolean shouldAddRetryableWriteErrorLabel(final MongoException exception, final int maxWireVersion) { + return (maxWireVersion >= 9 && exception instanceof MongoSocketException) + || (maxWireVersion < 9 && isRetryableException(exception)); + } + static void addRetryableWriteErrorLabel(final MongoException exception, final int maxWireVersion) { - if (maxWireVersion >= 9 && exception instanceof MongoSocketException) { - exception.addLabel(RETRYABLE_WRITE_ERROR_LABEL); - } else if (maxWireVersion < 9 && isRetryableException(exception)) { + if (shouldAddRetryableWriteErrorLabel(exception, maxWireVersion)) { exception.addLabel(RETRYABLE_WRITE_ERROR_LABEL); } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java index 43cf4b4cf6..e24bb6eb90 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java @@ -51,9 +51,7 @@ import java.util.List; import java.util.Locale; import java.util.Optional; -import java.util.Set; import java.util.function.Supplier; -import java.util.stream.Collectors; import static com.mongodb.assertions.Assertions.assertTrue; import static com.mongodb.assertions.Assertions.isTrueArgument; @@ -61,10 +59,12 @@ import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback; import static com.mongodb.internal.operation.AsyncOperationHelper.exceptionTransformingCallback; import static com.mongodb.internal.operation.AsyncOperationHelper.withAsyncSourceAndConnection; +import static com.mongodb.internal.operation.CommandOperationHelper.RETRYABLE_WRITE_ERROR_LABEL; import static com.mongodb.internal.operation.CommandOperationHelper.addRetryableWriteErrorLabel; import static com.mongodb.internal.operation.CommandOperationHelper.logRetryExecute; import static com.mongodb.internal.operation.CommandOperationHelper.loggingShouldAttemptToRetryWriteAndAddRetryableLabel; import static com.mongodb.internal.operation.CommandOperationHelper.onRetryableWriteAttemptFailure; +import static com.mongodb.internal.operation.CommandOperationHelper.shouldAddRetryableWriteErrorLabel; import static com.mongodb.internal.operation.CommandOperationHelper.transformWriteException; import static com.mongodb.internal.operation.CommandOperationHelper.validateAndGetEffectiveWriteConcern; import static com.mongodb.internal.operation.OperationHelper.LOGGER; @@ -287,8 +287,11 @@ private BulkWriteResult executeBulkWriteBatch( connection.getDescription().getServerAddress(), "errMsg", timeoutContext); if (writeConcernBasedError != null) { if (currentBulkWriteTracker.lastAttempt()) { - addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion); - addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), writeConcernBasedError.getErrorLabels()); + // The raw result is not exposed to the user, so labels can be added directly here. + // They are further processed as if they originated from the server. + if (shouldAddRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion)) { + addRetryableErrorLabelToResult(result); + } } else if (loggingShouldAttemptToRetryWriteAndAddRetryableLabel(retryState, writeConcernBasedError)) { throw new MongoWriteConcernWithResponseException(writeConcernBasedError, result); } @@ -341,9 +344,11 @@ private void executeBulkWriteBatchAsync( connection.getDescription().getServerAddress(), "errMsg", operationContext.getTimeoutContext()); if (writeConcernBasedError != null) { if (currentBulkWriteTracker.lastAttempt()) { - addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion); - addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), - writeConcernBasedError.getErrorLabels()); + // The raw result is not exposed to the user, so labels can be added directly here. + // They are further processed as if they originated from the server. + if (shouldAddRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion)) { + addRetryableErrorLabelToResult(result); + } } else if (loggingShouldAttemptToRetryWriteAndAddRetryableLabel(retryState, writeConcernBasedError)) { iterationCallback.onResult(null, new MongoWriteConcernWithResponseException(writeConcernBasedError, result)); @@ -456,9 +461,11 @@ private boolean shouldExpectResponse(final BulkWriteBatch batch, final WriteConc return effectiveWriteConcern.isAcknowledged() || (ordered && batch.hasAnotherBatch()); } - private void addErrorLabelsToWriteConcern(final BsonDocument result, final Set errorLabels) { + private void addRetryableErrorLabelToResult(final BsonDocument result) { if (!result.containsKey("errorLabels")) { - result.put("errorLabels", new BsonArray(errorLabels.stream().map(BsonString::new).collect(Collectors.toList()))); + BsonArray labelsArray = new BsonArray(); + labelsArray.add(new BsonString(RETRYABLE_WRITE_ERROR_LABEL)); + result.put("errorLabels", labelsArray); } } diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index 2225f837ec..345a90908b 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -25,7 +25,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet; import static com.mongodb.ClusterFixture.isSharded; import static com.mongodb.ClusterFixture.serverVersionLessThan; import static com.mongodb.assertions.Assertions.assertNotNull; @@ -400,10 +399,6 @@ public static void applyCustomizations(final TestDef def) { .test("retryable-writes", "retryable-writes insertOne serverErrors", "InsertOne succeeds after retryable writeConcernError") .test("retryable-writes", "retryable-writes bulkWrite serverErrors", "BulkWrite succeeds after retryable writeConcernError in first batch"); - def.skipJira("https://jira.mongodb.org/browse/JAVA-5341") - .when(() -> isDiscoverableReplicaSet() && serverVersionLessThan(4, 4)) - .test("retryable-writes", "retryable-writes insertOne serverErrors", - "RetryableWriteError label is added based on writeConcernError in pre-4.4 mongod response"); // server-discovery-and-monitoring (SDAM)