Skip to content

Commit 973834a

Browse files
committed
CommitQuorum option support for createIndexes command on MongoDB 4.4
JAVA-3701
1 parent 16daa31 commit 973834a

File tree

9 files changed

+423
-10
lines changed

9 files changed

+423
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb;
18+
19+
import org.bson.BsonInt32;
20+
import org.bson.BsonString;
21+
import org.bson.BsonValue;
22+
23+
import static com.mongodb.assertions.Assertions.notNull;
24+
25+
/**
26+
* A commit quorum specifies how many data-bearing members of a replica set, including the primary, must
27+
* complete the index builds successfully before the primary marks the indexes as ready.
28+
*
29+
* @mongodb.driver.manual reference/command/createIndexes/ Create indexes
30+
* @mongodb.server.release 4.4
31+
* @since 4.1
32+
*/
33+
public abstract class CreateIndexCommitQuorum {
34+
35+
/**
36+
* A create index commit quorum of majority.
37+
*/
38+
public static final CreateIndexCommitQuorum MAJORITY = new CreateIndexCommitQuorumWithMode("majority");
39+
40+
/**
41+
* A create index commit quorum of voting members.
42+
*/
43+
public static final CreateIndexCommitQuorum VOTING_MEMBERS = new CreateIndexCommitQuorumWithMode("votingMembers");
44+
45+
/**
46+
* Create a create index commit quorum with a mode value.
47+
*
48+
* @param mode the mode value
49+
* @return a create index commit quorum of the specified mode
50+
*/
51+
public static CreateIndexCommitQuorum create(final String mode) {
52+
return new CreateIndexCommitQuorumWithMode(mode);
53+
}
54+
55+
/**
56+
* Create a create index commit quorum with a w value.
57+
*
58+
* @param w the w value
59+
* @return a create index commit quorum with the specified w value
60+
*/
61+
public static CreateIndexCommitQuorum create(final int w) {
62+
return new CreateIndexCommitQuorumWithW(w);
63+
}
64+
65+
/**
66+
* Converts the create index commit quorum to a Bson value.
67+
*
68+
* @return the BsonValue that represents the create index commit quorum
69+
*/
70+
public abstract BsonValue toBsonValue();
71+
72+
private CreateIndexCommitQuorum() {
73+
}
74+
75+
private static final class CreateIndexCommitQuorumWithMode extends CreateIndexCommitQuorum {
76+
private final String mode;
77+
78+
private CreateIndexCommitQuorumWithMode(final String mode) {
79+
notNull("mode", mode);
80+
this.mode = mode;
81+
}
82+
83+
public String getMode() {
84+
return mode;
85+
}
86+
87+
@Override
88+
public BsonValue toBsonValue() {
89+
return new BsonString(mode);
90+
}
91+
92+
93+
@Override
94+
public boolean equals(final Object o) {
95+
if (this == o) {
96+
return true;
97+
}
98+
if (o == null || getClass() != o.getClass()) {
99+
return false;
100+
}
101+
102+
CreateIndexCommitQuorumWithMode that = (CreateIndexCommitQuorumWithMode) o;
103+
return mode.equals(that.mode);
104+
}
105+
106+
@Override
107+
public int hashCode() {
108+
return mode.hashCode();
109+
}
110+
111+
@Override
112+
public String toString() {
113+
return "CreateIndexCommitQuorum{"
114+
+ "mode=" + mode
115+
+ '}';
116+
}
117+
}
118+
119+
private static final class CreateIndexCommitQuorumWithW extends CreateIndexCommitQuorum {
120+
private final int w;
121+
122+
private CreateIndexCommitQuorumWithW(final int w) {
123+
if (w < 0) {
124+
throw new IllegalArgumentException("w cannot be less than zero");
125+
}
126+
this.w = w;
127+
}
128+
129+
public int getW() {
130+
return w;
131+
}
132+
133+
@Override
134+
public BsonValue toBsonValue() {
135+
return new BsonInt32(w);
136+
}
137+
138+
@Override
139+
public boolean equals(final Object o) {
140+
if (this == o) {
141+
return true;
142+
}
143+
if (o == null || getClass() != o.getClass()) {
144+
return false;
145+
}
146+
147+
CreateIndexCommitQuorumWithW that = (CreateIndexCommitQuorumWithW) o;
148+
return w == that.w;
149+
}
150+
151+
@Override
152+
public int hashCode() {
153+
return w;
154+
}
155+
156+
@Override
157+
public String toString() {
158+
return "CreateIndexCommitQuorum{"
159+
+ "w=" + w
160+
+ '}';
161+
}
162+
}
163+
}

