Skip to content

Commit 942e1bd

Browse files
committed
JAVA-908: Support write concern for findAndModify command
Throw exception from findAndModify-related operations if the response contains a write concern error Support write concern for findAndModify-related helper methods in DBCollection
1 parent 5370977 commit 942e1bd

39 files changed

+738
-167
lines changed

config/checkstyle.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121

122122
<module name="MethodLength"/>
123123
<module name="ParameterNumber">
124-
<property name="max" value="10"/>
124+
<property name="max" value="11"/>
125125
</module>
126126

127127

driver-async/src/main/com/mongodb/async/client/MongoCollectionImpl.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
package com.mongodb.async.client;
1818

1919
import com.mongodb.MongoBulkWriteException;
20+
import com.mongodb.MongoInternalException;
2021
import com.mongodb.MongoNamespace;
2122
import com.mongodb.MongoWriteConcernException;
2223
import com.mongodb.MongoWriteException;
2324
import com.mongodb.ReadConcern;
2425
import com.mongodb.ReadPreference;
2526
import com.mongodb.WriteConcern;
27+
import com.mongodb.WriteConcernResult;
2628
import com.mongodb.WriteError;
2729
import com.mongodb.async.SingleResultCallback;
2830
import com.mongodb.bulk.BulkWriteResult;
@@ -590,8 +592,11 @@ public void onResult(final BulkWriteResult result, final Throwable t) {
590592
if (t instanceof MongoBulkWriteException) {
591593
MongoBulkWriteException e = (MongoBulkWriteException) t;
592594
if (e.getWriteErrors().isEmpty()) {
593-
callback.onResult(null, new MongoWriteConcernException(e.getWriteConcernError(),
594-
e.getServerAddress()));
595+
callback.onResult(null,
596+
new MongoWriteConcernException(e.getWriteConcernError(),
597+
translateBulkWriteResult(request,
598+
e.getWriteResult()),
599+
e.getServerAddress()));
595600
} else {
596601
callback.onResult(null, new MongoWriteException(new WriteError(e.getWriteErrors().get(0)),
597602
e.getServerAddress()));
@@ -603,6 +608,23 @@ public void onResult(final BulkWriteResult result, final Throwable t) {
603608
});
604609
}
605610

611+
private WriteConcernResult translateBulkWriteResult(final WriteRequest request, final BulkWriteResult writeResult) {
612+
switch (request.getType()) {
613+
case INSERT:
614+
return WriteConcernResult.acknowledged(writeResult.getInsertedCount(), false, null);
615+
case DELETE:
616+
return WriteConcernResult.acknowledged(writeResult.getDeletedCount(), false, null);
617+
case UPDATE:
618+
case REPLACE:
619+
return WriteConcernResult.acknowledged(writeResult.getMatchedCount() + writeResult.getUpserts().size(),
620+
writeResult.getMatchedCount() > 0,
621+
writeResult.getUpserts().isEmpty()
622+
? null : writeResult.getUpserts().get(0).getId());
623+
default:
624+
throw new MongoInternalException("Unhandled write request type: " + request.getType());
625+
}
626+
}
627+
606628
private UpdateResult toUpdateResult(final com.mongodb.bulk.BulkWriteResult result) {
607629
if (result.wasAcknowledged()) {
608630
Long modifiedCount = result.isModifiedCountAvailable() ? (long) result.getModifiedCount() : null;

driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,30 @@ class MongoCollectionSpecification extends Specification {
533533
WriteConcern.UNACKNOWLEDGED | new TestOperationExecutor([unacknowledged()]) | DeleteResult.unacknowledged()
534534
}
535535

536+
def 'deleteOne should translate BulkWriteException correctly'() {
537+
given:
538+
def bulkWriteException = new MongoBulkWriteException(acknowledged(0, 0, 1, null, []), [],
539+
new WriteConcernError(100, '', new BsonDocument()),
540+
new ServerAddress());
541+
542+
def executor = new TestOperationExecutor([bulkWriteException])
543+
def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, WriteConcern.ACKNOWLEDGED,
544+
readConcern, executor)
545+
def futureResultCallback = new FutureResultCallback<DeleteResult>()
546+
547+
when:
548+
collection.deleteOne(new Document('_id', 1), futureResultCallback)
549+
futureResultCallback.get()
550+
551+
then:
552+
def ex = thrown(MongoWriteConcernException)
553+
ex.writeConcernError == bulkWriteException.writeConcernError
554+
ex.writeResult.wasAcknowledged()
555+
ex.writeResult.count == 1
556+
!ex.writeResult.updateOfExisting
557+
ex.writeResult.upsertedId == null
558+
}
559+
536560
def 'deleteMany should use MixedBulkWriteOperation correctly'() {
537561
given:
538562
def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, writeConcern, readConcern, executor)
@@ -583,6 +607,36 @@ class MongoCollectionSpecification extends Specification {
583607
WriteConcern.UNACKNOWLEDGED | new TestOperationExecutor([unacknowledged()]) | UpdateResult.unacknowledged()
584608
}
585609

610+
def 'replaceOne should translate BulkWriteException correctly'() {
611+
given:
612+
def bulkWriteException = new MongoBulkWriteException(bulkWriteResult, [],
613+
new WriteConcernError(100, '', new BsonDocument()),
614+
new ServerAddress());
615+
616+
def executor = new TestOperationExecutor([bulkWriteException])
617+
def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, WriteConcern.ACKNOWLEDGED,
618+
readConcern, executor)
619+
def futureResultCallback = new FutureResultCallback<UpdateResult>()
620+
621+
when:
622+
collection.replaceOne(new Document('_id', 1), new Document('_id', 1), futureResultCallback)
623+
futureResultCallback.get()
624+
625+
then:
626+
def ex = thrown(MongoWriteConcernException)
627+
ex.writeConcernError == bulkWriteException.writeConcernError
628+
ex.writeResult.wasAcknowledged() == writeResult.wasAcknowledged()
629+
ex.writeResult.count == writeResult.count
630+
ex.writeResult.updateOfExisting == writeResult.updateOfExisting
631+
ex.writeResult.upsertedId == writeResult.upsertedId
632+
633+
where:
634+
bulkWriteResult | writeResult
635+
acknowledged(0, 1, 0, 1, []) | WriteConcernResult.acknowledged(1, true, null)
636+
acknowledged(0, 0, 0, 0, [new BulkWriteUpsert(0, new BsonInt32(1))]) | WriteConcernResult.acknowledged(1, false, new BsonInt32(1))
637+
}
638+
639+
586640
def 'updateOne should use MixedBulkWriteOperationOperation correctly'() {
587641
given:
588642
def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, writeConcern, readConcern, executor)

driver-core/src/main/com/mongodb/MongoWriteConcernException.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import com.mongodb.bulk.WriteConcernError;
2020

21+
import static com.mongodb.assertions.Assertions.notNull;
22+
2123
/**
2224
* An exception indicating a failure to apply the write concern to the requested write operation
2325
*
@@ -29,23 +31,50 @@ public class MongoWriteConcernException extends MongoServerException {
2931
private static final long serialVersionUID = 4577579466973523211L;
3032

3133
private final WriteConcernError writeConcernError;
34+
private final WriteConcernResult writeConcernResult;
3235

3336
/**
3437
* Construct an instance.
3538
*
36-
* @param writeConcernError the write concern error
37-
* @param serverAddress the server address
39+
* @param writeConcernError the non-null write concern error
40+
* @param serverAddress the non-null server address
3841
*/
3942
public MongoWriteConcernException(final WriteConcernError writeConcernError, final ServerAddress serverAddress) {
43+
this(writeConcernError, null, serverAddress);
44+
}
45+
46+
/**
47+
* Construct an instance.
48+
*
49+
* @param writeConcernError the non-null write concern error
50+
* @param writeConcernResult the write result
51+
* @param serverAddress the non-null server address
52+
* @since 3.2
53+
*/
54+
public MongoWriteConcernException(final WriteConcernError writeConcernError, final WriteConcernResult writeConcernResult,
55+
final ServerAddress serverAddress) {
4056
super(writeConcernError.getCode(), writeConcernError.getMessage(), serverAddress);
41-
this.writeConcernError = writeConcernError;
57+
this.writeConcernResult = writeConcernResult;
58+
this.writeConcernError = notNull("writeConcernError", writeConcernError);
4259
}
4360

4461
/**
62+
* Gets the write concern error.
4563
*
46-
* @return the write concern error
64+
* @return the write concern error, which may not be null
4765
*/
4866
public WriteConcernError getWriteConcernError() {
4967
return writeConcernError;
5068
}
69+
70+
/**
71+
* Gets the write result.
72+
*
73+
* @return the write result
74+
*
75+
* @since 3.2
76+
*/
77+
public WriteConcernResult getWriteResult() {
78+
return writeConcernResult;
79+
}
5180
}

