@@ -172,18 +172,16 @@ static boolean loggingShouldAttemptToRetryRead(final RetryState retryState, fina
172172 || (attemptFailure instanceof MongoSecurityException
173173 && attemptFailure .getCause () != null && isRetryableException (attemptFailure .getCause ()));
174174 if (!decision ) {
175- logUnableToRetry (retryState . attachment ( AttachmentKeys . commandDescriptionSupplier ()). orElse ( null ) , attemptFailure );
175+ logUnableToRetryCommand (retryState , attemptFailure );
176176 }
177177 return decision ;
178178 }
179179
180180 static boolean loggingShouldAttemptToRetryWriteAndAddRetryableLabel (final RetryState retryState , final Throwable attemptFailure ) {
181181 Throwable attemptFailureNotToBeRetried = getWriteAttemptFailureNotToBeRetriedOrAddRetryableLabel (retryState , attemptFailure );
182182 boolean decision = attemptFailureNotToBeRetried == null ;
183- if (!decision && retryState .attachment (AttachmentKeys .retryableCommandFlag ()).orElse (false )) {
184- logUnableToRetry (
185- retryState .attachment (AttachmentKeys .commandDescriptionSupplier ()).orElse (null ),
186- assertNotNull (attemptFailureNotToBeRetried ));
183+ if (!decision && retryState .attachment (AttachmentKeys .retryableWriteCommandFlag ()).orElse (false )) {
184+ logUnableToRetryCommand (retryState , assertNotNull (attemptFailureNotToBeRetried ));
187185 }
188186 return decision ;
189187 }
@@ -205,10 +203,10 @@ private static Throwable getWriteAttemptFailureNotToBeRetriedOrAddRetryableLabel
205203 decision = true ;
206204 exceptionRetryableRegardlessOfCommand = (MongoException ) failure ;
207205 }
208- if (retryState .attachment (AttachmentKeys .retryableCommandFlag ()).orElse (false )) {
206+ if (retryState .attachment (AttachmentKeys .retryableWriteCommandFlag ()).orElse (false )) {
209207 if (exceptionRetryableRegardlessOfCommand != null ) {
210- /* We are going to retry even if `retryableCommand ` is false,
211- * but we add the retryable label only if `retryableCommand ` is true. */
208+ /* We are going to retry even if `retryableWriteCommandFlag ` is false,
209+ * but we add the retryable label only if `retryableWriteCommandFlag ` is true. */
212210 exceptionRetryableRegardlessOfCommand .addLabel (RETRYABLE_WRITE_ERROR_LABEL );
213211 } else if (decideRetryableAndAddRetryableWriteErrorLabel (failure , retryState .attachment (AttachmentKeys .maxWireVersion ())
214212 .orElse (null ))) {
@@ -218,9 +216,20 @@ private static Throwable getWriteAttemptFailureNotToBeRetriedOrAddRetryableLabel
218216 return decision ? null : assertNotNull (failure );
219217 }
220218
221- static boolean isRetryWritesEnabled (@ Nullable final BsonDocument command ) {
222- return (command != null && (command .containsKey ("txnNumber" )
223- || command .getFirstKey ().equals ("commitTransaction" ) || command .getFirstKey ().equals ("abortTransaction" )));
219+ /**
220+ * Returns {@code true} if the {@code command} is intended to be executed outside a transaction and supports being retried,
221+ * or if the {@code command} is {@code commitTransaction}/{@code abortTransaction}; {@code false} otherwise.
222+ */
223+ static boolean isRetryableWriteCommand (final BsonDocument command ) {
224+ // Given the requirement
225+ // https://github.com/mongodb/specifications/blame/7039e69945d463a14b1b727d16db063e21f48f53/source/transactions/transactions.md#L584-L586:
226+ // When executing the `commitTransaction` and `abortTransaction` commands within a transaction
227+ // drivers MUST use the same `txnNumber` used for all preceding commands in the transaction.
228+ // the additional checks if the `command` is either `commitTransaction`/`abortTransaction, may seem unnecessary.
229+ // However, since the `txnNumber` key is added to commands within transactions by `CommandMessage`,
230+ // the key is not present when the logic of automatic retries inspects a `commitTransaction`/`abortTransaction` command for it.
231+ return (command .containsKey ("txnNumber" )
232+ || command .getFirstKey ().equals ("commitTransaction" ) || command .getFirstKey ().equals ("abortTransaction" ));
224233 }
225234
226235 static final String RETRYABLE_WRITE_ERROR_LABEL = "RetryableWriteError" ;
@@ -245,26 +254,26 @@ static void addRetryableWriteErrorLabel(final MongoException exception, final in
245254 }
246255 }
247256
248- static void logRetryExecute (final RetryState retryState , final OperationContext operationContext ) {
257+ static void logRetryCommand (final RetryState retryState , final OperationContext operationContext ) {
249258 if (LOGGER .isDebugEnabled () && !retryState .isFirstAttempt ()) {
250259 String commandDescription = retryState .attachment (AttachmentKeys .commandDescriptionSupplier ()).map (Supplier ::get ).orElse (null );
251260 Throwable exception = retryState .exception ().orElseThrow (Assertions ::fail );
252261 int oneBasedAttempt = retryState .attempt () + 1 ;
253262 long operationId = operationContext .getId ();
254263 LOGGER .debug (commandDescription == null
255- ? format ("Retrying the operation with operation ID %s due to the error \" %s\" . Attempt number: #%d" ,
256- operationId , exception , oneBasedAttempt )
257- : format ("Retrying the operation '%s' with operation ID %s due to the error \" %s\" . Attempt number: #%d" ,
258- commandDescription , operationId , exception , oneBasedAttempt ));
264+ ? format ("Retrying a command within the operation with operation ID %s due to the error \" %s\" . Attempt number: #%d" ,
265+ operationId , exception , oneBasedAttempt )
266+ : format ("Retrying the command '%s' within the operation with operation ID %s due to the error \" %s\" . Attempt number: #%d" ,
267+ commandDescription , operationId , exception , oneBasedAttempt ));
259268 }
260269 }
261270
262- private static void logUnableToRetry ( @ Nullable final Supplier < String > commandDescriptionSupplier , final Throwable originalError ) {
271+ private static void logUnableToRetryCommand ( final RetryState retryState , final Throwable originalError ) {
263272 if (LOGGER .isDebugEnabled ()) {
264- String commandDescription = commandDescriptionSupplier == null ? null : commandDescriptionSupplier . get ( );
273+ String commandDescription = retryState . attachment ( AttachmentKeys . commandDescriptionSupplier ()). map ( Supplier :: get ). orElse ( null );
265274 LOGGER .debug (commandDescription == null
266- ? format ("Unable to retry an operation due to the error \" %s\" " , originalError )
267- : format ("Unable to retry the operation %s due to the error \" %s\" " , commandDescription , originalError ));
275+ ? format ("Unable to retry a command due to the error \" %s\" " , originalError )
276+ : format ("Unable to retry the command '%s' due to the error \" %s\" " , commandDescription , originalError ));
268277 }
269278 }
270279
0 commit comments