driver-core/src/main/com/mongodb/client/model/CreateIndexOptions.java

+30
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package com.mongodb.client.model;
1818

1919

20+
import com.mongodb.CreateIndexCommitQuorum;
21+
import com.mongodb.lang.Nullable;
22+
2023
import java.util.concurrent.TimeUnit;
2124

2225
import static com.mongodb.assertions.Assertions.notNull;
@@ -29,6 +32,7 @@
2932
*/
3033
public class CreateIndexOptions {
3134
private long maxTimeMS;
35+
private CreateIndexCommitQuorum commitQuorum;
3236

3337
/**
3438
* Gets the maximum execution time on the server for this operation. The default is 0, which places no limit on the execution time.
@@ -54,10 +58,36 @@ public CreateIndexOptions maxTime(final long maxTime, final TimeUnit timeUnit) {
5458
return this;
5559
}
5660

61+
/**
62+
* Gets the create index commit quorum for this operation.
63+
*
64+
* @return the create index commit quorum
65+
* @mongodb.server.release 4.4
66+
* @since 4.1
67+
*/
68+
@Nullable
69+
public CreateIndexCommitQuorum getCommitQuorum() {
70+
return commitQuorum;
71+
}
72+
73+
/**
74+
* Sets the create index commit quorum for this operation.
75+
*
76+
* @param commitQuorum the create index commit quorum
77+
* @return this
78+
* @mongodb.server.release 4.4
79+
* @since 4.1
80+
*/
81+
public CreateIndexOptions commitQuorum(final CreateIndexCommitQuorum commitQuorum) {
82+
this.commitQuorum = commitQuorum;
83+
return this;
84+
}
85+
5786
@Override
5887
public String toString() {
5988
return "CreateIndexOptions{"
6089
+ "maxTimeMS=" + maxTimeMS
90+
+ ", commitQuorum=" + commitQuorum
6191
+ '}';
6292
}
6393
}

driver-core/src/main/com/mongodb/internal/operation/CreateIndexesOperation.java

+46-8
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package com.mongodb.internal.operation;
1818

19+
import com.mongodb.CreateIndexCommitQuorum;
1920
import com.mongodb.DuplicateKeyException;
2021
import com.mongodb.ErrorCategory;
22+
import com.mongodb.MongoClientException;
2123
import com.mongodb.MongoCommandException;
2224
import com.mongodb.MongoException;
2325
import com.mongodb.MongoNamespace;
@@ -58,6 +60,7 @@
5860
import static com.mongodb.internal.operation.OperationHelper.validateIndexRequestCollations;
5961
import static com.mongodb.internal.operation.OperationHelper.withAsyncConnection;
6062
import static com.mongodb.internal.operation.OperationHelper.withConnection;
63+
import static com.mongodb.internal.operation.ServerVersionHelper.serverIsAtLeastVersionFourDotFour;
6164
import static com.mongodb.internal.operation.WriteConcernHelper.appendWriteConcernToCommand;
6265