driver-core/src/main/com/mongodb/WriteConcernException.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ public static int extractErrorCode(final BsonDocument response) {
8484
public static String extractErrorMessage(final BsonDocument response) {
8585
if (response.isString("err")) {
8686
return response.getString("err").getValue();
87+
} else if (response.isString("errmsg")) {
88+
return response.getString("errmsg").getValue();
8789
} else {
8890
return null;
8991
}

driver-core/src/main/com/mongodb/operation/AggregateOperation.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package com.mongodb.operation;
1818

1919
import com.mongodb.ExplainVerbosity;
20-
import com.mongodb.Function;
2120
import com.mongodb.MongoNamespace;
2221
import com.mongodb.ReadConcern;
22+
import com.mongodb.ServerAddress;
2323
import com.mongodb.async.AsyncBatchCursor;
2424
import com.mongodb.async.SingleResultCallback;
2525
import com.mongodb.binding.AsyncConnectionSource;
@@ -30,6 +30,7 @@
3030
import com.mongodb.connection.Connection;
3131
import com.mongodb.connection.ConnectionDescription;
3232
import com.mongodb.connection.QueryResult;
33+
import com.mongodb.operation.CommandOperationHelper.CommandTransformer;
3334
import org.bson.BsonArray;
3435
import org.bson.BsonBoolean;
3536
import org.bson.BsonDocument;
@@ -321,21 +322,21 @@ private QueryResult<T> createQueryResult(final BsonDocument result, final Connec
321322
}
322323
}
323324

324-
private Function<BsonDocument, BatchCursor<T>> transformer(final ConnectionSource source, final Connection connection) {
325-
return new Function<BsonDocument, BatchCursor<T>>() {
325+
private CommandTransformer<BsonDocument, BatchCursor<T>> transformer(final ConnectionSource source, final Connection connection) {
326+
return new CommandTransformer<BsonDocument, BatchCursor<T>>() {
326327
@Override
327-
public BatchCursor<T> apply(final BsonDocument result) {
328+
public BatchCursor<T> apply(final BsonDocument result, final ServerAddress serverAddress) {
328329
QueryResult<T> queryResult = createQueryResult(result, connection.getDescription());
329330
return new QueryBatchCursor<T>(queryResult, 0, batchSize != null ? batchSize : 0, decoder, source);
330331
}
331332
};
332333
}
333334

334-
private Function<BsonDocument, AsyncBatchCursor<T>> asyncTransformer(final AsyncConnectionSource source,
335+
private CommandTransformer<BsonDocument, AsyncBatchCursor<T>> asyncTransformer(final AsyncConnectionSource source,
335336
final AsyncConnection connection) {
336-
return new Function<BsonDocument, AsyncBatchCursor<T>>() {
337+
return new CommandTransformer<BsonDocument, AsyncBatchCursor<T>>() {
337338
@Override
338-
public AsyncBatchCursor<T> apply(final BsonDocument result) {
339+
public AsyncBatchCursor<T> apply(final BsonDocument result, final ServerAddress serverAddress) {
339340
QueryResult<T> queryResult = createQueryResult(result, connection.getDescription());
340341
return new AsyncQueryBatchCursor<T>(queryResult, 0, batchSize != null ? batchSize : 0, decoder, source, connection);
341342
}

driver-core/src/main/com/mongodb/operation/AggregateToCollectionOperation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
import static com.mongodb.assertions.Assertions.isTrueArgument;
3636
import static com.mongodb.assertions.Assertions.notNull;
3737
import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback;
38+
import static com.mongodb.operation.CommandOperationHelper.VoidTransformer;
3839
import static com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol;
3940
import static com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocolAsync;
40-
import static com.mongodb.operation.OperationHelper.VoidTransformer;
4141
import static com.mongodb.operation.OperationHelper.releasingCallback;
4242
import static com.mongodb.operation.OperationHelper.serverIsAtLeastVersionThreeDotTwo;
4343
import static com.mongodb.operation.OperationHelper.withConnection;

0 commit comments

Comments
 (0)