Skip to content

Commit 9a5bee7

Browse files
committed
JAVA-1131: With bulk writes in emulation mode, treat GLE failures with either wnote or jnote as write concern errors
1 parent 54e437a commit 9a5bee7

File tree

2 files changed

+87
-9
lines changed

2 files changed

+87
-9
lines changed

src/main/com/mongodb/DBCollectionImpl.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -845,10 +845,16 @@ private BulkWriteResult executeWriteProtocol() {
845845
WriteResult writeResult = executeWriteProtocol(i);
846846
if (writeConcern.callGetLastError()) {
847847
bulkWriteBatchCombiner.addResult(getResult(writeResult), indexMap);
848+
// When a journaled write is requested but journaling is disabled, it's not thrown as an exception.
849+
if (isWriteConcernError(writeResult.getLastError())) {
850+
bulkWriteBatchCombiner.addWriteConcernErrorResult(getWriteConcernError(writeResult.getLastError()));
851+
}
848852
}
849853
} catch (WriteConcernException writeException) {
850-
if (isWriteConcernError(writeException)) {
851-
bulkWriteBatchCombiner.addWriteConcernErrorResult(getWriteConcernError(writeException));
854+
if (isWriteConcernError(writeException.getCommandResult())) {
855+
bulkWriteBatchCombiner.addResult(getResult(new WriteResult(writeException.getCommandResult(), writeConcern)),
856+
indexMap);
857+
bulkWriteBatchCombiner.addWriteConcernErrorResult(getWriteConcernError(writeException.getCommandResult()));
852858
} else {
853859
bulkWriteBatchCombiner.addWriteErrorResult(getBulkWriteError(writeException), indexMap);
854860
}
@@ -865,10 +871,6 @@ private int getCount(final WriteResult writeResult) {
865871
return getType() == INSERT ? 1 : writeResult.getN();
866872
}
867873

868-
private boolean isWriteConcernError(final WriteConcernException writeException) {
869-
return writeException.getCommandResult().get("wtimeout") != null;
870-
}
871-
872874
List<BulkWriteUpsert> getUpsertedItems(final WriteResult writeResult) {
873875
return writeResult.getUpsertedId() == null
874876
? Collections.<BulkWriteUpsert>emptyList()
@@ -882,9 +884,26 @@ private BulkWriteError getBulkWriteError(final WriteConcernException writeExcept
882884
0);
883885
}
884886

885-
private WriteConcernError getWriteConcernError(final WriteConcernException writeException) {
886-
return new WriteConcernError(writeException.getCode(), writeException.getCommandResult().getString("err"),
887-
getErrorResponseDetails(writeException.getCommandResult()));
887+
// Accommodating GLE representation of write concern errors
888+
private boolean isWriteConcernError(final CommandResult commandResult) {
889+
return commandResult.get("wtimeout") != null || commandResult.get("wnote") != null || commandResult.get("jnote") != null;
890+
}
891+
892+
private WriteConcernError getWriteConcernError(final CommandResult commandResult) {
893+
return new WriteConcernError(commandResult.getCode(), getWriteConcernErrorMessage(commandResult),
894+
getErrorResponseDetails(commandResult));
895+
}
896+
897+
// GLE uses jnote and wnote as alternative ways or reporting write concern errors
898+
private String getWriteConcernErrorMessage(final CommandResult commandResult) {
899+
String errorMessage = commandResult.getString("jnote");
900+
if (errorMessage == null) {
901+
errorMessage = commandResult.getString("wnote");
902+
}
903+
if (errorMessage == null) {
904+
errorMessage = commandResult.getString("err");
905+
}
906+
return errorMessage;
888907
}
889908

890909
private DBObject getErrorResponseDetails(final DBObject response) {

src/test/com/mongodb/BulkWriteOperationSpecification.groovy

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,65 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
579579
ordered << [false]
580580
}
581581

582+
def 'when w > 1 write concern is used on a standalone server with write commands, CommandFailureException is thrown'() {
583+
assumeTrue(isStandalone() && serverIsAtLeastVersion(2.6))
584+
585+
given:
586+
def operation = collection.initializeUnorderedBulkOperation()
587+
operation.insert(new BasicDBObject('_id', 1))
588+
589+
when:
590+
operation.execute(new WriteConcern(2, 1))
591+
592+
then:
593+
thrown(CommandFailureException)
594+
595+
where:
596+
ordered << [true, false]
597+
}
598+
599+
def 'when w > 1 write concern is used on a standalone server without write commands, BulkWriteException is thrown'() {
600+
assumeTrue(isStandalone() && !serverIsAtLeastVersion(2.6))
601+
602+
given:
603+
def operation = collection.initializeUnorderedBulkOperation()
604+
operation.insert(new BasicDBObject('_id', 1))
605+
operation.insert(new BasicDBObject('_id', 2))
606+
607+
when:
608+
operation.execute(new WriteConcern(2, 1))
609+
610+
then:
611+
def e = thrown(BulkWriteException)
612+
e.writeResult == new AcknowledgedBulkWriteResult(INSERT, 2, [])
613+
e.writeConcernError != null
614+
e.writeConcernError.getDetails().containsField('wnote')
615+
616+
where:
617+
ordered << [true, false]
618+
}
619+
620+
def 'when j write concern is used on a server without journaling or write commands, BulkWriteException is thrown'() {
621+
assumeTrue(!isSharded() && isServerStartedWithJournalingDisabled() && !serverIsAtLeastVersion(2.6))
622+
623+
given:
624+
def operation = collection.initializeUnorderedBulkOperation()
625+
operation.insert(new BasicDBObject('_id', 1))
626+
operation.insert(new BasicDBObject('_id', 2))
627+
628+
when:
629+
operation.execute(WriteConcern.JOURNALED)
630+
631+
then:
632+
def e = thrown(BulkWriteException)
633+
e.writeResult == new AcknowledgedBulkWriteResult(INSERT, 2, [])
634+
e.writeConcernError != null
635+
e.writeConcernError.getDetails().containsField('jnote')
636+
637+
where:
638+
ordered << [true, false]
639+
}
640+
582641
def 'execute should throw IllegalStateException when already executed'() {
583642
given:
584643
def operation = initializeBulkOperation(ordered)

0 commit comments

Comments
 (0)