Skip to content

Commit 2bf6aaa

Browse files
committed
Limit server selection deprioritization to system overloaded errors on replica sets
- Gate server deprioritization in onAttemptFailure: sharded clusters deprioritize on any error, all other topologies only on SystemOverloadedError - Pass ClusterType to updateCandidate so onAttemptFailure can distinguish topology types - Parameterize ServerDeprioritizationTest by cluster type and error type to cover conditional deprioritization - Add retryable reads prose tests 3.1 and 3.2 JAVA-6105
1 parent 446f8ff commit 2bf6aaa

File tree

7 files changed

+363
-175
lines changed

7 files changed

+363
-175
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public ServerTuple selectServer(final ServerSelector serverSelector, final Opera
163163
if (serverTuple != null) {
164164
ServerAddress serverAddress = serverTuple.getServerDescription().getAddress();
165165
logServerSelectionSucceeded(operationContext, clusterId, serverAddress, serverSelector, currentDescription);
166-
serverDeprioritization.updateCandidate(serverAddress);
166+
serverDeprioritization.updateCandidate(serverAddress, currentDescription.getType());
167167
return serverTuple;
168168
}
169169
computedServerSelectionTimeout.onExpired(() ->
@@ -306,7 +306,7 @@ private boolean handleServerSelectionRequest(
306306
if (serverTuple != null) {
307307
ServerAddress serverAddress = serverTuple.getServerDescription().getAddress();
308308
logServerSelectionSucceeded(operationContext, clusterId, serverAddress, request.originalSelector, description);
309-
serverDeprioritization.updateCandidate(serverAddress);
309+
serverDeprioritization.updateCandidate(serverAddress, description.getType());
310310
request.onResult(serverTuple, null);
311311
return true;
312312
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
import com.mongodb.Function;
1919
import com.mongodb.MongoConnectionPoolClearedException;
20+
import com.mongodb.MongoException;
2021
import com.mongodb.ReadConcern;
2122
import com.mongodb.RequestContext;
2223
import com.mongodb.ServerAddress;
2324
import com.mongodb.ServerApi;
2425
import com.mongodb.connection.ClusterDescription;
26+
import com.mongodb.connection.ClusterType;
2527
import com.mongodb.connection.ServerDescription;
2628
import com.mongodb.internal.IgnorableRequestContext;
2729
import com.mongodb.internal.TimeoutContext;
@@ -215,6 +217,7 @@ public OperationContext withOverride(final TimeoutContextOverride timeoutContext
215217
public static final class ServerDeprioritization {
216218
@Nullable
217219
private ServerAddress candidate;
220+
private ClusterType clusterType;
218221
private final Set<ServerAddress> deprioritized;
219222

220223
private ServerDeprioritization() {
@@ -236,16 +239,21 @@ ServerSelector apply(final ServerSelector wrappedSelector) {
236239
}
237240

238241
@VisibleForTesting(otherwise = PACKAGE)
239-
public void updateCandidate(final ServerAddress serverAddress) {
240-
candidate = serverAddress;
242+
public void updateCandidate(final ServerAddress serverAddress, final ClusterType clusterType) {
243+
this.candidate = serverAddress;
244+
this.clusterType = clusterType;
241245
}
242246

243247
public void onAttemptFailure(final Throwable failure) {
244248
if (candidate == null || failure instanceof MongoConnectionPoolClearedException) {
245249
candidate = null;
246250
return;
247251
}
248-
deprioritized.add(candidate);
252+
253+
boolean isSystemOverloadedError = failure instanceof MongoException && ((MongoException) failure).hasErrorLabel("SystemOverloadedError");
254+
if (clusterType == ClusterType.SHARDED || isSystemOverloadedError) {
255+
deprioritized.add(candidate);
256+
}
249257
}
250258

251259
/**

driver-core/src/test/unit/com/mongodb/connection/ServerSelectionSelectionTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,10 @@
6767

6868
import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS;
6969
import static com.mongodb.connection.ServerDescription.MIN_DRIVER_WIRE_VERSION;
70-
import static java.lang.String.format;
70+
import static org.junit.Assert.assertNotNull;
7171
import static org.junit.Assert.assertTrue;
7272
import static org.junit.Assert.fail;
7373
import static org.junit.Assume.assumeFalse;
74-
import static org.junit.Assert.assertNotNull;
7574
import static org.mockito.Mockito.when;
7675

7776
/**
@@ -299,8 +298,12 @@ private OperationContext createOperationContext() {
299298
new TimeoutContext(TIMEOUT_SETTINGS.withServerSelectionTimeoutMS(0)));
300299
OperationContext.ServerDeprioritization serverDeprioritization = operationContext.getServerDeprioritization();
301300
for (ServerAddress address : extractDeprioritizedServerAddresses(definition)) {
302-
serverDeprioritization.updateCandidate(address);
303-
serverDeprioritization.onAttemptFailure(new MongoException("test"));
301+
serverDeprioritization.updateCandidate(address, clusterDescription.getType());
302+
// The spec defines deprioritized_servers as a pre-populated list to feed into the selection mechanism - not as "simulate the
303+
// failure that caused deprioritization." Thus, SystemOverloadedError used unconditionally regardless of the cluster type.
304+
MongoException error = new MongoException("test");
305+
error.addLabel("SystemOverloadedError");
306+
serverDeprioritization.onAttemptFailure(error);
304307
}
305308
return operationContext;
306309
}
@@ -317,7 +320,7 @@ private static Cluster.ServersSnapshot createServersSnapshot(
317320
return serverMap::get;
318321
}
319322

320-
private static void validateTestDescriptionFields(final Set<String> actualFields, final Set<String> knownFields) {
323+
private static void validateTestDescriptionFields(final Set<String> actualFields, final Set<String> knownFields) {
321324
Set<String> unknownFields = new HashSet<>(actualFields);
322325
unknownFields.removeAll(knownFields);
323326
if (!unknownFields.isEmpty()) {

0 commit comments

Comments
 (0)