From bb67941a1ba9c04a58bc4cb74cfd02ec9f315024 Mon Sep 17 00:00:00 2001 From: Cheahuychou Mao Date: Wed, 25 Mar 2020 13:59:23 -0400 Subject: SERVER-47141 Make failpoint in NetworkInterfaceTL sort targets before constructing CommandState --- jstests/sharding/hedged_reads.js | 17 ++++++------ src/mongo/executor/network_interface_tl.cpp | 40 +++++++++++++---------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/jstests/sharding/hedged_reads.js b/jstests/sharding/hedged_reads.js index 9cf05016615..288f0d4d60a 100644 --- a/jstests/sharding/hedged_reads.js +++ b/jstests/sharding/hedged_reads.js @@ -94,15 +94,15 @@ st.rs0.nodes.forEach(function(conn) { assert.commandWorked( st.s.adminCommand({setParameter: 1, logComponentVerbosity: {network: {verbosity: 2}}})); -jsTest.log("Verify the initial request is canceled when the hedged request responds first"); +jsTest.log("Verify that the initial request is canceled when the hedged request responds first"); try { // Make the initial request block. - setCommandDelay(sortedNodes[0], "find", kLargeTimeoutMS); + setCommandDelay(sortedNodes[0], "count", kLargeTimeoutMS); const comment = "test_kill_initial_request_" + ObjectId(); assert.commandWorked(testDB.runCommand({ - find: collName, - filter: {x: {$gte: 0}}, + count: collName, + query: {x: {$gte: 0}}, $readPreference: {mode: "nearest"}, comment: comment })); @@ -117,18 +117,19 @@ try { clearCommandDelay(sortedNodes[0]); } -jsTest.log("Verify the additional request is canceled when the initial request responds first"); +jsTest.log( + "Verify that the additional request is canceled when the initial request responds first"); try { // Make the additional/hedged request block, set a large maxTimeMSForHedgedReads to prevent // the remote host from killing the operation by itself. assert.commandWorked( st.s.adminCommand({setParameter: 1, maxTimeMSForHedgedReads: kLargeTimeoutMS})); - setCommandDelay(sortedNodes[1], "find", kLargeTimeoutMS); + setCommandDelay(sortedNodes[1], "count", kLargeTimeoutMS); const comment = "test_kill_additional_request_" + ObjectId(); assert.commandWorked(testDB.runCommand({ - find: collName, - filter: {x: {$gte: 0}}, + count: collName, + query: {x: {$gte: 0}}, $readPreference: {mode: "nearest"}, comment: comment })); diff --git a/src/mongo/executor/network_interface_tl.cpp b/src/mongo/executor/network_interface_tl.cpp index fcae4dee869..3f2f6871c3d 100644 --- a/src/mongo/executor/network_interface_tl.cpp +++ b/src/mongo/executor/network_interface_tl.cpp @@ -419,6 +419,18 @@ Status NetworkInterfaceTL::startCommand(const TaskExecutor::CallbackHandle& cbHa request.metadata = newMetadata.obj(); } + bool targetHostsInAlphabeticalOrder = + MONGO_unlikely(networkInterfaceSendRequestsToTargetHostsInAlphabeticalOrder.shouldFail()); + + if (targetHostsInAlphabeticalOrder) { + // Sort the target hosts by host names. + std::sort(request.target.begin(), + request.target.end(), + [](const HostAndPort& target1, const HostAndPort& target2) { + return target1.toString() < target2.toString(); + }); + } + auto [cmdState, future] = CommandState::make(this, request, cbHandle); if (cmdState->requestOnAny.timeout != cmdState->requestOnAny.kNoTimeout) { cmdState->deadline = cmdState->stopwatch.start() + cmdState->requestOnAny.timeout; @@ -487,37 +499,21 @@ Status NetworkInterfaceTL::startCommand(const TaskExecutor::CallbackHandle& cbHa RequestManager* rm = cmdState->requestManager.get(); - if (MONGO_unlikely(networkInterfaceSendRequestsToTargetHostsInAlphabeticalOrder.shouldFail())) { - // Sort the target hosts by host names. - std::sort(request.target.begin(), - request.target.end(), - [](const HostAndPort& target1, const HostAndPort& target2) { - return target1.toString() < target2.toString(); - }); - } - // Attempt to get a connection to every target host for (size_t idx = 0; idx < request.target.size() && !rm->usedAllConn(); ++idx) { auto connFuture = _pool->get(request.target[idx], request.sslMode, request.timeout); - if (connFuture.isReady()) { + // If connection future is ready or requests should be sent in order, send the request + // immediately. + if (connFuture.isReady() || targetHostsInAlphabeticalOrder) { rm->trySend(std::move(connFuture).getNoThrow(), idx); continue; } - if (MONGO_unlikely( - networkInterfaceSendRequestsToTargetHostsInAlphabeticalOrder.shouldFail())) { - // Wait for a connection so the requests are sent to target hosts in alphabetical order - // of host names. - auto swConn = std::move(connFuture).get(); + // Otherwise, schedule the request. + std::move(connFuture).thenRunOn(_reactor).getAsync([requestStates, rm, idx](auto swConn) { rm->trySend(std::move(swConn), idx); - } else { - // For every connection future we didn't have immediately ready, schedule - std::move(connFuture) - .thenRunOn(_reactor) - .getAsync( - [requestStates, rm, idx](auto swConn) { rm->trySend(std::move(swConn), idx); }); - } + }); } return Status::OK(); -- cgit v1.2.1