Skip to content

Commit 1db10dc

Browse files
authored
Use "hello" command where possible (#717)
There are two scenarios where "hello" command can be used: 1. When the application declares an API version 3. When the response to "ismaster" contains helloOk: true Additionally, use OP_MSG when the application declares an API version, even when maxWireVersion is unknown during the handshake JAVA-4092 JAVA-4157
1 parent 379ba75 commit 1db10dc

19 files changed

+115
-56
lines changed

driver-core/src/main/com/mongodb/connection/ServerDescription.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public class ServerDescription {
9494
private final Integer logicalSessionTimeoutMinutes;
9595

9696
private final Throwable exception;
97+
private final boolean helloOk;
9798

9899
/**
99100
* Gets a Builder for creating a new ServerDescription instance.
@@ -137,6 +138,18 @@ public Integer getLogicalSessionTimeoutMinutes() {
137138
return logicalSessionTimeoutMinutes;
138139
}
139140

141+
142+
/**
143+
* Gets whether this server supports the "hello" command. The default is {@code false}.
144+
*
145+
* @return true if this server supports the "hello" command.
146+
* @mongodb.server.release 5.0
147+
* @since 4.3
148+
*/
149+
public boolean isHelloOk() {
150+
return helloOk;
151+
}
152+
140153
/**
141154
* A builder for creating ServerDescription.
142155
*/
@@ -163,6 +176,7 @@ public static class Builder {
163176
private Date lastWriteDate;
164177
private long lastUpdateTimeNanos = Time.nanoTime();
165178
private Integer logicalSessionTimeoutMinutes;
179+
private boolean helloOk;
166180

167181
private Throwable exception;
168182

@@ -441,6 +455,18 @@ public Builder logicalSessionTimeoutMinutes(@Nullable final Integer logicalSessi
441455
return this;
442456
}
443457

458+
/**
459+
* Sets whether this server supports the "hello" command. The default is {@code false}.
460+
*
461+
* @param helloOk helloOk
462+
* @return this
463+
* @mongodb.server.release 5.0
464+
* @since 4.3
465+
*/
466+
public Builder helloOk(final boolean helloOk) {
467+
this.helloOk = helloOk;
468+
return this;
469+
}
444470

445471
/**
446472
* Sets the exception thrown while attempting to determine the server description.
@@ -895,6 +921,10 @@ public boolean equals(final Object o) {
895921
return false;
896922
}
897923

924+
if (helloOk != that.helloOk) {
925+
return false;
926+
}
927+
898928
// Compare class equality and message as exceptions rarely override equals
899929
Class<?> thisExceptionClass = exception != null ? exception.getClass() : null;
900930
Class<?> thatExceptionClass = that.exception != null ? that.exception.getClass() : null;
@@ -933,6 +963,7 @@ public int hashCode() {
933963
result = 31 * result + minWireVersion;
934964
result = 31 * result + maxWireVersion;
935965
result = 31 * result + (logicalSessionTimeoutMinutes != null ? logicalSessionTimeoutMinutes.hashCode() : 0);
966+
result = 31 * result + (helloOk ? 1 : 0);
936967
result = 31 * result + (exception == null ? 0 : exception.getClass().hashCode());
937968
result = 31 * result + (exception == null ? 0 : exception.getMessage().hashCode());
938969
return result;
@@ -1032,6 +1063,7 @@ private String getRoundTripFormattedInMilliseconds() {
10321063
lastWriteDate = builder.lastWriteDate;
10331064
lastUpdateTimeNanos = builder.lastUpdateTimeNanos;
10341065
logicalSessionTimeoutMinutes = builder.logicalSessionTimeoutMinutes;
1066+
helloOk = builder.helloOk;
10351067
exception = builder.exception;
10361068
}
10371069
}

driver-core/src/main/com/mongodb/internal/connection/CommandMessage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public final class CommandMessage extends RequestMessage {
9696
final boolean responseExpected, final boolean exhaustAllowed,
9797
final SplittablePayload payload, final FieldNameValidator payloadFieldNameValidator,
9898
final ClusterConnectionMode clusterConnectionMode, final @Nullable ServerApi serverApi) {
99-
super(namespace.getFullName(), getOpCode(settings), settings);
99+
super(namespace.getFullName(), getOpCode(settings, serverApi), settings);
100100
this.namespace = namespace;
101101
this.command = command;
102102
this.commandFieldNameValidator = commandFieldNameValidator;
@@ -328,8 +328,8 @@ private void addReadConcernDocument(final List<BsonElement> extraElements, final
328328
}
329329
}
330330

331-
private static OpCode getOpCode(final MessageSettings settings) {
332-
return isServerVersionAtLeastThreeDotSix(settings) ? OpCode.OP_MSG : OpCode.OP_QUERY;
331+
private static OpCode getOpCode(final MessageSettings settings, @Nullable final ServerApi serverApi) {
332+
return isServerVersionAtLeastThreeDotSix(settings) || serverApi != null ? OpCode.OP_MSG : OpCode.OP_QUERY;
333333
}
334334

335335
private static boolean isServerVersionAtLeastThreeDotSix(final MessageSettings settings) {

driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.mongodb.internal.session.SessionContext;
3333
import com.mongodb.internal.validator.NoOpFieldNameValidator;
3434
import com.mongodb.lang.Nullable;
35+
import org.bson.BsonBoolean;
3536
import org.bson.BsonDocument;
3637
import org.bson.BsonInt32;
3738
import org.bson.BsonInt64;
@@ -206,7 +207,8 @@ private ServerDescription lookupServerDescription(final ServerDescription curren
206207
try {
207208
SessionContext sessionContext = new ClusterClockAdvancingSessionContext(NoOpSessionContext.INSTANCE, clusterClock);
208209
if (!connection.hasMoreToCome()) {
209-
BsonDocument ismaster = new BsonDocument("ismaster", new BsonInt32(1));
210+
BsonDocument ismaster = new BsonDocument(getHandshakeCommandName(currentServerDescription), new BsonInt32(1))
211+
.append("helloOk", BsonBoolean.TRUE);
210212
if (shouldStreamResponses(currentServerDescription)) {
211213
ismaster.append("topologyVersion", currentServerDescription.getTopologyVersion().asDocument());
212214
ismaster.append("maxAwaitTimeMS", new BsonInt64(serverSettings.getHeartbeatFrequency(MILLISECONDS)));
@@ -430,7 +432,9 @@ private void initialize() {
430432

431433
private void pingServer(final InternalConnection connection) {
432434
long start = System.nanoTime();
433-
executeCommand("admin", new BsonDocument("ismaster", new BsonInt32(1)), clusterClock, serverApi, connection);
435+
executeCommand("admin",
436+
new BsonDocument(getHandshakeCommandName(connection.getInitialServerDescription()), new BsonInt32(1)),
437+
clusterClock, serverApi, connection);
434438
long elapsedTimeNanos = System.nanoTime() - start;
435439
averageRoundTripTime.addSample(elapsedTimeNanos);
436440
}
@@ -443,4 +447,8 @@ private void waitForNext() {
443447
// fall through
444448
}
445449
}
450+
451+
private String getHandshakeCommandName(final ServerDescription serverDescription) {
452+
return serverDescription.isHelloOk() ? "hello" : "ismaster";
453+
}
446454
}

driver-core/src/main/com/mongodb/internal/connection/DescriptionHelper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public static ServerDescription createServerDescription(final ServerAddress serv
112112
.lastWriteDate(getLastWriteDate(isMasterResult))
113113
.roundTripTime(roundTripTime, NANOSECONDS)
114114
.logicalSessionTimeoutMinutes(getLogicalSessionTimeoutMinutes(isMasterResult))
115+
.helloOk(isMasterResult.getBoolean("helloOk", BsonBoolean.FALSE).getValue())
115116
.ok(CommandHelper.isCommandOk(isMasterResult)).build();
116117
}
117118

@@ -192,6 +193,10 @@ private static ServerType getServerType(final BsonDocument isMasterResult) {
192193
return REPLICA_SET_OTHER;
193194
}
194195

196+
if (isMasterResult.getBoolean("isWritablePrimary", BsonBoolean.FALSE).getValue()) {
197+
return REPLICA_SET_PRIMARY;
198+
}
199+
195200
if (isMasterResult.getBoolean("ismaster", BsonBoolean.FALSE).getValue()) {
196201
return REPLICA_SET_PRIMARY;
197202
}

driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnectionInitializer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.mongodb.internal.async.SingleResultCallback;
3030
import com.mongodb.lang.Nullable;
3131
import org.bson.BsonArray;
32+
import org.bson.BsonBoolean;
3233
import org.bson.BsonDocument;
3334
import org.bson.BsonInt32;
3435
import org.bson.BsonString;
@@ -138,7 +139,8 @@ private InternalConnectionInitializationDescription initializeConnectionDescript
138139
}
139140

140141
private BsonDocument createIsMasterCommand(final Authenticator authenticator, final InternalConnection connection) {
141-
BsonDocument isMasterCommandDocument = new BsonDocument("ismaster", new BsonInt32(1));
142+
BsonDocument isMasterCommandDocument = new BsonDocument(getHandshakeCommandName(), new BsonInt32(1))
143+
.append("helloOk", BsonBoolean.TRUE);
142144
if (clientMetadataDocument != null) {
143145
isMasterCommandDocument.append("client", clientMetadataDocument);
144146
}
@@ -262,4 +264,8 @@ private InternalConnectionInitializationDescription applyGetLastErrorResult(
262264

263265
return description.withConnectionDescription(connectionDescription.withConnectionId(connectionId));
264266
}
267+
268+
private String getHandshakeCommandName() {
269+
return serverApi == null ? "ismaster" : "hello";
270+
}
265271
}

driver-core/src/test/resources/connection-monitoring-and-pooling/pool-checkout-maxConnecting-is-enforced.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
},
1515
"data": {
1616
"failCommands": [
17-
"isMaster"
17+
"isMaster",
18+
"hello"
1819
],
1920
"closeConnection": false,
2021
"blockConnection": true,

driver-core/src/test/resources/connection-monitoring-and-pooling/pool-checkout-maxConnecting-timeout.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
},
1515
"data": {
1616
"failCommands": [
17-
"isMaster"
17+
"isMaster",
18+
"hello"
1819
],
1920
"closeConnection": false,
2021
"blockConnection": true,

driver-core/src/test/resources/connection-monitoring-and-pooling/pool-checkout-returned-connection-maxConnecting.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
},
1515
"data": {
1616
"failCommands": [
17-
"isMaster"
17+
"isMaster",
18+
"hello"
1819
],
1920
"closeConnection": false,
2021
"blockConnection": true,

driver-core/src/test/resources/server-discovery-and-monitoring-integration/connectTimeoutMS.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
},
4343
"data": {
4444
"failCommands": [
45-
"isMaster"
45+
"isMaster",
46+
"hello"
4647
],
4748
"appName": "connectTimeoutMS=0",
4849
"blockConnection": true,

driver-core/src/test/resources/server-discovery-and-monitoring-integration/isMaster-command-error.json

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"runOn": [
33
{
4-
"minServerVersion": "4.4"
4+
"minServerVersion": "4.9"
55
}
66
],
77
"database_name": "sdam-tests",
@@ -17,7 +17,8 @@
1717
},
1818
"data": {
1919
"failCommands": [
20-
"isMaster"
20+
"isMaster",
21+
"hello"
2122
],
2223
"appName": "commandErrorHandshakeTest",
2324
"closeConnection": false,
@@ -39,14 +40,6 @@
3940
"count": 1
4041
}
4142
},
42-
{
43-
"name": "waitForEvent",
44-
"object": "testRunner",
45-
"arguments": {
46-
"event": "PoolClearedEvent",
47-
"count": 1
48-
}
49-
},
5043
{
5144
"name": "insertMany",
5245
"object": "collection",
@@ -128,7 +121,8 @@
128121
},
129122
"data": {
130123
"failCommands": [
131-
"isMaster"
124+
"isMaster",
125+
"hello"
132126
],
133127
"appName": "commandErrorCheckTest",
134128
"closeConnection": false,

0 commit comments

Comments
 (0)