6366
/**
@@ -71,6 +74,7 @@ public class CreateIndexesOperation implements AsyncWriteOperation<Void>, WriteO
7174
private final List<IndexRequest> requests;
7275
private final WriteConcern writeConcern;
7376
private long maxTimeMS;
77+
private CreateIndexCommitQuorum commitQuorum;
7478

7579
/**
7680
* Construct a new instance.
@@ -161,6 +165,28 @@ public CreateIndexesOperation maxTime(final long maxTime, final TimeUnit timeUni
161165
return this;
162166
}
163167

168+
/**
169+
* Gets the create index commit quorum.
170+
*
171+
* @return the create index commit quorum
172+
* @since 4.1
173+
*/
174+
public CreateIndexCommitQuorum getCommitQuorum() {
175+
return commitQuorum;
176+
}
177+
178+
/**
179+
* Sets the create index commit quorum.
180+
*
181+
* @param commitQuorum the create index commit quorum
182+
* @return this
183+
* @since 4.1
184+
*/
185+
public CreateIndexesOperation commitQuorum(final CreateIndexCommitQuorum commitQuorum) {
186+
this.commitQuorum = commitQuorum;
187+
return this;
188+
}
189+
164190
@Override
165191
public Void execute(final WriteBinding binding) {
166192
return withConnection(binding, new CallableWithConnection<Void>() {
@@ -194,14 +220,18 @@ public void call(final AsyncConnection connection, final Throwable t) {
194220
if (t != null) {
195221
wrappedCallback.onResult(null, t);
196222
} else {
197-
executeCommandAsync(binding, namespace.getDatabaseName(),
198-
getCommand(connection.getDescription()), connection, writeConcernErrorWriteTransformer(),
199-
new SingleResultCallback<Void>() {
200-
@Override
201-
public void onResult(final Void result, final Throwable t) {
202-
wrappedCallback.onResult(null, translateException(t));
203-
}
204-
});
223+
try {
224+
executeCommandAsync(binding, namespace.getDatabaseName(),
225+
getCommand(connection.getDescription()), connection, writeConcernErrorWriteTransformer(),
226+
new SingleResultCallback<Void>() {
227+
@Override
228+
public void onResult(final Void result, final Throwable t) {
229+
wrappedCallback.onResult(null, translateException(t));
230+
}
231+
});
232+
} catch (Throwable t1) {
233+
wrappedCallback.onResult(null, t1);
234+
}
205235
}
206236
}
207237
});
@@ -284,6 +314,14 @@ private BsonDocument getCommand(final ConnectionDescription description) {
284314
command.put("indexes", new BsonArray(values));
285315
putIfNotZero(command, "maxTimeMS", maxTimeMS);
286316
appendWriteConcernToCommand(writeConcern, command, description);
317+
if (commitQuorum != null) {
318+
if (serverIsAtLeastVersionFourDotFour(description)) {
319+
command.put("commitQuorum", commitQuorum.toBsonValue());
320+
} else {
321+
throw new MongoClientException("Specifying a value for the create index commit quorum option "
322+
+ "requires a minimum MongoDB version of 4.4");
323+
}
324+
}
287325
return command;
288326
}
289327

driver-core/src/main/com/mongodb/internal/operation/Operations.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,8 @@ CreateIndexesOperation createIndexes(final List<IndexModel> indexes, final Creat
482482
);
483483
}
484484
return new CreateIndexesOperation(namespace, indexRequests, writeConcern)
485-
.maxTime(createIndexOptions.getMaxTime(MILLISECONDS), MILLISECONDS);
485+
.maxTime(createIndexOptions.getMaxTime(MILLISECONDS), MILLISECONDS)
486+
.commitQuorum(createIndexOptions.getCommitQuorum());
486487
}
487488

488489
DropIndexOperation dropIndex(final String indexName, final DropIndexOptions dropIndexOptions) {

driver-core/src/test/functional/com/mongodb/internal/operation/CreateIndexesOperationSpecification.groovy

+42
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package com.mongodb.internal.operation
1818

19+
import com.mongodb.CreateIndexCommitQuorum
1920
import com.mongodb.DuplicateKeyException
21+
import com.mongodb.MongoClientException
2022
import com.mongodb.MongoCommandException
2123
import com.mongodb.MongoExecutionTimeoutException
2224
import com.mongodb.MongoWriteConcernException
@@ -97,6 +99,46 @@ class CreateIndexesOperationSpecification extends OperationFunctionalSpecificati
9799
async << [true, false]
98100
}
99101

102+
@IgnoreIf({ serverVersionAtLeast(4, 3) })
103+
def 'should throw exception if commit quorum is set where server < 4.3'() {
104+
given:
105+
def keys = new BsonDocument('field', new BsonInt32(1))
106+
def operation = new CreateIndexesOperation(getNamespace(), [new IndexRequest(keys)])
107+
.commitQuorum(CreateIndexCommitQuorum.MAJORITY)
108+
109+
when:
110+
execute(operation, async)
111+
112+
then:
113+
thrown(MongoClientException)
114+
115+
where:
116+
async << [true, false]
117+
}
118+
119+
@IgnoreIf({ !isDiscoverableReplicaSet() || !serverVersionAtLeast(4, 3) })
120+
def 'should create index with commit quorum'() {
121+
given:
122+
def keys = new BsonDocument('field', new BsonInt32(1))
123+
124+
when:
125+
def operation = new CreateIndexesOperation(getNamespace(), [new IndexRequest(keys)])
126+
.commitQuorum(quorum)
127+
128+
then:
129+
operation.getCommitQuorum() == quorum
130+
131+
when:
132+
execute(operation, async)
133+
134+
then:
135+
getUserCreatedIndexes('key') == [field1Index]
136+
137+
where:
138+
[async, quorum] << [[true, false], [CreateIndexCommitQuorum.MAJORITY, CreateIndexCommitQuorum.VOTING_MEMBERS,
139+
CreateIndexCommitQuorum.create(1), CreateIndexCommitQuorum.create(2)]].combinations()
140+
}
141+
100142
def 'should be able to create a single index with a BsonInt64'() {
101143
given:
102144
def keys = new BsonDocument('field', new BsonInt64(1))

0 commit comments

Comments
 (0)