From 76664e4fcb1a351e87bde238ccf4c7b64f47ad3c Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 10 Dec 2025 09:39:08 -0700 Subject: [PATCH 1/4] misc server selection cleanups --- src/sdam/server_selection.ts | 63 ++++++++++++++---------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/src/sdam/server_selection.ts b/src/sdam/server_selection.ts index 03b6e959386..76c1524aa4e 100644 --- a/src/sdam/server_selection.ts +++ b/src/sdam/server_selection.ts @@ -113,7 +113,7 @@ function maxStalenessReducer( primaryFilter )[0]; - return servers.reduce((result: ServerDescription[], server: ServerDescription) => { + return servers.filter((server: ServerDescription) => { const stalenessMS = server.lastUpdateTime - server.lastWriteDate - @@ -122,12 +122,8 @@ function maxStalenessReducer( const staleness = stalenessMS / 1000; const maxStalenessSeconds = readPreference.maxStalenessSeconds ?? 0; - if (staleness <= maxStalenessSeconds) { - result.push(server); - } - - return result; - }, []); + return staleness <= maxStalenessSeconds; + }); } if (topologyDescription.type === TopologyType.ReplicaSetNoPrimary) { @@ -139,40 +135,38 @@ function maxStalenessReducer( s.lastWriteDate > max.lastWriteDate ? s : max ); - return servers.reduce((result: ServerDescription[], server: ServerDescription) => { + return servers.filter((server: ServerDescription) => { const stalenessMS = sMax.lastWriteDate - server.lastWriteDate + topologyDescription.heartbeatFrequencyMS; const staleness = stalenessMS / 1000; const maxStalenessSeconds = readPreference.maxStalenessSeconds ?? 0; - if (staleness <= maxStalenessSeconds) { - result.push(server); - } - - return result; - }, []); + return staleness <= maxStalenessSeconds; + }); } return servers; } /** - * Determines whether a server's tags match a given set of tags + * Determines whether a server's tags match a given set of tags. + * + * A tagset matches the server's tags if every k-v pair in the tagset + * is also in the server's tagset. + * + * Note that this does not requires that every k-v pair in the server's tagset is also + * in the client's tagset. The server's tagset is required only to be a superset of the + * client's tags. + * + * @see https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md#tag_sets * * @param tagSet - The requested tag set to match * @param serverTags - The server's tags */ function tagSetMatch(tagSet: TagSet, serverTags: TagSet) { - const keys = Object.keys(tagSet); - const serverTagKeys = Object.keys(serverTags); - for (let i = 0; i < keys.length; ++i) { - const key = keys[i]; - if (serverTagKeys.indexOf(key) === -1 || serverTags[key] !== tagSet[key]) { - return false; - } - } - - return true; + return Object.entries(tagSet).every( + ([key, value]) => serverTags[key] != null && serverTags[key] === value + ); } /** @@ -183,24 +177,17 @@ function tagSetMatch(tagSet: TagSet, serverTags: TagSet) { * @returns The list of servers matching the requested tags */ function tagSetReducer( - readPreference: ReadPreference, + { tags }: ReadPreference, servers: ServerDescription[] ): ServerDescription[] { - if ( - readPreference.tags == null || - (Array.isArray(readPreference.tags) && readPreference.tags.length === 0) - ) { + if (tags == null || tags.length === 0) { + // empty tag sets match all servers return servers; } - for (let i = 0; i < readPreference.tags.length; ++i) { - const tagSet = readPreference.tags[i]; - const serversMatchingTagset = servers.reduce( - (matched: ServerDescription[], server: ServerDescription) => { - if (tagSetMatch(tagSet, server.tags)) matched.push(server); - return matched; - }, - [] + for (const tagSet of tags) { + const serversMatchingTagset = servers.filter((s: ServerDescription) => + tagSetMatch(tagSet, s.tags) ); if (serversMatchingTagset.length) { From b456b3babde0c69505957f2fa48feb1dace97352 Mon Sep 17 00:00:00 2001 From: bailey Date: Tue, 9 Dec 2025 11:52:13 -0700 Subject: [PATCH 2/4] Initial POC - all tests passing but using full server descriptions for change tracking. --- src/change_stream.ts | 3 +- src/mongo_client.ts | 2 +- src/operations/execute_operation.ts | 9 +- src/sdam/server_selection.ts | 128 +++++++++--- src/sdam/topology.ts | 17 +- .../read/DeprioritizedNearest.json | 63 ++++++ .../read/DeprioritizedNearest.yml | 26 +++ .../read/DeprioritizedPrimary.json | 40 ++++ .../read/DeprioritizedPrimary.yml | 22 ++ .../read/DeprioritizedPrimaryPreferred.json | 63 ++++++ .../read/DeprioritizedPrimaryPreferred.yml | 26 +++ .../read/DeprioritizedSecondary.json | 63 ++++++ .../read/DeprioritizedSecondary.yml | 26 +++ .../read/DeprioritizedSecondaryPreferred.json | 63 ++++++ .../read/DeprioritizedSecondaryPreferred.yml | 26 +++ .../DeprioritizedAllPrimaryPreferred.json | 84 ++++++++ .../read/DeprioritizedAllPrimaryPreferred.yml | 34 +++ .../DeprioritizedAllSecondaryPreferred.json | 100 +++++++++ .../DeprioritizedAllSecondaryPreferred.yml | 36 ++++ .../read/DeprioritizedNearest.json | 78 +++++++ .../read/DeprioritizedNearest.yml | 33 +++ .../read/DeprioritizedPrimary.json | 65 ++++++ .../read/DeprioritizedPrimary.yml | 30 +++ .../read/DeprioritizedPrimaryPreferred.json | 84 ++++++++ .../read/DeprioritizedPrimaryPreferred.yml | 34 +++ .../read/DeprioritizedSecondary.json | 86 ++++++++ .../read/DeprioritizedSecondary.yml | 34 +++ .../read/DeprioritizedSecondaryPreferred.json | 78 +++++++ .../read/DeprioritizedSecondaryPreferred.yml | 33 +++ .../DeprioritizedSecondaryPreferred.json | 70 +++++++ .../write/DeprioritizedSecondaryPreferred.yml | 30 +++ .../Sharded/read/DeprioritizedNearest.json | 47 +++++ .../Sharded/read/DeprioritizedNearest.yml | 22 ++ .../Sharded/read/DeprioritizedPrimary.json | 43 ++++ .../Sharded/read/DeprioritizedPrimary.yml | 20 ++ .../read/DeprioritizedPrimaryPreferred.json | 48 +++++ .../read/DeprioritizedPrimaryPreferred.yml | 22 ++ .../Sharded/read/DeprioritizedSecondary.json | 48 +++++ .../Sharded/read/DeprioritizedSecondary.yml | 22 ++ .../read/DeprioritizedSecondaryPreferred.json | 48 +++++ .../read/DeprioritizedSecondaryPreferred.yml | 22 ++ .../Sharded/write/DeprioritizedNearest.json | 47 +++++ .../Sharded/write/DeprioritizedNearest.yml | 22 ++ .../Sharded/write/DeprioritizedPrimary.json | 43 ++++ .../Sharded/write/DeprioritizedPrimary.yml | 20 ++ .../write/DeprioritizedPrimaryPreferred.json | 48 +++++ .../write/DeprioritizedPrimaryPreferred.yml | 22 ++ .../Sharded/write/DeprioritizedSecondary.json | 48 +++++ .../Sharded/write/DeprioritizedSecondary.yml | 22 ++ .../DeprioritizedSecondaryPreferred.json | 48 +++++ .../write/DeprioritizedSecondaryPreferred.yml | 22 ++ .../Single/read/Deprioritized.json | 54 +++++ .../Single/read/Deprioritized.yml | 20 ++ .../Single/write/Deprioritized.json | 54 +++++ .../Single/write/Deprioritized.yml | 20 ++ test/tools/utils.ts | 7 +- .../server_selection_latency_window_utils.ts | 5 +- .../server_selection_logic_spec_utils.ts | 10 +- .../assorted/server_selection_spec_helper.js | 6 +- test/unit/error.test.ts | 14 +- test/unit/sdam/server_selection.test.ts | 195 ++++++++---------- test/unit/sdam/topology.test.ts | 8 +- 62 files changed, 2396 insertions(+), 167 deletions(-) create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.json create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.json create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.json create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.json create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.json create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.json create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.yml create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.json create mode 100644 test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.yml create mode 100644 test/spec/server-selection/server_selection/Single/read/Deprioritized.json create mode 100644 test/spec/server-selection/server_selection/Single/read/Deprioritized.yml create mode 100644 test/spec/server-selection/server_selection/Single/write/Deprioritized.json create mode 100644 test/spec/server-selection/server_selection/Single/write/Deprioritized.yml diff --git a/src/change_stream.ts b/src/change_stream.ts index f5b94bdd560..be4a7c0e361 100644 --- a/src/change_stream.ts +++ b/src/change_stream.ts @@ -1073,7 +1073,8 @@ export class ChangeStream< try { await topology.selectServer(this.cursor.readPreference, { operationName: 'reconnect topology in change stream', - timeoutContext: this.timeoutContext + timeoutContext: this.timeoutContext, + deprioritizedServers: [] }); this.cursor = this._createChangeStreamCursor(this.cursor.resumeOptions); } catch { diff --git a/src/mongo_client.ts b/src/mongo_client.ts index d93fba761af..3cfe0f8ab87 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -789,7 +789,7 @@ export class MongoClient extends TypedEventEmitter implements // to avoid the server selection timeout. const selector = readPreferenceServerSelector(ReadPreference.primaryPreferred); const serverDescriptions = Array.from(topologyDescription.servers.values()); - const servers = selector(topologyDescription, serverDescriptions); + const servers = selector(topologyDescription, serverDescriptions, []); if (servers.length !== 0) { const endSessions = Array.from(client.s.sessionPool.sessions, ({ id }) => id); if (endSessions.length !== 0) { diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index d833623d148..a615ce7908f 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -207,7 +207,8 @@ async function tryOperation ServerDescription[]; +function sdEquals(a: ServerDescription, b: ServerDescription) { + return a.address === b.address && a.equals(b); +} +function filterDeprioritized( + candidates: ServerDescription[], + deprioritized: ServerDescription[] +): ServerDescription[] { + const filtered = candidates.filter( + candidate => !deprioritized.some(serverDescription => sdEquals(serverDescription, candidate)) + ); + + return filtered.length ? filtered : candidates; +} + /** * Returns a server selector that selects for writable servers */ export function writableServerSelector(): ServerSelector { return function writableServer( topologyDescription: TopologyDescription, - servers: ServerDescription[] + servers: ServerDescription[], + deprioritized: ServerDescription[] ): ServerDescription[] { - return latencyWindowReducer( - topologyDescription, - servers.filter((s: ServerDescription) => s.isWritable) + const eligibleServers = filterDeprioritized( + servers.filter(({ isWritable }) => isWritable), + deprioritized ); + + return latencyWindowReducer(topologyDescription, eligibleServers); }; } @@ -39,8 +56,9 @@ export function writableServerSelector(): ServerSelector { */ export function sameServerSelector(description?: ServerDescription): ServerSelector { return function sameServerSelector( - topologyDescription: TopologyDescription, - servers: ServerDescription[] + _topologyDescription: TopologyDescription, + servers: ServerDescription[], + _deprioritized: ServerDescription[] ): ServerDescription[] { if (!description) return []; // Filter the servers to match the provided description only if @@ -218,10 +236,7 @@ function latencyWindowReducer( ); const high = low + topologyDescription.localThresholdMS; - return servers.reduce((result: ServerDescription[], server: ServerDescription) => { - if (server.roundTripTime <= high && server.roundTripTime >= low) result.push(server); - return result; - }, []); + return servers.filter(server => server.roundTripTime <= high && server.roundTripTime >= low); } // filters @@ -245,6 +260,18 @@ function loadBalancerFilter(server: ServerDescription): boolean { return server.type === ServerType.LoadBalancer; } +function isDeprioritizedFactory( + deprioritized: ServerDescription[] +): (server: ServerDescription) => boolean { + return server => + // if any deprioritized servers equal the server, here we are. + !deprioritized.some(deprioritizedServer => { + const result = sdEquals(deprioritizedServer, server); + // console.error(result); + return result; + }); +} + /** * Returns a function which selects servers based on a provided read preference * @@ -258,7 +285,7 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se return function readPreferenceServers( topologyDescription: TopologyDescription, servers: ServerDescription[], - deprioritized: ServerDescription[] = [] + deprioritized: ServerDescription[] ): ServerDescription[] { if (topologyDescription.type === TopologyType.LoadBalanced) { return servers.filter(loadBalancerFilter); @@ -273,38 +300,79 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se } if (topologyDescription.type === TopologyType.Sharded) { - const filtered = servers.filter(server => { - return !deprioritized.includes(server); - }); - const selectable = filtered.length > 0 ? filtered : deprioritized; + const selectable = filterDeprioritized(servers, deprioritized); return latencyWindowReducer(topologyDescription, selectable.filter(knownFilter)); } const mode = readPreference.mode; if (mode === ReadPreference.PRIMARY) { - return servers.filter(primaryFilter); + return filterDeprioritized(servers.filter(primaryFilter), deprioritized); } if (mode === ReadPreference.PRIMARY_PREFERRED) { - const result = servers.filter(primaryFilter); - if (result.length) { - return result; + const primary = servers.filter(primaryFilter); + + // If there is a primary and it is not deprioritized, use the primary. Otherwise, + // check for secondaries. + const eligiblePrimary = primary.filter(isDeprioritizedFactory(deprioritized)); + if (eligiblePrimary.length) { + return eligiblePrimary; } - } - const filter = mode === ReadPreference.NEAREST ? nearestFilter : secondaryFilter; - const selectedServers = latencyWindowReducer( - topologyDescription, - tagSetReducer( + const secondaries = tagSetReducer( readPreference, - maxStalenessReducer(readPreference, topologyDescription, servers.filter(filter)) - ) + maxStalenessReducer(readPreference, topologyDescription, servers.filter(secondaryFilter)) + ); + const deprioritizedSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); + + // console.error({ deprioritizedSecondaries, secondaries, deprioritized }); + if (deprioritizedSecondaries.length) + return latencyWindowReducer(topologyDescription, deprioritizedSecondaries); + + // if we make it here, we have no primaries or secondaries that not deprioritized. + // prefer the primary (which may not exist, if the topology has no primary). + // otherwise, return the secondaries (which also may not exist, but there is nothing else to check here). + return primary.length ? primary : latencyWindowReducer(topologyDescription, secondaries); + } + + // TODO: should we be applying the latency window to nearest servers? + if (mode === 'nearest') { + // if read preference is nearest + return latencyWindowReducer( + topologyDescription, + filterDeprioritized( + tagSetReducer( + readPreference, + maxStalenessReducer(readPreference, topologyDescription, servers.filter(nearestFilter)) + ), + deprioritized + ) + ); + } + + const filter = secondaryFilter; + + const secondaries = tagSetReducer( + readPreference, + maxStalenessReducer(readPreference, topologyDescription, servers.filter(filter)) ); + const eligibleSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); + + if (eligibleSecondaries.length) + return latencyWindowReducer(topologyDescription, eligibleSecondaries); + + // we have no eligible secondaries, try for a primary. + if (mode === ReadPreference.SECONDARY_PREFERRED) { + const primary = servers.filter(primaryFilter); + const eligiblePrimary = primary.filter(isDeprioritizedFactory(deprioritized)); + + if (eligiblePrimary.length) return eligiblePrimary; - if (mode === ReadPreference.SECONDARY_PREFERRED && selectedServers.length === 0) { - return servers.filter(primaryFilter); + // we have no eligible primary nor secondaries that have not been deprioritized + return secondaries.length ? latencyWindowReducer(topologyDescription, secondaries) : primary; } - return selectedServers; + // return all secondaries in the latency window. + return latencyWindowReducer(topologyDescription, secondaries); }; } diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index eba356b020e..c62f742feeb 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -105,7 +105,7 @@ export interface ServerSelectionRequest { cancelled: boolean; operationName: string; waitingLogged: boolean; - previousServer?: ServerDescription; + deprioritizedServers: ServerDescription[]; } /** @internal */ @@ -169,7 +169,7 @@ export interface SelectServerOptions { serverSelectionTimeoutMS?: number; session?: ClientSession; operationName: string; - previousServer?: ServerDescription; + deprioritizedServers: ServerDescription[]; /** * @internal * TODO(NODE-6496): Make this required by making ChangeStream use LegacyTimeoutContext @@ -455,7 +455,8 @@ export class Topology extends TypedEventEmitter { const selectServerOptions = { operationName: 'handshake', ...options, - timeoutContext + timeoutContext, + deprioritizedServers: [] }; try { @@ -605,7 +606,7 @@ export class Topology extends TypedEventEmitter { startTime: processTimeMS(), operationName: options.operationName, waitingLogged: false, - previousServer: options.previousServer + deprioritizedServers: options.deprioritizedServers }; const abortListener = addAbortListener(options.signal, function () { @@ -957,13 +958,9 @@ function processWaitQueue(topology: Topology) { let selectedDescriptions; try { const serverSelector = waitQueueMember.serverSelector; - const previousServer = waitQueueMember.previousServer; + const deprioritizedServers = waitQueueMember.deprioritizedServers; selectedDescriptions = serverSelector - ? serverSelector( - topology.description, - serverDescriptions, - previousServer ? [previousServer] : [] - ) + ? serverSelector(topology.description, serverDescriptions, deprioritizedServers) : serverDescriptions; } catch (selectorError) { if ( diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.json b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.json new file mode 100644 index 00000000000..464e542c542 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.json @@ -0,0 +1,63 @@ +{ + "topology_description": { + "type": "ReplicaSetNoPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Nearest", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} + diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.yml b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.yml new file mode 100644 index 00000000000..9297b98a32f --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedNearest.yml @@ -0,0 +1,26 @@ +topology_description: + type: ReplicaSetNoPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc +operation: read +read_preference: + mode: Nearest + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.json b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.json new file mode 100644 index 00000000000..4726045de80 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.json @@ -0,0 +1,40 @@ +{ + "topology_description": { + "type": "ReplicaSetNoPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Primary" + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [], + "in_latency_window": [] +} + diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.yml b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.yml new file mode 100644 index 00000000000..6d29358f3c2 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimary.yml @@ -0,0 +1,22 @@ +topology_description: + type: ReplicaSetNoPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc +operation: read +read_preference: + mode: Primary +deprioritized_servers: +- *1 +suitable_servers: [] +in_latency_window: [] diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.json new file mode 100644 index 00000000000..ef9444e5952 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.json @@ -0,0 +1,63 @@ +{ + "topology_description": { + "type": "ReplicaSetNoPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "PrimaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} + diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.yml new file mode 100644 index 00000000000..cb08766a3d0 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedPrimaryPreferred.yml @@ -0,0 +1,26 @@ +topology_description: + type: ReplicaSetNoPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc +operation: read +read_preference: + mode: PrimaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.json b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.json new file mode 100644 index 00000000000..fbd5456ad6d --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.json @@ -0,0 +1,63 @@ +{ + "topology_description": { + "type": "ReplicaSetNoPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Secondary", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} + diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.yml b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.yml new file mode 100644 index 00000000000..08ca00c0ab0 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondary.yml @@ -0,0 +1,26 @@ +topology_description: + type: ReplicaSetNoPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc +operation: read +read_preference: + mode: Secondary + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.json new file mode 100644 index 00000000000..d8d92261e1b --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.json @@ -0,0 +1,63 @@ +{ + "topology_description": { + "type": "ReplicaSetNoPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} + diff --git a/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.yml new file mode 100644 index 00000000000..0ae92459ae6 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetNoPrimary/read/DeprioritizedSecondaryPreferred.yml @@ -0,0 +1,26 @@ +topology_description: + type: ReplicaSetNoPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc +operation: read +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.json new file mode 100644 index 00000000000..095537ba1a5 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.json @@ -0,0 +1,84 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "PrimaryPreferred", + "tag_sets": [ + {} + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.yml new file mode 100644 index 00000000000..f63605889ef --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllPrimaryPreferred.yml @@ -0,0 +1,34 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 5 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: PrimaryPreferred + tag_sets: + - {} +deprioritized_servers: +- *1 +- *2 +- *3 +suitable_servers: +- *3 +in_latency_window: +- *3 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.json new file mode 100644 index 00000000000..b29ba2bc800 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.json @@ -0,0 +1,100 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + {} + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.yml new file mode 100644 index 00000000000..37e9e055ca2 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedAllSecondaryPreferred.yml @@ -0,0 +1,36 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 5 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: SecondaryPreferred + tag_sets: + - {} +deprioritized_servers: +- *1 +- *2 +- *3 +suitable_servers: +- *1 +- *2 +in_latency_window: +- *1 +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.json new file mode 100644 index 00000000000..5b9d0fa538d --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.json @@ -0,0 +1,78 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Nearest", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.yml new file mode 100644 index 00000000000..3dcb9bffdc5 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedNearest.yml @@ -0,0 +1,33 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 26 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: Nearest + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *3 +- *2 +in_latency_window: +- *3 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.json new file mode 100644 index 00000000000..a1ef5b200fe --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.json @@ -0,0 +1,65 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Primary" + }, + "deprioritized_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.yml new file mode 100644 index 00000000000..a4c09ba3d49 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimary.yml @@ -0,0 +1,30 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 5 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: Primary +deprioritized_servers: +- *3 +suitable_servers: +- *3 +in_latency_window: +- *3 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.json new file mode 100644 index 00000000000..367d19e66d1 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.json @@ -0,0 +1,84 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "PrimaryPreferred", + "tag_sets": [ + {} + ] + }, + "deprioritized_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.yml new file mode 100644 index 00000000000..83551a51bbf --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedPrimaryPreferred.yml @@ -0,0 +1,34 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 5 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: PrimaryPreferred + tag_sets: + - {} +deprioritized_servers: +- *3 +suitable_servers: +- *1 +- *2 +in_latency_window: +- *1 +- *2 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.json new file mode 100644 index 00000000000..32080807a1a --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.json @@ -0,0 +1,86 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Secondary", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.yml new file mode 100644 index 00000000000..cfcedf3a579 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondary.yml @@ -0,0 +1,34 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 26 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: Secondary + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +- *2 +suitable_servers: +- *1 +- *2 +in_latency_window: +- *1 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.json new file mode 100644 index 00000000000..1fd6c654f06 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.json @@ -0,0 +1,78 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.yml new file mode 100644 index 00000000000..1db29405f95 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/read/DeprioritizedSecondaryPreferred.yml @@ -0,0 +1,33 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - &1 + address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - &2 + address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc + - &3 + address: a:27017 + avg_rtt_ms: 5 + type: RSPrimary + tags: + data_center: nyc +operation: read +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +- *2 +suitable_servers: +- *3 +in_latency_window: +- *3 diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.json b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.json new file mode 100644 index 00000000000..0f3642aa209 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.json @@ -0,0 +1,70 @@ +{ + "topology_description": { + "type": "ReplicaSetWithPrimary", + "servers": [ + { + "address": "b:27017", + "avg_rtt_ms": 5, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "c:27017", + "avg_rtt_ms": 100, + "type": "RSSecondary", + "tags": { + "data_center": "nyc" + } + }, + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 26, + "type": "RSPrimary", + "tags": { + "data_center": "nyc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.yml b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.yml new file mode 100644 index 00000000000..cb0d7acbb33 --- /dev/null +++ b/test/spec/server-selection/server_selection/ReplicaSetWithPrimary/write/DeprioritizedSecondaryPreferred.yml @@ -0,0 +1,30 @@ +topology_description: + type: ReplicaSetWithPrimary + servers: + - address: b:27017 + avg_rtt_ms: 5 + type: RSSecondary + tags: + data_center: nyc + - address: c:27017 + avg_rtt_ms: 100 + type: RSSecondary + tags: + data_center: nyc + - &1 + address: a:27017 + avg_rtt_ms: 26 + type: RSPrimary + tags: + data_center: nyc +operation: write +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *3 +in_latency_window: +- *3 diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.json b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.json new file mode 100644 index 00000000000..1aa730cd21d --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.json @@ -0,0 +1,47 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Nearest", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ] +} diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.yml b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.yml new file mode 100644 index 00000000000..27fd8fc6934 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedNearest.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 10 + type: Mongos +operation: read +read_preference: + mode: Nearest + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.json b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.json new file mode 100644 index 00000000000..0017e28a467 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.json @@ -0,0 +1,43 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Primary" + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.yml b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.yml new file mode 100644 index 00000000000..a7bfee07d82 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimary.yml @@ -0,0 +1,20 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: read +read_preference: + mode: Primary +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.json b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.json new file mode 100644 index 00000000000..7540492b4d1 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "PrimaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.yml b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.yml new file mode 100644 index 00000000000..3452acdeff9 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedPrimaryPreferred.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: read +read_preference: + mode: PrimaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.json b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.json new file mode 100644 index 00000000000..a476695d06b --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "Secondary", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.yml b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.yml new file mode 100644 index 00000000000..5db76672384 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondary.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: read +read_preference: + mode: Secondary + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.json b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.json new file mode 100644 index 00000000000..effca47d2df --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.yml b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.yml new file mode 100644 index 00000000000..a07e44b55ff --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/read/DeprioritizedSecondaryPreferred.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: read +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.json b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.json new file mode 100644 index 00000000000..5cc2cc5477d --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.json @@ -0,0 +1,47 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "Nearest", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 10, + "type": "Mongos" + } + ] +} diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.yml b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.yml new file mode 100644 index 00000000000..af8ca190d6d --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedNearest.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 10 + type: Mongos +operation: write +read_preference: + mode: Nearest + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.json b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.json new file mode 100644 index 00000000000..faae97e51f8 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.json @@ -0,0 +1,43 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "Primary" + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.yml b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.yml new file mode 100644 index 00000000000..7fc405c3f2f --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimary.yml @@ -0,0 +1,20 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: write +read_preference: + mode: Primary +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.json b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.json new file mode 100644 index 00000000000..37546302462 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "PrimaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.yml b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.yml new file mode 100644 index 00000000000..cf2359cc449 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedPrimaryPreferred.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: write +read_preference: + mode: PrimaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.json b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.json new file mode 100644 index 00000000000..905c8df90a6 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "Secondary", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.yml b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.yml new file mode 100644 index 00000000000..06888b0bb7a --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondary.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: write +read_preference: + mode: Secondary + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.json b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.json new file mode 100644 index 00000000000..47e55ca20de --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.json @@ -0,0 +1,48 @@ +{ + "topology_description": { + "type": "Sharded", + "servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + }, + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "g:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "suitable_servers": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ], + "in_latency_window": [ + { + "address": "h:27017", + "avg_rtt_ms": 5, + "type": "Mongos" + } + ] +} + diff --git a/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.yml b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.yml new file mode 100644 index 00000000000..8c1abf2cec0 --- /dev/null +++ b/test/spec/server-selection/server_selection/Sharded/write/DeprioritizedSecondaryPreferred.yml @@ -0,0 +1,22 @@ +topology_description: + type: Sharded + servers: + - &1 + address: g:27017 + avg_rtt_ms: 5 + type: Mongos + - &2 + address: h:27017 + avg_rtt_ms: 5 + type: Mongos +operation: write +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *2 +in_latency_window: +- *2 diff --git a/test/spec/server-selection/server_selection/Single/read/Deprioritized.json b/test/spec/server-selection/server_selection/Single/read/Deprioritized.json new file mode 100644 index 00000000000..c76fc6c7719 --- /dev/null +++ b/test/spec/server-selection/server_selection/Single/read/Deprioritized.json @@ -0,0 +1,54 @@ +{ + "topology_description": { + "type": "Single", + "servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ] + }, + "operation": "read", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/Single/read/Deprioritized.yml b/test/spec/server-selection/server_selection/Single/read/Deprioritized.yml new file mode 100644 index 00000000000..463a7a55354 --- /dev/null +++ b/test/spec/server-selection/server_selection/Single/read/Deprioritized.yml @@ -0,0 +1,20 @@ +topology_description: + type: Single + servers: + - &1 + address: a:27017 + avg_rtt_ms: 5 + type: Standalone + tags: + data_center: dc +operation: read +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *1 +in_latency_window: +- *1 diff --git a/test/spec/server-selection/server_selection/Single/write/Deprioritized.json b/test/spec/server-selection/server_selection/Single/write/Deprioritized.json new file mode 100644 index 00000000000..099076f2da8 --- /dev/null +++ b/test/spec/server-selection/server_selection/Single/write/Deprioritized.json @@ -0,0 +1,54 @@ +{ + "topology_description": { + "type": "Single", + "servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ] + }, + "operation": "write", + "read_preference": { + "mode": "SecondaryPreferred", + "tag_sets": [ + { + "data_center": "nyc" + } + ] + }, + "deprioritized_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ], + "suitable_servers": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ], + "in_latency_window": [ + { + "address": "a:27017", + "avg_rtt_ms": 5, + "type": "Standalone", + "tags": { + "data_center": "dc" + } + } + ] +} diff --git a/test/spec/server-selection/server_selection/Single/write/Deprioritized.yml b/test/spec/server-selection/server_selection/Single/write/Deprioritized.yml new file mode 100644 index 00000000000..08780151c97 --- /dev/null +++ b/test/spec/server-selection/server_selection/Single/write/Deprioritized.yml @@ -0,0 +1,20 @@ +topology_description: + type: Single + servers: + - &1 + address: a:27017 + avg_rtt_ms: 5 + type: Standalone + tags: + data_center: dc +operation: write +read_preference: + mode: SecondaryPreferred + tag_sets: + - data_center: nyc +deprioritized_servers: +- *1 +suitable_servers: +- *1 +in_latency_window: +- *1 diff --git a/test/tools/utils.ts b/test/tools/utils.ts index d092fe2eca6..47d92411c88 100644 --- a/test/tools/utils.ts +++ b/test/tools/utils.ts @@ -285,7 +285,12 @@ export function topologyWithPlaceholderClient( options: Partial ): Topology { return new Topology( - new MongoClient('mongodb://iLoveJavaScript'), + new MongoClient( + 'mongodb://iLoveJavaScript', + options.serverSelectionTimeoutMS + ? { serverSelectionTimeoutMS: options.serverSelectionTimeoutMS } + : {} + ), seeds, options as TopologyOptions ); diff --git a/test/unit/assorted/server_selection_latency_window_utils.ts b/test/unit/assorted/server_selection_latency_window_utils.ts index da4e8463569..3ae6f0659f0 100644 --- a/test/unit/assorted/server_selection_latency_window_utils.ts +++ b/test/unit/assorted/server_selection_latency_window_utils.ts @@ -134,7 +134,10 @@ export async function runServerSelectionLatencyWindowTest(test: ServerSelectionL const selectedServers: Server[] = []; for (let i = 0; i < test.iterations; ++i) { - const server: Server = await topology.selectServer(ReadPreference.NEAREST, {}); + const server: Server = await topology.selectServer(ReadPreference.NEAREST, { + deprioritizedServers: [], + operationName: 'test operation' + }); selectedServers.push(server); } diff --git a/test/unit/assorted/server_selection_logic_spec_utils.ts b/test/unit/assorted/server_selection_logic_spec_utils.ts index 62a31fba189..4b8a159df68 100644 --- a/test/unit/assorted/server_selection_logic_spec_utils.ts +++ b/test/unit/assorted/server_selection_logic_spec_utils.ts @@ -12,6 +12,7 @@ import { type ServerType, type TopologyType } from '../../../src/sdam/common'; import { type ServerDescription, type TagSet } from '../../../src/sdam/server_description'; import { readPreferenceServerSelector, + type ServerSelector, writableServerSelector } from '../../../src/sdam/server_selection'; import { TopologyDescription } from '../../../src/sdam/topology_description'; @@ -41,6 +42,7 @@ interface ServerSelectionLogicTest { */ suitable_servers: never; in_latency_window: ServerSelectionLogicTestServer[]; + deprioritized_servers?: ServerSelectionLogicTestServer[]; } function readPreferenceFromDefinition(definition) { @@ -96,8 +98,11 @@ export function runServerSelectionLogicTest(testDefinition: ServerSelectionLogic const expectedServers = serverDescriptionsToMap( testDefinition.in_latency_window.map(s => serverDescriptionFromDefinition(s)) ); + const deprioritized = + testDefinition.deprioritized_servers?.map(s => serverDescriptionFromDefinition(s, allHosts)) ?? + []; - let selector; + let selector: ServerSelector; if (testDefinition.operation === 'write') { selector = writableServerSelector(); } else if (testDefinition.operation === 'read' || testDefinition.read_preference) { @@ -107,10 +112,11 @@ export function runServerSelectionLogicTest(testDefinition: ServerSelectionLogic expect.fail('test operation was neither read nor write, and no read preference was provided.'); } - const result = selector(topologyDescription, serversInTopology); + const result = selector(topologyDescription, serversInTopology, deprioritized); expect(result.length).to.equal(expectedServers.size); + // console.error({ result, expectedServers }); for (const server of result) { const expectedServer = expectedServers.get(server.address); expect(expectedServer).to.exist; diff --git a/test/unit/assorted/server_selection_spec_helper.js b/test/unit/assorted/server_selection_spec_helper.js index a110ae3d117..9bbd0e0705c 100644 --- a/test/unit/assorted/server_selection_spec_helper.js +++ b/test/unit/assorted/server_selection_spec_helper.js @@ -137,7 +137,11 @@ export async function executeServerSelectionTest(testDefinition) { // default to serverSelectionTimeoutMS of `100` for unit tests try { - const server = await topology.selectServer(selector, { serverSelectionTimeoutMS: 50 }); + const server = await topology.selectServer(selector, { + serverSelectionTimeoutMS: 50, + deprioritizedServers: [], + operationName: 'test operation' + }); if (testDefinition.error) throw new Error('Expected an error, but found none!'); if (expectedServers.length === 0 && server !== null) { diff --git a/test/unit/error.test.ts b/test/unit/error.test.ts index 34428b0666f..f0d1ca06c94 100644 --- a/test/unit/error.test.ts +++ b/test/unit/error.test.ts @@ -383,7 +383,13 @@ describe('MongoErrors', () => { ); return replSet .connect() - .then(topology => topology.selectServer('primary', { timeoutContext })) + .then(topology => + topology.selectServer('primary', { + timeoutContext, + deprioritizedServers: [], + operationName: 'test operation' + }) + ) .then(server => server.command(op, timeoutContext)) .then( () => expect.fail('expected command to fail'), @@ -426,7 +432,11 @@ describe('MongoErrors', () => { Object.assign({}, RAW_USER_WRITE_CONCERN_CMD), {} ); - const server = await topology.selectServer('primary', { timeoutContext }); + const server = await topology.selectServer('primary', { + timeoutContext, + deprioritizedServers: [], + operationName: 'test operation' + }); try { await server.command(op, timeoutContext); } catch (err) { diff --git a/test/unit/sdam/server_selection.test.ts b/test/unit/sdam/server_selection.test.ts index 4c0a45985de..4b179d16cb6 100644 --- a/test/unit/sdam/server_selection.test.ts +++ b/test/unit/sdam/server_selection.test.ts @@ -50,93 +50,6 @@ describe('server selection', function () { ok: 0 }); - describe('#readPreferenceServerSelector', function () { - let selector; - let servers; - - context('when the topology is sharded', function () { - const topologyDescription = new TopologyDescription( - TopologyType.Sharded, - new Map(), - 'test', - MIN_SECONDARY_WRITE_WIRE_VERSION, - new ObjectId(), - MIN_SECONDARY_WRITE_WIRE_VERSION - ); - - beforeEach(function () { - selector = readPreferenceServerSelector(ReadPreference.secondaryPreferred); - }); - - context('when there are deprioritized servers', function () { - context('when there are other servers', function () { - beforeEach(function () { - servers = selector(topologyDescription, [mongos], [mongosTwo]); - }); - - it('returns a server from the other servers', function () { - expect(servers).to.deep.equal([mongos]); - }); - }); - - context('when there are no other servers', function () { - beforeEach(function () { - servers = selector(topologyDescription, [], [mongosTwo]); - }); - - it('returns a server from the deprioritized servers', function () { - expect(servers).to.deep.equal([mongosTwo]); - }); - }); - }); - - context('when there are no deprioritised servers', function () { - beforeEach(function () { - servers = selector(topologyDescription, [mongos]); - }); - - it('returns a server from the other servers', function () { - expect(servers).to.deep.equal([mongos]); - }); - }); - }); - - context('when the topology is not sharded', function () { - const topologyDescription = new TopologyDescription( - TopologyType.ReplicaSetWithPrimary, - new Map(), - 'test', - MIN_SECONDARY_WRITE_WIRE_VERSION, - new ObjectId(), - MIN_SECONDARY_WRITE_WIRE_VERSION - ); - - beforeEach(function () { - selector = readPreferenceServerSelector(ReadPreference.secondary); - }); - - context('when there are deprioritized servers', function () { - beforeEach(function () { - servers = selector(topologyDescription, [secondaryTwo], [secondary]); - }); - - it('selects from all server lists', function () { - expect(servers).to.contain.oneOf([secondary, secondaryTwo]); - }); - }); - - context('when there are no deprioritised servers', function () { - beforeEach(function () { - servers = selector(topologyDescription, [secondary], []); - }); - - it('selects from all non-deprioritised servers', function () { - expect(servers).to.deep.equal([secondary]); - }); - }); - }); - }); - describe('#sameServerSelector', function () { const topologyDescription = sinon.stub(); const serverDescriptions = new Map(); @@ -211,7 +124,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('uses the provided read preference', function () { expect(servers).to.deep.equal([secondary]); @@ -220,7 +137,11 @@ describe('server selection', function () { context('when a read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a primary', function () { expect(servers).to.deep.equal([primary]); @@ -243,7 +164,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION - 1, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a primary', function () { expect(servers).to.deep.equal([primary]); @@ -252,7 +177,11 @@ describe('server selection', function () { context('when read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a primary', function () { expect(servers).to.deep.equal([primary]); @@ -270,7 +199,7 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(undefined, ReadPreference.secondary); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); it('selects a primary', function () { expect(servers).to.deep.equal([primary]); @@ -297,7 +226,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -306,7 +239,11 @@ describe('server selection', function () { context('when a read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -329,7 +266,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION - 1, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -338,7 +279,11 @@ describe('server selection', function () { context('when read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -356,7 +301,7 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -383,7 +328,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -392,7 +341,11 @@ describe('server selection', function () { context('when a read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -415,7 +368,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION - 1, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -424,7 +381,11 @@ describe('server selection', function () { context('when read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -442,7 +403,7 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -469,7 +430,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -478,7 +443,11 @@ describe('server selection', function () { context('when a read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -501,7 +470,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION - 1, ReadPreference.secondary ); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -510,7 +483,11 @@ describe('server selection', function () { context('when read preference is not provided', function () { const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + [] + ); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -528,7 +505,7 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -581,7 +558,7 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); expect(servers).to.have.lengthOf(2); const selectedAddresses = new Set(servers.map(({ address }) => address)); expect(selectedAddresses.has(serverDescription1.address)).to.be.true; @@ -600,7 +577,7 @@ describe('server selection', function () { { localThresholdMS: 5 } ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values())); + const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); expect(servers).to.have.lengthOf(1); const selectedAddresses = new Set(servers.map(({ address }) => address)); expect(selectedAddresses.has(serverDescription1.address)).to.be.true; diff --git a/test/unit/sdam/topology.test.ts b/test/unit/sdam/topology.test.ts index cf0511a8437..a148aa953a9 100644 --- a/test/unit/sdam/topology.test.ts +++ b/test/unit/sdam/topology.test.ts @@ -446,11 +446,9 @@ describe('Topology (unit)', function () { describe('selectServer()', function () { it('should schedule monitoring if no suitable server is found', async function () { - const topology = topologyWithPlaceholderClient( - 'someserver:27019', - {}, - { serverSelectionTimeoutMS: 10 } - ); + const topology = topologyWithPlaceholderClient('someserver:27019', { + serverSelectionTimeoutMS: 10 + }); const requestCheck = sinon.stub(Server.prototype, 'requestCheck'); sinon.stub(Server.prototype, 'connect').callsFake(function () { From 67081d4557de344821f997afeced85a862bcb35a Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 10 Dec 2025 09:22:00 -0700 Subject: [PATCH 3/4] POC - only track addresses --- src/change_stream.ts | 3 +- src/index.ts | 2 +- src/mongo_client.ts | 4 +- src/operations/execute_operation.ts | 8 +- src/sdam/server_selection.ts | 42 ++++++---- src/sdam/topology.ts | 14 +++- test/unit/assorted/imports.test.ts | 2 +- .../server_selection_latency_window_utils.ts | 3 +- .../server_selection_logic_spec_utils.ts | 7 +- .../assorted/server_selection_spec_helper.js | 2 +- test/unit/error.test.ts | 5 +- test/unit/sdam/server_selection.test.ts | 79 +++++++++++-------- 12 files changed, 103 insertions(+), 68 deletions(-) diff --git a/src/change_stream.ts b/src/change_stream.ts index be4a7c0e361..22330e8595e 100644 --- a/src/change_stream.ts +++ b/src/change_stream.ts @@ -18,6 +18,7 @@ import { MongoClient } from './mongo_client'; import { type InferIdType, TypedEventEmitter } from './mongo_types'; import type { AggregateOptions } from './operations/aggregate'; import type { OperationParent } from './operations/command'; +import { DeprioritizedServers } from './sdam/server_selection'; import type { ServerSessionId } from './sessions'; import { CSOTTimeoutContext, type TimeoutContext } from './timeout'; import { type AnyOptions, getTopology, type MongoDBNamespace, squashError } from './utils'; @@ -1074,7 +1075,7 @@ export class ChangeStream< await topology.selectServer(this.cursor.readPreference, { operationName: 'reconnect topology in change stream', timeoutContext: this.timeoutContext, - deprioritizedServers: [] + deprioritizedServers: new DeprioritizedServers() }); this.cursor = this._createChangeStreamCursor(this.cursor.resumeOptions); } catch { diff --git a/src/index.ts b/src/index.ts index 75acf17c68b..8f5c4cfa60e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -588,7 +588,7 @@ export type { TagSet, TopologyVersion } from './sdam/server_description'; -export type { ServerSelector } from './sdam/server_selection'; +export type { DeprioritizedServers, ServerSelector } from './sdam/server_selection'; export type { SrvPoller, SrvPollerEvents, SrvPollerOptions } from './sdam/srv_polling'; export type { ConnectOptions, diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 3cfe0f8ab87..970f0f88061 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -48,7 +48,7 @@ import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_conc import { ReadPreference, type ReadPreferenceMode } from './read_preference'; import type { ServerMonitoringMode } from './sdam/monitor'; import type { TagSet } from './sdam/server_description'; -import { readPreferenceServerSelector } from './sdam/server_selection'; +import { DeprioritizedServers, readPreferenceServerSelector } from './sdam/server_selection'; import type { SrvPoller } from './sdam/srv_polling'; import { Topology, type TopologyEvents } from './sdam/topology'; import { ClientSession, type ClientSessionOptions, ServerSessionPool } from './sessions'; @@ -789,7 +789,7 @@ export class MongoClient extends TypedEventEmitter implements // to avoid the server selection timeout. const selector = readPreferenceServerSelector(ReadPreference.primaryPreferred); const serverDescriptions = Array.from(topologyDescription.servers.values()); - const servers = selector(topologyDescription, serverDescriptions, []); + const servers = selector(topologyDescription, serverDescriptions, new DeprioritizedServers()); if (servers.length !== 0) { const endSessions = Array.from(client.s.sessionPool.sessions, ({ id }) => id); if (endSessions.length !== 0) { diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index a615ce7908f..b6ddbba2b66 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -17,8 +17,8 @@ import { } from '../error'; import type { MongoClient } from '../mongo_client'; import { ReadPreference } from '../read_preference'; -import type { ServerDescription } from '../sdam/server_description'; import { + DeprioritizedServers, sameServerSelector, secondaryWritableServerSelector, type ServerSelector @@ -208,7 +208,7 @@ async function tryOperation ServerDescription[]; -function sdEquals(a: ServerDescription, b: ServerDescription) { - return a.address === b.address && a.equals(b); +/** @internal */ +export class DeprioritizedServers { + private deprioritized: Set = new Set(); + + constructor(descriptions?: Iterable) { + for (const description of descriptions ?? []) { + this.add(description); + } + } + + add({ address }: ServerDescription) { + this.deprioritized.add(address); + } + + has({ address }: ServerDescription): boolean { + return this.deprioritized.has(address); + } } + function filterDeprioritized( candidates: ServerDescription[], - deprioritized: ServerDescription[] + deprioritized: DeprioritizedServers ): ServerDescription[] { - const filtered = candidates.filter( - candidate => !deprioritized.some(serverDescription => sdEquals(serverDescription, candidate)) - ); + const filtered = candidates.filter(candidate => !deprioritized.has(candidate)); return filtered.length ? filtered : candidates; } @@ -39,7 +53,7 @@ export function writableServerSelector(): ServerSelector { return function writableServer( topologyDescription: TopologyDescription, servers: ServerDescription[], - deprioritized: ServerDescription[] + deprioritized: DeprioritizedServers ): ServerDescription[] { const eligibleServers = filterDeprioritized( servers.filter(({ isWritable }) => isWritable), @@ -58,7 +72,7 @@ export function sameServerSelector(description?: ServerDescription): ServerSelec return function sameServerSelector( _topologyDescription: TopologyDescription, servers: ServerDescription[], - _deprioritized: ServerDescription[] + _deprioritized: DeprioritizedServers ): ServerDescription[] { if (!description) return []; // Filter the servers to match the provided description only if @@ -261,15 +275,11 @@ function loadBalancerFilter(server: ServerDescription): boolean { } function isDeprioritizedFactory( - deprioritized: ServerDescription[] + deprioritized: DeprioritizedServers ): (server: ServerDescription) => boolean { return server => // if any deprioritized servers equal the server, here we are. - !deprioritized.some(deprioritizedServer => { - const result = sdEquals(deprioritizedServer, server); - // console.error(result); - return result; - }); + !deprioritized.has(server); } /** @@ -285,7 +295,7 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se return function readPreferenceServers( topologyDescription: TopologyDescription, servers: ServerDescription[], - deprioritized: ServerDescription[] + deprioritized: DeprioritizedServers ): ServerDescription[] { if (topologyDescription.type === TopologyType.LoadBalanced) { return servers.filter(loadBalancerFilter); diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index c62f742feeb..8cbe8357dce 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -70,7 +70,11 @@ import { import type { ServerMonitoringMode } from './monitor'; import { Server, type ServerEvents, type ServerOptions } from './server'; import { compareTopologyVersion, ServerDescription } from './server_description'; -import { readPreferenceServerSelector, type ServerSelector } from './server_selection'; +import { + DeprioritizedServers, + readPreferenceServerSelector, + type ServerSelector +} from './server_selection'; import { ServerSelectionFailedEvent, ServerSelectionStartedEvent, @@ -105,7 +109,7 @@ export interface ServerSelectionRequest { cancelled: boolean; operationName: string; waitingLogged: boolean; - deprioritizedServers: ServerDescription[]; + deprioritizedServers: DeprioritizedServers; } /** @internal */ @@ -169,7 +173,9 @@ export interface SelectServerOptions { serverSelectionTimeoutMS?: number; session?: ClientSession; operationName: string; - deprioritizedServers: ServerDescription[]; + + /** @internal */ + deprioritizedServers: DeprioritizedServers; /** * @internal * TODO(NODE-6496): Make this required by making ChangeStream use LegacyTimeoutContext @@ -456,7 +462,7 @@ export class Topology extends TypedEventEmitter { operationName: 'handshake', ...options, timeoutContext, - deprioritizedServers: [] + deprioritizedServers: new DeprioritizedServers() }; try { diff --git a/test/unit/assorted/imports.test.ts b/test/unit/assorted/imports.test.ts index 1e66b70eb7d..d5117874f5a 100644 --- a/test/unit/assorted/imports.test.ts +++ b/test/unit/assorted/imports.test.ts @@ -15,7 +15,7 @@ function* walk(root) { } } -describe('importing mongodb driver', () => { +describe.skip('importing mongodb driver', () => { const sourceFiles = walk(path.resolve(__dirname, '../../../src')); for (const sourceFile of sourceFiles) { diff --git a/test/unit/assorted/server_selection_latency_window_utils.ts b/test/unit/assorted/server_selection_latency_window_utils.ts index 3ae6f0659f0..2b6a38392f9 100644 --- a/test/unit/assorted/server_selection_latency_window_utils.ts +++ b/test/unit/assorted/server_selection_latency_window_utils.ts @@ -6,6 +6,7 @@ import { join } from 'path'; import { ReadPreference } from '../../../src/read_preference'; import { type ServerType, STATE_CONNECTED, type TopologyType } from '../../../src/sdam/common'; import { type Server } from '../../../src/sdam/server'; +import { DeprioritizedServers } from '../../../src/sdam/server_selection'; import { type Topology } from '../../../src/sdam/topology'; import { topologyWithPlaceholderClient } from '../../tools/utils'; import { serverDescriptionFromDefinition } from './server_selection_spec_helper'; @@ -135,7 +136,7 @@ export async function runServerSelectionLatencyWindowTest(test: ServerSelectionL for (let i = 0; i < test.iterations; ++i) { const server: Server = await topology.selectServer(ReadPreference.NEAREST, { - deprioritizedServers: [], + deprioritizedServers: new DeprioritizedServers(), operationName: 'test operation' }); selectedServers.push(server); diff --git a/test/unit/assorted/server_selection_logic_spec_utils.ts b/test/unit/assorted/server_selection_logic_spec_utils.ts index 4b8a159df68..685da3a1102 100644 --- a/test/unit/assorted/server_selection_logic_spec_utils.ts +++ b/test/unit/assorted/server_selection_logic_spec_utils.ts @@ -11,6 +11,7 @@ import { import { type ServerType, type TopologyType } from '../../../src/sdam/common'; import { type ServerDescription, type TagSet } from '../../../src/sdam/server_description'; import { + DeprioritizedServers, readPreferenceServerSelector, type ServerSelector, writableServerSelector @@ -98,9 +99,9 @@ export function runServerSelectionLogicTest(testDefinition: ServerSelectionLogic const expectedServers = serverDescriptionsToMap( testDefinition.in_latency_window.map(s => serverDescriptionFromDefinition(s)) ); - const deprioritized = - testDefinition.deprioritized_servers?.map(s => serverDescriptionFromDefinition(s, allHosts)) ?? - []; + const deprioritized = new DeprioritizedServers( + testDefinition.deprioritized_servers?.map(s => serverDescriptionFromDefinition(s, allHosts)) + ); let selector: ServerSelector; if (testDefinition.operation === 'write') { diff --git a/test/unit/assorted/server_selection_spec_helper.js b/test/unit/assorted/server_selection_spec_helper.js index 9bbd0e0705c..ea294df6d57 100644 --- a/test/unit/assorted/server_selection_spec_helper.js +++ b/test/unit/assorted/server_selection_spec_helper.js @@ -139,7 +139,7 @@ export async function executeServerSelectionTest(testDefinition) { try { const server = await topology.selectServer(selector, { serverSelectionTimeoutMS: 50, - deprioritizedServers: [], + deprioritizedServers: new ServerSelectors.DeprioritizedServers(), operationName: 'test operation' }); diff --git a/test/unit/error.test.ts b/test/unit/error.test.ts index f0d1ca06c94..c860d142775 100644 --- a/test/unit/error.test.ts +++ b/test/unit/error.test.ts @@ -34,6 +34,7 @@ import { type TopologyOptions } from '../../src/index'; import { RunCommandOperation } from '../../src/operations/run_command'; +import { DeprioritizedServers } from '../../src/sdam/server_selection'; import { type Topology } from '../../src/sdam/topology'; import { TimeoutContext } from '../../src/timeout'; import { isHello, ns, setDifference } from '../../src/utils'; @@ -386,7 +387,7 @@ describe('MongoErrors', () => { .then(topology => topology.selectServer('primary', { timeoutContext, - deprioritizedServers: [], + deprioritizedServers: new DeprioritizedServers(), operationName: 'test operation' }) ) @@ -434,7 +435,7 @@ describe('MongoErrors', () => { ); const server = await topology.selectServer('primary', { timeoutContext, - deprioritizedServers: [], + deprioritizedServers: new DeprioritizedServers(), operationName: 'test operation' }); try { diff --git a/test/unit/sdam/server_selection.test.ts b/test/unit/sdam/server_selection.test.ts index 4b179d16cb6..f911ae34186 100644 --- a/test/unit/sdam/server_selection.test.ts +++ b/test/unit/sdam/server_selection.test.ts @@ -7,8 +7,8 @@ import { ReadPreference } from '../../../src/read_preference'; import { TopologyType } from '../../../src/sdam/common'; import { ServerDescription } from '../../../src/sdam/server_description'; import { + DeprioritizedServers, MIN_SECONDARY_WRITE_WIRE_VERSION, - readPreferenceServerSelector, sameServerSelector, secondaryWritableServerSelector } from '../../../src/sdam/server_selection'; @@ -28,19 +28,10 @@ describe('server selection', function () { secondary: true, ok: 1 }); - const secondaryTwo = new ServerDescription('127.0.0.1:27024', { - setName: 'test', - secondary: true, - ok: 1 - }); const mongos = new ServerDescription('127.0.0.1:27019', { msg: 'isdbgrid', ok: 1 }); - const mongosTwo = new ServerDescription('127.0.0.1:27023', { - msg: 'isdbgrid', - ok: 1 - }); const loadBalancer = new ServerDescription('127.0.0.1:27020', { ok: 1 }, { loadBalanced: true }); const single = new ServerDescription('127.0.0.1:27021', { isWritablePrimary: true, @@ -127,7 +118,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('uses the provided read preference', function () { @@ -140,7 +131,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a primary', function () { @@ -167,7 +158,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a primary', function () { @@ -180,7 +171,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a primary', function () { @@ -199,7 +190,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(undefined, ReadPreference.secondary); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); it('selects a primary', function () { expect(servers).to.deep.equal([primary]); @@ -229,7 +224,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a mongos', function () { @@ -242,7 +237,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a mongos', function () { @@ -269,7 +264,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a mongos', function () { @@ -282,7 +277,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a mongos', function () { @@ -301,7 +296,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); it('selects a mongos', function () { expect(servers).to.deep.equal([mongos]); @@ -331,7 +330,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a load balancer', function () { @@ -344,7 +343,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a load balancer', function () { @@ -371,7 +370,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a load balancer', function () { @@ -384,7 +383,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a load balancer', function () { @@ -403,7 +402,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); it('selects a load balancer', function () { expect(servers).to.deep.equal([loadBalancer]); @@ -433,7 +436,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a standalone', function () { @@ -446,7 +449,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a standalone', function () { @@ -473,7 +476,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a standalone', function () { @@ -486,7 +489,7 @@ describe('server selection', function () { const servers = selector( topologyDescription, Array.from(serverDescriptions.values()), - [] + new DeprioritizedServers() ); it('selects a standalone', function () { @@ -505,7 +508,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); it('selects a standalone', function () { expect(servers).to.deep.equal([single]); @@ -558,7 +565,11 @@ describe('server selection', function () { MIN_SECONDARY_WRITE_WIRE_VERSION ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); expect(servers).to.have.lengthOf(2); const selectedAddresses = new Set(servers.map(({ address }) => address)); expect(selectedAddresses.has(serverDescription1.address)).to.be.true; @@ -577,7 +588,11 @@ describe('server selection', function () { { localThresholdMS: 5 } ); const selector = secondaryWritableServerSelector(); - const servers = selector(topologyDescription, Array.from(serverDescriptions.values()), []); + const servers = selector( + topologyDescription, + Array.from(serverDescriptions.values()), + new DeprioritizedServers() + ); expect(servers).to.have.lengthOf(1); const selectedAddresses = new Set(servers.map(({ address }) => address)); expect(selectedAddresses.has(serverDescription1.address)).to.be.true; From 8fa05c6b6d7425311731ae96080ee62ce28f98a0 Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 10 Dec 2025 12:25:03 -0700 Subject: [PATCH 4/4] clean up server selection logic --- src/sdam/server_selection.ts | 173 +++++++++++++++++------------ test/unit/assorted/imports.test.ts | 2 +- 2 files changed, 101 insertions(+), 74 deletions(-) diff --git a/src/sdam/server_selection.ts b/src/sdam/server_selection.ts index 8f7baeaf5ac..8637ea114fc 100644 --- a/src/sdam/server_selection.ts +++ b/src/sdam/server_selection.ts @@ -1,4 +1,4 @@ -import { MongoInvalidArgumentError } from '../error'; +import { MongoInvalidArgumentError, MongoRuntimeError } from '../error'; import { ReadPreference } from '../read_preference'; import { ServerType, TopologyType } from './common'; import type { ServerDescription, TagSet } from './server_description'; @@ -282,44 +282,21 @@ function isDeprioritizedFactory( !deprioritized.has(server); } -/** - * Returns a function which selects servers based on a provided read preference - * - * @param readPreference - The read preference to select with - */ -export function readPreferenceServerSelector(readPreference: ReadPreference): ServerSelector { - if (!readPreference.isValid()) { - throw new MongoInvalidArgumentError('Invalid read preference specified'); - } - - return function readPreferenceServers( - topologyDescription: TopologyDescription, - servers: ServerDescription[], - deprioritized: DeprioritizedServers - ): ServerDescription[] { - if (topologyDescription.type === TopologyType.LoadBalanced) { - return servers.filter(loadBalancerFilter); - } - - if (topologyDescription.type === TopologyType.Unknown) { - return []; - } - - if (topologyDescription.type === TopologyType.Single) { - return latencyWindowReducer(topologyDescription, servers.filter(knownFilter)); - } - - if (topologyDescription.type === TopologyType.Sharded) { - const selectable = filterDeprioritized(servers, deprioritized); - return latencyWindowReducer(topologyDescription, selectable.filter(knownFilter)); - } - - const mode = readPreference.mode; - if (mode === ReadPreference.PRIMARY) { - return filterDeprioritized(servers.filter(primaryFilter), deprioritized); - } - - if (mode === ReadPreference.PRIMARY_PREFERRED) { +function secondarySelector( + readPreference: ReadPreference, + topologyDescription: TopologyDescription, + servers: ServerDescription[], + deprioritized: DeprioritizedServers +) { + const mode = readPreference.mode; + switch (mode) { + case 'primary': + // Note: no need to filter for deprioritized servers. A replica set has only one primary; that means that + // we are in one of two scenarios: + // 1. deprioritized servers is empty - return the primary. + // 2. deprioritized servers contains the primary - return the primary. + return servers.filter(primaryFilter); + case 'primaryPreferred': { const primary = servers.filter(primaryFilter); // If there is a primary and it is not deprioritized, use the primary. Otherwise, @@ -329,60 +306,110 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se return eligiblePrimary; } + // If we make it here, we either have: + // 1. a deprioritized primary + // 2. no eligible primary + // secondaries take precedence of deprioritized primaries. const secondaries = tagSetReducer( readPreference, maxStalenessReducer(readPreference, topologyDescription, servers.filter(secondaryFilter)) ); - const deprioritizedSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); - // console.error({ deprioritizedSecondaries, secondaries, deprioritized }); - if (deprioritizedSecondaries.length) - return latencyWindowReducer(topologyDescription, deprioritizedSecondaries); + const eligibleSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); + if (eligibleSecondaries.length) { + return latencyWindowReducer(topologyDescription, eligibleSecondaries); + } // if we make it here, we have no primaries or secondaries that not deprioritized. // prefer the primary (which may not exist, if the topology has no primary). // otherwise, return the secondaries (which also may not exist, but there is nothing else to check here). return primary.length ? primary : latencyWindowReducer(topologyDescription, secondaries); } - - // TODO: should we be applying the latency window to nearest servers? - if (mode === 'nearest') { - // if read preference is nearest - return latencyWindowReducer( - topologyDescription, - filterDeprioritized( - tagSetReducer( - readPreference, - maxStalenessReducer(readPreference, topologyDescription, servers.filter(nearestFilter)) - ), - deprioritized - ) + case 'nearest': { + const eligible = filterDeprioritized( + tagSetReducer( + readPreference, + maxStalenessReducer(readPreference, topologyDescription, servers.filter(nearestFilter)) + ), + deprioritized ); + return latencyWindowReducer(topologyDescription, eligible); } + case 'secondary': + case 'secondaryPreferred': { + const secondaries = tagSetReducer( + readPreference, + maxStalenessReducer(readPreference, topologyDescription, servers.filter(secondaryFilter)) + ); + const eligibleSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); - const filter = secondaryFilter; + if (eligibleSecondaries.length) { + return latencyWindowReducer(topologyDescription, eligibleSecondaries); + } - const secondaries = tagSetReducer( - readPreference, - maxStalenessReducer(readPreference, topologyDescription, servers.filter(filter)) - ); - const eligibleSecondaries = secondaries.filter(isDeprioritizedFactory(deprioritized)); + // we have no eligible secondaries, try for a primary if we can. + if (mode === ReadPreference.SECONDARY_PREFERRED) { + const primary = servers.filter(primaryFilter); - if (eligibleSecondaries.length) - return latencyWindowReducer(topologyDescription, eligibleSecondaries); + // unlike readPreference=primary, here we do filter for deprioritized servers. + // if the primary is deprioritized, deprioritized secondaries take precedence. + const eligiblePrimary = primary.filter(isDeprioritizedFactory(deprioritized)); + if (eligiblePrimary.length) return eligiblePrimary; - // we have no eligible secondaries, try for a primary. - if (mode === ReadPreference.SECONDARY_PREFERRED) { - const primary = servers.filter(primaryFilter); - const eligiblePrimary = primary.filter(isDeprioritizedFactory(deprioritized)); + // we have no eligible primary nor secondaries that have not been deprioritized + return secondaries.length + ? latencyWindowReducer(topologyDescription, secondaries) + : primary; + } - if (eligiblePrimary.length) return eligiblePrimary; + // return all secondaries in the latency window. + return latencyWindowReducer(topologyDescription, secondaries); + } - // we have no eligible primary nor secondaries that have not been deprioritized - return secondaries.length ? latencyWindowReducer(topologyDescription, secondaries) : primary; + default: { + const _exhaustiveCheck: never = mode; + throw new MongoRuntimeError( + `unexpected readPreference=${mode} (should never happen). Please report a bug in the Node driver Jira project.` + ); } + } +} - // return all secondaries in the latency window. - return latencyWindowReducer(topologyDescription, secondaries); +/** + * Returns a function which selects servers based on a provided read preference + * + * @param readPreference - The read preference to select with + */ +export function readPreferenceServerSelector(readPreference: ReadPreference): ServerSelector { + if (!readPreference.isValid()) { + throw new MongoInvalidArgumentError('Invalid read preference specified'); + } + + return function readPreferenceServers( + topologyDescription: TopologyDescription, + servers: ServerDescription[], + deprioritized: DeprioritizedServers + ): ServerDescription[] { + switch (topologyDescription.type) { + case 'Single': + return latencyWindowReducer(topologyDescription, servers.filter(knownFilter)); + case 'ReplicaSetNoPrimary': + case 'ReplicaSetWithPrimary': + return secondarySelector(readPreference, topologyDescription, servers, deprioritized); + case 'Sharded': { + const selectable = filterDeprioritized(servers, deprioritized); + return latencyWindowReducer(topologyDescription, selectable.filter(knownFilter)); + } + case 'Unknown': + return []; + case 'LoadBalanced': + return servers.filter(loadBalancerFilter); + default: { + const _exhaustiveCheck: never = topologyDescription.type; + throw new MongoRuntimeError( + `unexpected topology type: ${topologyDescription.type} (this should never happen). Please file a bug in the Node driver Jira project.` + ); + } + } }; } diff --git a/test/unit/assorted/imports.test.ts b/test/unit/assorted/imports.test.ts index d5117874f5a..1e66b70eb7d 100644 --- a/test/unit/assorted/imports.test.ts +++ b/test/unit/assorted/imports.test.ts @@ -15,7 +15,7 @@ function* walk(root) { } } -describe.skip('importing mongodb driver', () => { +describe('importing mongodb driver', () => { const sourceFiles = walk(path.resolve(__dirname, '../../../src')); for (const sourceFile of sourceFiles) {