Skip to content

Commit 653d1bf

Browse files
committed
Retryable write support
Adds support for retryable writes for findAndModify, insert one, update one and remove one operations on 3.6 feature compatible servers. JAVA-2570
1 parent 0d3c5aa commit 653d1bf

File tree

74 files changed

+6178
-1062
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+6178
-1062
lines changed

config/checkstyle-exclude.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@
110110
<suppress checks="HideUtilityClassConstructor" files="QuickTour"/>
111111
<suppress checks="HideUtilityClassConstructor" files="Util"/>
112112

113+
<suppress checks="ParameterNumber" files="BulkWriteBatch"/>
114+
113115
<!-- Alternative copyrights -->
114116
<suppress checks="RegexpSingleline" files="Immutable"/>
115117
<suppress checks="RegexpSingleline" files="NotThreadSafe"/>

docs/reference/content/whats-new.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ The 3.6 release adds support for [change streams](https://docs.mongodb.com/manua
2929

3030
The 3.6 release adds support for causally consistency.
3131

32+
### Retryable writes
33+
34+
The 3.6 release adds support for retryable writes using the `retryWrites` option in
35+
[`MongoClientOptions`]({{<apiref "com/mongodb/MongoClientOptions">}}).
36+
3237
## What's New in 3.5
3338

3439
Key new features of the 3.5 Java driver release:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class MongoClientImpl implements MongoClient {
6464
@Override
6565
public MongoDatabase getDatabase(final String name) {
6666
return new MongoDatabaseImpl(name, settings.getCodecRegistry(), settings.getReadPreference(), settings.getWriteConcern(),
67-
settings.getReadConcern(), executor);
67+
settings.getRetryWrites(), settings.getReadConcern(), executor);
6868
}
6969

7070
@Override

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
public final class MongoClientSettings {
5151
private final ReadPreference readPreference;
5252
private final WriteConcern writeConcern;
53+
private final boolean retryWrites;
5354
private final ReadConcern readConcern;
5455
private final List<MongoCredential> credentialList;
5556
private final StreamFactoryFactory streamFactoryFactory;
@@ -93,6 +94,7 @@ public static Builder builder(final MongoClientSettings settings) {
9394
public static final class Builder {
9495
private ReadPreference readPreference = ReadPreference.primary();
9596
private WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED;
97+
private boolean retryWrites;
9698
private ReadConcern readConcern = ReadConcern.DEFAULT;
9799
private CodecRegistry codecRegistry = MongoClients.getDefaultCodecRegistry();
98100
private StreamFactoryFactory streamFactoryFactory;
@@ -122,6 +124,7 @@ private Builder() {
122124
private Builder(final MongoClientSettings settings) {
123125
readPreference = settings.getReadPreference();
124126
writeConcern = settings.getWriteConcern();
127+
retryWrites = settings.getRetryWrites();
125128
readConcern = settings.getReadConcern();
126129
credentialList = settings.getCredentialList();
127130
codecRegistry = settings.getCodecRegistry();
@@ -235,6 +238,20 @@ public Builder writeConcern(final WriteConcern writeConcern) {
235238
return this;
236239
}
237240

241+
/**
242+
* Sets whether writes should be retried if they fail due to a network error.
243+
*
244+
* @param retryWrites sets if writes should be retried if they fail due to a network error.
245+
* @return {@code this}
246+
* @see #getRetryWrites()
247+
* @since 3.6
248+
* @mongodb.server.release 3.6
249+
*/
250+
public Builder retryWrites(final boolean retryWrites) {
251+
this.retryWrites = retryWrites;
252+
return this;
253+
}
254+
238255
/**
239256
* Sets the read concern.
240257
*
@@ -379,6 +396,17 @@ public WriteConcern getWriteConcern() {
379396
return writeConcern;
380397
}
381398

399+
/**
400+
* Returns true if writes should be retried if they fail due to a network error.
401+
*
402+
* @return the retryWrites value
403+
* @since 3.6
404+
* @mongodb.server.release 3.6
405+
*/
406+
public boolean getRetryWrites() {
407+
return retryWrites;
408+
}
409+
382410
/**
383411
* The read concern to use.
384412
*
@@ -518,6 +546,7 @@ public ServerSettings getServerSettings() {
518546
private MongoClientSettings(final Builder builder) {
519547
readPreference = builder.readPreference;
520548
writeConcern = builder.writeConcern;
549+
retryWrites = builder.retryWrites;
521550
readConcern = builder.readConcern;
522551
credentialList = builder.credentialList;
523552
streamFactoryFactory = builder.streamFactoryFactory;

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

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,19 @@ class MongoCollectionImpl<TDocument> implements MongoCollection<TDocument> {
9696
private final ReadPreference readPreference;
9797
private final CodecRegistry codecRegistry;
9898
private final WriteConcern writeConcern;
99+
private final boolean retryWrites;
99100
private final ReadConcern readConcern;
100101
private final AsyncOperationExecutor executor;
101102

102103
MongoCollectionImpl(final MongoNamespace namespace, final Class<TDocument> documentClass, final CodecRegistry codecRegistry,
103-
final ReadPreference readPreference, final WriteConcern writeConcern, final ReadConcern readConcern,
104-
final AsyncOperationExecutor executor) {
104+
final ReadPreference readPreference, final WriteConcern writeConcern, final boolean retryWrites,
105+
final ReadConcern readConcern, final AsyncOperationExecutor executor) {
105106
this.namespace = notNull("namespace", namespace);
106107
this.documentClass = notNull("documentClass", documentClass);
107108
this.codecRegistry = notNull("codecRegistry", codecRegistry);
108109
this.readPreference = notNull("readPreference", readPreference);
109110
this.writeConcern = notNull("writeConcern", writeConcern);
111+
this.retryWrites = retryWrites;
110112
this.readConcern = notNull("readConcern", readConcern);
111113
this.executor = notNull("executor", executor);
112114
}
@@ -143,32 +145,32 @@ public ReadConcern getReadConcern() {
143145

144146
@Override
145147
public <NewTDocument> MongoCollection<NewTDocument> withDocumentClass(final Class<NewTDocument> newDocumentClass) {
146-
return new MongoCollectionImpl<NewTDocument>(namespace, newDocumentClass, codecRegistry, readPreference, writeConcern, readConcern,
147-
executor);
148+
return new MongoCollectionImpl<NewTDocument>(namespace, newDocumentClass, codecRegistry, readPreference, writeConcern, retryWrites,
149+
readConcern, executor);
148150
}
149151

150152
@Override
151153
public MongoCollection<TDocument> withCodecRegistry(final CodecRegistry codecRegistry) {
152-
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, readConcern,
153-
executor);
154+
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, retryWrites,
155+
readConcern, executor);
154156
}
155157

156158
@Override
157159
public MongoCollection<TDocument> withReadPreference(final ReadPreference readPreference) {
158-
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, readConcern,
159-
executor);
160+
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, retryWrites,
161+
readConcern, executor);
160162
}
161163

162164
@Override
163165
public MongoCollection<TDocument> withWriteConcern(final WriteConcern writeConcern) {
164-
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, readConcern,
165-
executor);
166+
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, retryWrites,
167+
readConcern, executor);
166168
}
167169

168170
@Override
169171
public MongoCollection<TDocument> withReadConcern(final ReadConcern readConcern) {
170-
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, readConcern,
171-
executor);
172+
return new MongoCollectionImpl<TDocument>(namespace, documentClass, codecRegistry, readPreference, writeConcern, retryWrites,
173+
readConcern, executor);
172174
}
173175

174176
@Override
@@ -333,7 +335,7 @@ public void bulkWrite(final List<? extends WriteModel<? extends TDocument>> requ
333335
writeRequests.add(writeRequest);
334336
}
335337

336-
executor.execute(new MixedBulkWriteOperation(namespace, writeRequests, options.isOrdered(), writeConcern)
338+
executor.execute(new MixedBulkWriteOperation(namespace, writeRequests, options.isOrdered(), writeConcern, retryWrites)
337339
.bypassDocumentValidation(options.getBypassDocumentValidation()), callback);
338340
}
339341

@@ -376,7 +378,7 @@ public void insertMany(final List<? extends TDocument> documents, final InsertMa
376378
}
377379
requests.add(new InsertRequest(documentToBsonDocument(document)));
378380
}
379-
executor.execute(new MixedBulkWriteOperation(namespace, requests, options.isOrdered(), writeConcern)
381+
executor.execute(new MixedBulkWriteOperation(namespace, requests, options.isOrdered(), writeConcern, retryWrites)
380382
.bypassDocumentValidation(options.getBypassDocumentValidation()), errorHandlingCallback(
381383
new SingleResultCallback<BulkWriteResult>() {
382384
@Override
@@ -457,7 +459,7 @@ public void findOneAndDelete(final Bson filter, final SingleResultCallback<TDocu
457459

458460
@Override
459461
public void findOneAndDelete(final Bson filter, final FindOneAndDeleteOptions options, final SingleResultCallback<TDocument> callback) {
460-
executor.execute(new FindAndDeleteOperation<TDocument>(namespace, writeConcern, getCodec())
462+
executor.execute(new FindAndDeleteOperation<TDocument>(namespace, writeConcern, retryWrites, getCodec())
461463
.filter(toBsonDocument(filter))
462464
.projection(toBsonDocument(options.getProjection()))
463465
.sort(toBsonDocument(options.getSort()))
@@ -473,15 +475,16 @@ public void findOneAndReplace(final Bson filter, final TDocument replacement, fi
473475
@Override
474476
public void findOneAndReplace(final Bson filter, final TDocument replacement, final FindOneAndReplaceOptions options,
475477
final SingleResultCallback<TDocument> callback) {
476-
executor.execute(new FindAndReplaceOperation<TDocument>(namespace, writeConcern, getCodec(), documentToBsonDocument(replacement))
477-
.filter(toBsonDocument(filter))
478-
.projection(toBsonDocument(options.getProjection()))
479-
.sort(toBsonDocument(options.getSort()))
480-
.returnOriginal(options.getReturnDocument() == ReturnDocument.BEFORE)
481-
.upsert(options.isUpsert())
482-
.maxTime(options.getMaxTime(MILLISECONDS), MILLISECONDS)
483-
.bypassDocumentValidation(options.getBypassDocumentValidation())
484-
.collation(options.getCollation()), callback);
478+
executor.execute(new FindAndReplaceOperation<TDocument>(namespace, writeConcern, retryWrites, getCodec(),
479+
documentToBsonDocument(replacement))
480+
.filter(toBsonDocument(filter))
481+
.projection(toBsonDocument(options.getProjection()))
482+
.sort(toBsonDocument(options.getSort()))
483+
.returnOriginal(options.getReturnDocument() == ReturnDocument.BEFORE)
484+
.upsert(options.isUpsert())
485+
.maxTime(options.getMaxTime(MILLISECONDS), MILLISECONDS)
486+
.bypassDocumentValidation(options.getBypassDocumentValidation())
487+
.collation(options.getCollation()), callback);
485488
}
486489

487490
@Override
@@ -492,7 +495,7 @@ public void findOneAndUpdate(final Bson filter, final Bson update, final SingleR
492495
@Override
493496
public void findOneAndUpdate(final Bson filter, final Bson update, final FindOneAndUpdateOptions options,
494497
final SingleResultCallback<TDocument> callback) {
495-
executor.execute(new FindAndUpdateOperation<TDocument>(namespace, writeConcern, getCodec(), toBsonDocument(update))
498+
executor.execute(new FindAndUpdateOperation<TDocument>(namespace, writeConcern, retryWrites, getCodec(), toBsonDocument(update))
496499
.filter(toBsonDocument(filter))
497500
.projection(toBsonDocument(options.getProjection()))
498501
.sort(toBsonDocument(options.getSort()))
@@ -646,7 +649,7 @@ public void onResult(final BulkWriteResult result, final Throwable t) {
646649

647650
private void executeSingleWriteRequest(final WriteRequest request, final Boolean bypassDocumentValidation,
648651
final SingleResultCallback<BulkWriteResult> callback) {
649-
executor.execute(new MixedBulkWriteOperation(namespace, singletonList(request), true, writeConcern)
652+
executor.execute(new MixedBulkWriteOperation(namespace, singletonList(request), true, writeConcern, retryWrites)
650653
.bypassDocumentValidation(bypassDocumentValidation),
651654
new SingleResultCallback<BulkWriteResult>() {
652655
@Override

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,19 @@ class MongoDatabaseImpl implements MongoDatabase {
4747
private final ReadPreference readPreference;
4848
private final CodecRegistry codecRegistry;
4949
private final WriteConcern writeConcern;
50+
private final boolean retryWrites;
5051
private final ReadConcern readConcern;
5152
private final AsyncOperationExecutor executor;
5253

5354
MongoDatabaseImpl(final String name, final CodecRegistry codecRegistry, final ReadPreference readPreference,
54-
final WriteConcern writeConcern, final ReadConcern readConcern, final AsyncOperationExecutor executor) {
55+
final WriteConcern writeConcern, final boolean retryWrites, final ReadConcern readConcern,
56+
final AsyncOperationExecutor executor) {
5557
checkDatabaseNameValidity(name);
5658
this.name = notNull("name", name);
5759
this.codecRegistry = notNull("codecRegistry", codecRegistry);
5860
this.readPreference = notNull("readPreference", readPreference);
5961
this.writeConcern = notNull("writeConcern", writeConcern);
62+
this.retryWrites = retryWrites;
6063
this.readConcern = notNull("readConcern", readConcern);
6164
this.executor = notNull("executor", executor);
6265
}
@@ -88,22 +91,22 @@ public ReadConcern getReadConcern() {
8891

8992
@Override
9093
public MongoDatabase withCodecRegistry(final CodecRegistry codecRegistry) {
91-
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, readConcern, executor);
94+
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, retryWrites, readConcern, executor);
9295
}
9396

9497
@Override
9598
public MongoDatabase withReadPreference(final ReadPreference readPreference) {
96-
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, readConcern, executor);
99+
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, retryWrites, readConcern, executor);
97100
}
98101

99102
@Override
100103
public MongoDatabase withWriteConcern(final WriteConcern writeConcern) {
101-
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, readConcern, executor);
104+
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, retryWrites, readConcern, executor);
102105
}
103106

104107
@Override
105108
public MongoDatabase withReadConcern(final ReadConcern readConcern) {
106-
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, readConcern, executor);
109+
return new MongoDatabaseImpl(name, codecRegistry, readPreference, writeConcern, retryWrites, readConcern, executor);
107110
}
108111

109112
@Override
@@ -135,7 +138,7 @@ public MongoCollection<Document> getCollection(final String collectionName) {
135138
@Override
136139
public <TDocument> MongoCollection<TDocument> getCollection(final String collectionName, final Class<TDocument> documentClass) {
137140
return new MongoCollectionImpl<TDocument>(new MongoNamespace(name, collectionName), documentClass, codecRegistry, readPreference,
138-
writeConcern, readConcern, executor);
141+
writeConcern, retryWrites, readConcern, executor);
139142
}
140143

141144
@Override

0 commit comments

Comments
 (0)