16
16
17
17
package com .mongodb .internal .operation ;
18
18
19
+ import com .mongodb .MongoClientException ;
19
20
import com .mongodb .MongoException ;
20
21
import com .mongodb .MongoNamespace ;
21
22
import com .mongodb .WriteConcern ;
@@ -191,8 +192,8 @@ public BulkWriteResult execute(final WriteBinding binding) {
191
192
// attach `maxWireVersion` ASAP because it is used to check whether we can retry
192
193
retryState .attach (AttachmentKeys .maxWireVersion (), connectionDescription .getMaxWireVersion (), true );
193
194
SessionContext sessionContext = binding .getOperationContext ().getSessionContext ();
194
- WriteConcern writeConcern = getAppliedWriteConcern ( sessionContext );
195
- if (!isRetryableWrite (retryWrites , getAppliedWriteConcern ( sessionContext ) , connectionDescription , sessionContext )) {
195
+ WriteConcern writeConcern = validateAndGetEffectiveWriteConcern ( this . writeConcern , sessionContext );
196
+ if (!isRetryableWrite (retryWrites , writeConcern , connectionDescription , sessionContext )) {
196
197
handleMongoWriteConcernWithResponseException (retryState , true , timeoutContext );
197
198
}
198
199
validateWriteRequests (connectionDescription , bypassDocumentValidation , writeRequests , writeConcern );
@@ -201,7 +202,7 @@ public BulkWriteResult execute(final WriteBinding binding) {
201
202
connectionDescription , ordered , writeConcern ,
202
203
bypassDocumentValidation , retryWrites , writeRequests , binding .getOperationContext (), comment , variables ), timeoutContext );
203
204
}
204
- return executeBulkWriteBatch (retryState , binding , connection );
205
+ return executeBulkWriteBatch (retryState , writeConcern , binding , connection );
205
206
})
206
207
);
207
208
try {
@@ -226,8 +227,8 @@ public void executeAsync(final AsyncWriteBinding binding, final SingleResultCall
226
227
// attach `maxWireVersion` ASAP because it is used to check whether we can retry
227
228
retryState .attach (AttachmentKeys .maxWireVersion (), connectionDescription .getMaxWireVersion (), true );
228
229
SessionContext sessionContext = binding .getOperationContext ().getSessionContext ();
229
- WriteConcern writeConcern = getAppliedWriteConcern ( sessionContext );
230
- if (!isRetryableWrite (retryWrites , getAppliedWriteConcern ( sessionContext ) , connectionDescription , sessionContext )
230
+ WriteConcern writeConcern = validateAndGetEffectiveWriteConcern ( this . writeConcern , sessionContext );
231
+ if (!isRetryableWrite (retryWrites , writeConcern , connectionDescription , sessionContext )
231
232
&& handleMongoWriteConcernWithResponseExceptionAsync (retryState , releasingCallback , timeoutContext )) {
232
233
return ;
233
234
}
@@ -245,13 +246,17 @@ && handleMongoWriteConcernWithResponseExceptionAsync(retryState, releasingCallba
245
246
releasingCallback .onResult (null , t );
246
247
return ;
247
248
}
248
- executeBulkWriteBatchAsync (retryState , binding , connection , releasingCallback );
249
+ executeBulkWriteBatchAsync (retryState , writeConcern , binding , connection , releasingCallback );
249
250
})
250
251
).whenComplete (binding ::release );
251
252
retryingBulkWrite .get (exceptionTransformingCallback (errorHandlingCallback (callback , LOGGER )));
252
253
}
253
254
254
- private BulkWriteResult executeBulkWriteBatch (final RetryState retryState , final WriteBinding binding , final Connection connection ) {
255
+ private BulkWriteResult executeBulkWriteBatch (
256
+ final RetryState retryState ,
257
+ final WriteConcern effectiveWriteConcern ,
258
+ final WriteBinding binding ,
259
+ final Connection connection ) {
255
260
BulkWriteTracker currentBulkWriteTracker = retryState .attachment (AttachmentKeys .bulkWriteTracker ())
256
261
.orElseThrow (Assertions ::fail );
257
262
BulkWriteBatch currentBatch = currentBulkWriteTracker .batch ().orElseThrow (Assertions ::fail );
@@ -261,7 +266,7 @@ private BulkWriteResult executeBulkWriteBatch(final RetryState retryState, final
261
266
262
267
while (currentBatch .shouldProcessBatch ()) {
263
268
try {
264
- BsonDocument result = executeCommand (operationContext , connection , currentBatch );
269
+ BsonDocument result = executeCommand (effectiveWriteConcern , operationContext , connection , currentBatch );
265
270
if (currentBatch .getRetryWrites () && !operationContext .getSessionContext ().hasActiveTransaction ()) {
266
271
MongoException writeConcernBasedError = ProtocolHelper .createSpecialException (result ,
267
272
connection .getDescription ().getServerAddress (), "errMsg" , timeoutContext );
@@ -295,7 +300,11 @@ private BulkWriteResult executeBulkWriteBatch(final RetryState retryState, final
295
300
}
296
301
}
297
302
298
- private void executeBulkWriteBatchAsync (final RetryState retryState , final AsyncWriteBinding binding , final AsyncConnection connection ,
303
+ private void executeBulkWriteBatchAsync (
304
+ final RetryState retryState ,
305
+ final WriteConcern effectiveWriteConcern ,
306
+ final AsyncWriteBinding binding ,
307
+ final AsyncConnection connection ,
299
308
final SingleResultCallback <BulkWriteResult > callback ) {
300
309
LoopState loopState = new LoopState ();
301
310
AsyncCallbackRunnable loop = new AsyncCallbackLoop (loopState , iterationCallback -> {
@@ -309,7 +318,7 @@ private void executeBulkWriteBatchAsync(final RetryState retryState, final Async
309
318
}
310
319
OperationContext operationContext = binding .getOperationContext ();
311
320
TimeoutContext timeoutContext = operationContext .getTimeoutContext ();
312
- executeCommandAsync (operationContext , connection , currentBatch , (result , t ) -> {
321
+ executeCommandAsync (effectiveWriteConcern , operationContext , connection , currentBatch , (result , t ) -> {
313
322
if (t == null ) {
314
323
if (currentBatch .getRetryWrites () && !operationContext .getSessionContext ().hasActiveTransaction ()) {
315
324
MongoException writeConcernBasedError = ProtocolHelper .createSpecialException (result ,
@@ -405,31 +414,47 @@ private boolean handleMongoWriteConcernWithResponseExceptionAsync(final RetrySta
405
414
}
406
415
407
416
@ Nullable
408
- private BsonDocument executeCommand (final OperationContext operationContext , final Connection connection , final BulkWriteBatch batch ) {
417
+ private BsonDocument executeCommand (
418
+ final WriteConcern effectiveWriteConcern ,
419
+ final OperationContext operationContext ,
420
+ final Connection connection ,
421
+ final BulkWriteBatch batch ) {
409
422
return connection .command (namespace .getDatabaseName (), batch .getCommand (), NoOpFieldNameValidator .INSTANCE , null , batch .getDecoder (),
410
- operationContext , shouldAcknowledge (batch , operationContext . getSessionContext () ),
423
+ operationContext , shouldExpectResponse (batch , effectiveWriteConcern ),
411
424
batch .getPayload (), batch .getFieldNameValidator ());
412
425
}
413
426
414
- private void executeCommandAsync (final OperationContext operationContext , final AsyncConnection connection , final BulkWriteBatch batch ,
427
+ private void executeCommandAsync (
428
+ final WriteConcern effectiveWriteConcern ,
429
+ final OperationContext operationContext ,
430
+ final AsyncConnection connection ,
431
+ final BulkWriteBatch batch ,
415
432
final SingleResultCallback <BsonDocument > callback ) {
416
433
connection .commandAsync (namespace .getDatabaseName (), batch .getCommand (), NoOpFieldNameValidator .INSTANCE , null , batch .getDecoder (),
417
- operationContext , shouldAcknowledge (batch , operationContext . getSessionContext () ),
434
+ operationContext , shouldExpectResponse (batch , effectiveWriteConcern ),
418
435
batch .getPayload (), batch .getFieldNameValidator (), callback );
419
436
}
420
437
421
- private WriteConcern getAppliedWriteConcern (final SessionContext sessionContext ) {
422
- if (sessionContext .hasActiveTransaction ()) {
423
- return WriteConcern .ACKNOWLEDGED ;
424
- } else {
425
- return writeConcern ;
438
+ private static WriteConcern validateAndGetEffectiveWriteConcern (final WriteConcern writeConcernSetting , final SessionContext sessionContext )
439
+ throws MongoClientException {
440
+ boolean activeTransaction = sessionContext .hasActiveTransaction ();
441
+ WriteConcern effectiveWriteConcern = activeTransaction
442
+ ? WriteConcern .ACKNOWLEDGED
443
+ : writeConcernSetting ;
444
+ if (sessionContext .hasSession () && !sessionContext .isImplicitSession () && !activeTransaction && !effectiveWriteConcern .isAcknowledged ()) {
445
+ throw new MongoClientException ("Unacknowledged writes are not supported when using an explicit session" );
426
446
}
447
+ return effectiveWriteConcern ;
427
448
}
428
449
429
- private boolean shouldAcknowledge (final BulkWriteBatch batch , final SessionContext sessionContext ) {
430
- return ordered
431
- ? batch .hasAnotherBatch () || getAppliedWriteConcern (sessionContext ).isAcknowledged ()
432
- : getAppliedWriteConcern (sessionContext ).isAcknowledged ();
450
+ static Optional <WriteConcern > commandWriteConcern (final WriteConcern effectiveWriteConcern , final SessionContext sessionContext ) {
451
+ return effectiveWriteConcern .isServerDefault () || sessionContext .hasActiveTransaction ()
452
+ ? Optional .empty ()
453
+ : Optional .of (effectiveWriteConcern );
454
+ }
455
+
456
+ private boolean shouldExpectResponse (final BulkWriteBatch batch , final WriteConcern effectiveWriteConcern ) {
457
+ return effectiveWriteConcern .isAcknowledged () || (ordered && batch .hasAnotherBatch ());
433
458
}
434
459
435
460
private void addErrorLabelsToWriteConcern (final BsonDocument result , final Set <String > errorLabels ) {
0 commit comments