summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCheahuychou Mao <cheahuychou.mao@mongodb.com>2020-01-21 11:32:46 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-01-29 03:30:29 +0000
commit367f47f7f19a6344039a15e3d0748508ad9c6c2c (patch)
treea9daabfa3c33534496c55bd4d20b87f131c0ba96
parent5fd95451f78ad667eccca8d4934873529a35e746 (diff)
downloadmongo-367f47f7f19a6344039a15e3d0748508ad9c6c2c.tar.gz
SERVER-45449 Write a function to compute the desired latency for a staggered hedged read
create mode 100644 jstests/sharding/hedged_reads_server_parameters.js rename src/mongo/s/{warmup_server_parameters.cpp => hedge_options_util.cpp} (52%) rename src/mongo/s/{warmup_server_parameters.h => hedge_options_util.h} (74%) create mode 100644 src/mongo/s/hedge_options_util_test.cpp create mode 100644 src/mongo/s/mongos_server_parameters.idl
-rw-r--r--jstests/sharding/hedged_reads_server_parameters.js38
-rw-r--r--jstests/sharding/hedging_metrics_server_status.js2
-rw-r--r--src/mongo/executor/remote_command_request.cpp37
-rw-r--r--src/mongo/executor/remote_command_request.h40
-rw-r--r--src/mongo/s/SConscript29
-rw-r--r--src/mongo/s/async_requests_sender.cpp10
-rw-r--r--src/mongo/s/hedge_options_util.cpp (renamed from src/mongo/s/warmup_server_parameters.cpp)39
-rw-r--r--src/mongo/s/hedge_options_util.h (renamed from src/mongo/s/warmup_server_parameters.h)23
-rw-r--r--src/mongo/s/hedge_options_util_test.cpp229
-rw-r--r--src/mongo/s/mongos_options.idl23
-rw-r--r--src/mongo/s/mongos_server_parameters.idl85
-rw-r--r--src/mongo/s/sharding_initialization.cpp2
12 files changed, 504 insertions, 53 deletions
diff --git a/jstests/sharding/hedged_reads_server_parameters.js b/jstests/sharding/hedged_reads_server_parameters.js
new file mode 100644
index 00000000000..3c5dd089171
--- /dev/null
+++ b/jstests/sharding/hedged_reads_server_parameters.js
@@ -0,0 +1,38 @@
+/*
+ * Intergration test for the server parameters for hedged reads. The more comprehensive
+ * unit test can be found in executor/remote_command_request_test.cpp.
+ *
+ * TODO (SERVER-45432): test that hedging is performed as expected.
+ *
+ * @tags: [requires_fcv_44]
+ */
+(function() {
+
+const st = new ShardingTest({
+ shards: 2,
+ mongosOptions: {setParameter: {maxTimeMSThresholdForHedging: 1500, hedgingDelayPercentage: 50}}
+});
+const dbName = "foo";
+const collName = "bar";
+const ns = dbName + "." + collName;
+const testDB = st.s.getDB(dbName);
+
+assert.commandWorked(st.s.adminCommand({enableSharding: dbName}));
+st.ensurePrimaryShard(dbName, st.shard0.shardName);
+assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {x: 1}}));
+
+// With maxTimeMS.
+assert.commandWorked(st.s.getDB(dbName).runCommand(
+ {query: {find: collName, maxTimeMS: 1000}, $readPreference: {mode: "nearest", hedge: {}}}));
+
+// Without maxTimeMS.
+st.restartMongos(0, {
+ restart: true,
+ setParameter: {defaultHedgingDelayMS: 800},
+});
+
+assert.commandWorked(st.s.getDB(dbName).runCommand(
+ {query: {count: collName}, $readPreference: {mode: "secondaryPreferred", hedge: {}}}));
+
+st.stop();
+})();
diff --git a/jstests/sharding/hedging_metrics_server_status.js b/jstests/sharding/hedging_metrics_server_status.js
index 7010316f6d4..efd0f0c9413 100644
--- a/jstests/sharding/hedging_metrics_server_status.js
+++ b/jstests/sharding/hedging_metrics_server_status.js
@@ -58,6 +58,8 @@ checkServerStatusHedgingMetrics(testDB, expectedHedgingMetrics);
assert.commandWorked(
testDB.runCommand({query: {find: collName}, $readPreference: {mode: "nearest", hedge: {}}}));
+// TODO (SERVER-45432): increment expectedHedgingMetrics.numTotalOperations and
+// expectedHedgingMetrics.numTotalHedgedOperations.
checkServerStatusHedgingMetrics(testDB, expectedHedgingMetrics);
st.stop();
diff --git a/src/mongo/executor/remote_command_request.cpp b/src/mongo/executor/remote_command_request.cpp
index b8ffb8486e5..be119d7d69b 100644
--- a/src/mongo/executor/remote_command_request.cpp
+++ b/src/mongo/executor/remote_command_request.cpp
@@ -59,8 +59,13 @@ RemoteCommandRequestBase::RemoteCommandRequestBase(RequestId requestId,
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
- Milliseconds timeoutMillis)
- : id(requestId), dbname(theDbName), metadata(metadataObj), opCtx(opCtx) {
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions)
+ : id(requestId),
+ dbname(theDbName),
+ metadata(metadataObj),
+ opCtx(opCtx),
+ hedgeOptions(hedgeOptions) {
// If there is a comment associated with the current operation, append it to the command that we
// are about to dispatch to the shards.
//
@@ -91,8 +96,10 @@ RemoteCommandRequestImpl<T>::RemoteCommandRequestImpl(RequestId requestId,
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
- Milliseconds timeoutMillis)
- : RemoteCommandRequestBase(requestId, theDbName, theCmdObj, metadataObj, opCtx, timeoutMillis),
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions)
+ : RemoteCommandRequestBase(
+ requestId, theDbName, theCmdObj, metadataObj, opCtx, timeoutMillis, hedgeOptions),
target(theTarget) {
if constexpr (std::is_same_v<T, std::vector<HostAndPort>>) {
invariant(!theTarget.empty());
@@ -100,19 +107,32 @@ RemoteCommandRequestImpl<T>::RemoteCommandRequestImpl(RequestId requestId,
}
template <typename T>
-RemoteCommandRequestImpl<T>::RemoteCommandRequestImpl(const T& theTarget,
+RemoteCommandRequestImpl<T>::RemoteCommandRequestImpl(RequestId requestId,
+ const T& theTarget,
const std::string& theDbName,
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
Milliseconds timeoutMillis)
+ : RemoteCommandRequestImpl(
+ requestId, theTarget, theDbName, theCmdObj, metadataObj, opCtx, timeoutMillis, {}) {}
+
+template <typename T>
+RemoteCommandRequestImpl<T>::RemoteCommandRequestImpl(const T& theTarget,
+ const std::string& theDbName,
+ const BSONObj& theCmdObj,
+ const BSONObj& metadataObj,
+ OperationContext* opCtx,
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions)
: RemoteCommandRequestImpl(requestIdCounter.addAndFetch(1),
theTarget,
theDbName,
theCmdObj,
metadataObj,
opCtx,
- timeoutMillis) {}
+ timeoutMillis,
+ hedgeOptions) {}
template <typename T>
std::string RemoteCommandRequestImpl<T>::toString() const {
@@ -129,6 +149,11 @@ std::string RemoteCommandRequestImpl<T>::toString() const {
out << " expDate:" << expirationDate.toString();
}
+ if (hedgeOptions) {
+ out << " hedgeOptions.count: " << hedgeOptions->count;
+ out << " hedgeOptions.delay: " << hedgeOptions->delay;
+ }
+
out << " cmd:" << cmdObj.toString();
return out;
}
diff --git a/src/mongo/executor/remote_command_request.h b/src/mongo/executor/remote_command_request.h
index b776a14eafa..ab1cf4b3a34 100644
--- a/src/mongo/executor/remote_command_request.h
+++ b/src/mongo/executor/remote_command_request.h
@@ -43,6 +43,11 @@ namespace mongo {
namespace executor {
struct RemoteCommandRequestBase {
+ struct HedgeOptions {
+ size_t count;
+ Milliseconds delay;
+ };
+
// Indicates that there is no timeout for the request to complete
static constexpr Milliseconds kNoTimeout{-1};
@@ -58,7 +63,8 @@ struct RemoteCommandRequestBase {
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
- Milliseconds timeoutMillis);
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions);
// Internal id of this request. Not interpreted and used for tracing purposes only.
RequestId id;
@@ -76,6 +82,8 @@ struct RemoteCommandRequestBase {
// metadata attachment (i.e., replication).
OperationContext* opCtx{nullptr};
+ boost::optional<HedgeOptions> hedgeOptions;
+
Milliseconds timeout = kNoTimeout;
// Deadline by when the request must be completed
@@ -112,6 +120,15 @@ struct RemoteCommandRequestImpl : RemoteCommandRequestBase {
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions);
+
+ RemoteCommandRequestImpl(RequestId requestId,
+ const Target& theTarget,
+ const std::string& theDbName,
+ const BSONObj& theCmdObj,
+ const BSONObj& metadataObj,
+ OperationContext* opCtx,
Milliseconds timeoutMillis);
RemoteCommandRequestImpl(const Target& theTarget,
@@ -119,7 +136,26 @@ struct RemoteCommandRequestImpl : RemoteCommandRequestBase {
const BSONObj& theCmdObj,
const BSONObj& metadataObj,
OperationContext* opCtx,
- Milliseconds timeoutMillis = kNoTimeout);
+ Milliseconds timeoutMillis,
+ boost::optional<HedgeOptions> hedgeOptions);
+
+ RemoteCommandRequestImpl(const Target& theTarget,
+ const std::string& theDbName,
+ const BSONObj& theCmdObj,
+ const BSONObj& metadataObj,
+ OperationContext* opCtx,
+ Milliseconds timeoutMillis = kNoTimeout)
+ : RemoteCommandRequestImpl(
+ theTarget, theDbName, theCmdObj, metadataObj, opCtx, timeoutMillis, boost::none) {}
+
+ RemoteCommandRequestImpl(const Target& theTarget,
+ const std::string& theDbName,
+ const BSONObj& theCmdObj,
+ const BSONObj& metadataObj,
+ OperationContext* opCtx,
+ boost::optional<HedgeOptions> hedgeOptions)
+ : RemoteCommandRequestImpl(
+ theTarget, theDbName, theCmdObj, metadataObj, opCtx, kNoTimeout, hedgeOptions) {}
RemoteCommandRequestImpl(const Target& theTarget,
const std::string& theDbName,
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index ec3bc0f8f20..ab5e0984fb6 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -106,7 +106,6 @@ env.Library(
source=[
'sharding_initialization.cpp',
'sharding_task_executor_pool_controller.cpp',
- 'warmup_server_parameters.cpp',
env.Idlc('sharding_task_executor_pool.idl')[0],
'client/sharding_connection_hook.cpp',
'client/sharding_network_connection_hook.cpp',
@@ -124,6 +123,7 @@ env.Library(
'$BUILD_DIR/mongo/executor/thread_pool_task_executor',
'$BUILD_DIR/mongo/executor/connection_pool_executor',
'coreshard',
+ 'mongos_server_parameters',
'sharding_task_executor',
],
)
@@ -140,6 +140,7 @@ env.Library(
"$BUILD_DIR/mongo/s/client/sharding_client",
"$BUILD_DIR/mongo/s/coreshard",
'$BUILD_DIR/mongo/s/client/shard_interface',
+ 'hedge_options_util',
],
)
@@ -409,6 +410,31 @@ env.Library(
],
)
+env.Library(
+ target='mongos_server_parameters',
+ source=[
+ env.Idlc('mongos_server_parameters.idl')[0],
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/idl/server_parameter',
+ ]
+)
+
+env.Library(
+ target='hedge_options_util',
+ source=[
+ 'hedge_options_util.cpp',
+ ],
+ LIBDEPS=[
+ 'mongos_server_parameters',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/client/read_preference',
+ '$BUILD_DIR/mongo/db/query/query_request',
+ '$BUILD_DIR/mongo/idl/server_parameter',
+ ]
+)
+
env.CppUnitTest(
target='s_test',
source=[
@@ -434,6 +460,7 @@ env.CppUnitTest(
'client/shard_connection_test.cpp',
'cluster_identity_loader_test.cpp',
'cluster_last_error_info_test.cpp',
+ 'hedge_options_util_test.cpp',
'request_types/add_shard_request_test.cpp',
'request_types/add_shard_to_zone_request_test.cpp',
'request_types/balance_chunk_request_test.cpp',
diff --git a/src/mongo/s/async_requests_sender.cpp b/src/mongo/s/async_requests_sender.cpp
index 5d6f0b21ccb..92bf717f5e7 100644
--- a/src/mongo/s/async_requests_sender.cpp
+++ b/src/mongo/s/async_requests_sender.cpp
@@ -41,6 +41,7 @@
#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/grid.h"
+#include "mongo/s/hedge_options_util.h"
#include "mongo/transport/baton.h"
#include "mongo/transport/transport_layer.h"
#include "mongo/util/assert_util.h"
@@ -181,8 +182,13 @@ SemiFuture<std::vector<HostAndPort>> AsyncRequestsSender::RemoteData::resolveSha
auto AsyncRequestsSender::RemoteData::scheduleRemoteCommand(std::vector<HostAndPort>&& hostAndPorts)
-> SemiFuture<RemoteCommandOnAnyCallbackArgs> {
- executor::RemoteCommandRequestOnAny request(
- std::move(hostAndPorts), _ars->_db, _cmdObj, _ars->_metadataObj, _ars->_opCtx);
+ auto hedgeOptions = extractHedgeOptions(_ars->_opCtx, _cmdObj);
+ executor::RemoteCommandRequestOnAny request(std::move(hostAndPorts),
+ _ars->_db,
+ _cmdObj,
+ _ars->_metadataObj,
+ _ars->_opCtx,
+ hedgeOptions);
// We have to make a promise future pair because the TaskExecutor doesn't currently support a
// future returning variant of scheduleRemoteCommand
diff --git a/src/mongo/s/warmup_server_parameters.cpp b/src/mongo/s/hedge_options_util.cpp
index 3809bf64844..2de268c9e79 100644
--- a/src/mongo/s/warmup_server_parameters.cpp
+++ b/src/mongo/s/hedge_options_util.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019-present MongoDB, Inc.
+ * Copyright (C) 2020-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
@@ -27,13 +27,42 @@
* it in the license file.
*/
-#include "mongo/s/warmup_server_parameters.h"
+#include "mongo/s/hedge_options_util.h"
+#include "mongo/client/read_preference.h"
+#include "mongo/db/query/query_request.h"
+#include "mongo/s/mongos_server_parameters_gen.h"
namespace mongo {
-bool gLoadRoutingTableOnStartup = true;
-bool gWarmMinConnectionsInShardingTaskExecutorPoolOnStartup = true;
-int gWarmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS = 2000;
+boost::optional<executor::RemoteCommandRequestOnAny::HedgeOptions> extractHedgeOptions(
+ OperationContext* opCtx, const BSONObj& cmdObj) {
+ const auto hedgingMode = ReadPreferenceSetting::get(opCtx).hedgingMode;
+
+ if (hedgingMode && hedgingMode->getEnabled()) {
+ boost::optional<int> maxTimeMS;
+ if (auto cmdOptionMaxTimeMSField = cmdObj[QueryRequest::cmdOptionMaxTimeMS]) {
+ maxTimeMS = uassertStatusOK(QueryRequest::parseMaxTimeMS(cmdOptionMaxTimeMSField));
+ }
+
+ // Check if the operation is worth hedging.
+ if (maxTimeMS && maxTimeMS > gMaxTimeMSThresholdForHedging) {
+ return boost::none;
+ }
+
+ // Compute the delay.
+ auto delay = Milliseconds{0};
+ bool shouldDelayHedging = hedgingMode->getDelay();
+
+ if (shouldDelayHedging) {
+ delay = maxTimeMS ? Milliseconds{gHedgingDelayPercentage * maxTimeMS.get() / 100}
+ : Milliseconds{gDefaultHedgingDelayMS};
+ }
+
+ return executor::RemoteCommandRequestOnAny::HedgeOptions{1, delay};
+ }
+
+ return boost::none;
+}
} // namespace mongo
diff --git a/src/mongo/s/warmup_server_parameters.h b/src/mongo/s/hedge_options_util.h
index 9d1b616b322..5e045fc4c7b 100644
--- a/src/mongo/s/warmup_server_parameters.h
+++ b/src/mongo/s/hedge_options_util.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019-present MongoDB, Inc.
+ * Copyright (C) 2020-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
@@ -26,23 +26,20 @@
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
-
#pragma once
-namespace mongo {
-/**
- * Set parameter used to control whether or not the mongos attempts to precache the routing table on
- * startup.
- */
+#include "mongo/platform/basic.h"
-extern bool gLoadRoutingTableOnStartup;
+#include "mongo/executor/remote_command_request.h"
+
+namespace mongo {
/**
- * Set parameters used to control whether or not the mongos attempts to warm up the connection
- * pool on start up and for how long it should try.
+ * Constructs and returns hedge options based on the ReadPreferenceSetting on the 'opCtx'
+ * (assumes that it is not null), the hedging server parameters, and maxTimeMS in 'cmdObj'.
+ * If no hedging should be performed, returns boost::none.
*/
-
-extern bool gWarmMinConnectionsInShardingTaskExecutorPoolOnStartup;
-extern int gWarmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS;
+boost::optional<executor::RemoteCommandRequestOnAny::HedgeOptions> extractHedgeOptions(
+ OperationContext* opCtx, const BSONObj& cmdObj);
} // namespace mongo
diff --git a/src/mongo/s/hedge_options_util_test.cpp b/src/mongo/s/hedge_options_util_test.cpp
new file mode 100644
index 00000000000..7aae8afadfe
--- /dev/null
+++ b/src/mongo/s/hedge_options_util_test.cpp
@@ -0,0 +1,229 @@
+/**
+ * Copyright (C) 2020-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/read_preference.h"
+#include "mongo/s/hedge_options_util.h"
+#include "mongo/s/mongos_server_parameters_gen.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/duration.h"
+
+namespace mongo {
+namespace {
+
+class HedgeOptionsUtilTestFixture : public unittest::Test {
+protected:
+ /**
+ * Set the given server parameters.
+ */
+ void setParameters(const BSONObj& parameters) {
+ const ServerParameter::Map& parameterMap = ServerParameterSet::getGlobal()->getMap();
+ BSONObjIterator parameterIterator(parameters);
+
+ while (parameterIterator.more()) {
+ BSONElement parameter = parameterIterator.next();
+ std::string parameterName = parameter.fieldName();
+
+ ServerParameter::Map::const_iterator foundParameter = parameterMap.find(parameterName);
+ uassertStatusOK(foundParameter->second->set(parameter));
+ }
+ }
+
+ /**
+ * Unset the given server parameters by setting them back to the default.
+ */
+ void unsetParameters(const BSONObj& parameters) {
+ const ServerParameter::Map& parameterMap = ServerParameterSet::getGlobal()->getMap();
+ BSONObjIterator parameterIterator(parameters);
+
+ while (parameterIterator.more()) {
+ BSONElement parameter = parameterIterator.next();
+ std::string parameterName = parameter.fieldName();
+ const auto defaultParameter = kDefaultParameters[parameterName];
+ ASSERT_FALSE(defaultParameter.eoo());
+
+ ServerParameter::Map::const_iterator foundParameter = parameterMap.find(parameterName);
+ uassertStatusOK(foundParameter->second->set(defaultParameter));
+ }
+ }
+
+ /**
+ * Sets the given server parameters and sets the ReadPreferenceSetting decoration as given by
+ * 'rspObj'on the 'opCtx'. Constructs a RemoteCommandRequestOnAny with 'cmdObjWithoutReadPref'.
+ * If 'expectedDelay' is not given, asserts that the RemoteCommandRequestOnAny does not have
+ * hedgingOptions set. Otherwise, asserts that hedgingOptions.delay is equal to 'expectedDelay'.
+ */
+ void checkHedgeOptions(const BSONObj& serverParameters,
+ const BSONObj& cmdObjWithoutReadPref,
+ const BSONObj& rspObj,
+ const boost::optional<Milliseconds> expectedDelay = boost::none) {
+ setParameters(serverParameters);
+
+ auto opCtx = _client->makeOperationContext();
+ ReadPreferenceSetting::get(opCtx.get()) =
+ uassertStatusOK(ReadPreferenceSetting::fromInnerBSON(rspObj));
+
+ auto hedgeOptions = extractHedgeOptions(opCtx.get(), cmdObjWithoutReadPref);
+ if (expectedDelay) {
+ ASSERT_TRUE(hedgeOptions.has_value());
+ ASSERT_EQUALS(hedgeOptions->delay, expectedDelay.get());
+ } else {
+ ASSERT_FALSE(hedgeOptions.has_value());
+ }
+
+ unsetParameters(serverParameters);
+ }
+
+ static inline const std::string kCollName = "testColl";
+
+ static inline const std::string kMaxTimeMSThresholdForHedgingFieldName =
+ "maxTimeMSThresholdForHedging";
+ static inline const std::string kHedgingDelayPercentageFieldName = "hedgingDelayPercentage";
+ static inline const std::string kDefaultHedgingDelayMSFieldName = "defaultHedgingDelayMS";
+
+ static inline const BSONObj kDefaultParameters =
+ BSON(kMaxTimeMSThresholdForHedgingFieldName
+ << kMaxTimeMSThresholdForHedgingDefault << kHedgingDelayPercentageFieldName
+ << kHedgingDelayPercentageDefault << kDefaultHedgingDelayMSFieldName
+ << kDefaultHedgingDelayMSDefault);
+
+private:
+ ServiceContext::UniqueServiceContext _serviceCtx = ServiceContext::make();
+ ServiceContext::UniqueClient _client = _serviceCtx->makeClient("RemoteCommandRequestTest");
+};
+
+TEST_F(HedgeOptionsUtilTestFixture, DefaultWithoutMaxTimeMS) {
+ const auto parameters = BSONObj();
+ const auto cmdObj = BSON("find" << kCollName);
+ const auto rspObj = BSON("mode"
+ << "primaryPreferred"
+ << "hedge" << BSONObj());
+ const auto expectedDelay = Milliseconds{kDefaultHedgingDelayMSDefault};
+
+ checkHedgeOptions(parameters, cmdObj, rspObj, expectedDelay);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, DefaultWithMaxTimeMS) {
+ const auto parameters = BSONObj();
+ const auto maxTimeMS = 100;
+ const auto cmdObj = BSON("find" << kCollName << "maxTimeMS" << maxTimeMS);
+ const auto rspObj = BSON("mode"
+ << "secondary"
+ << "hedge" << BSONObj());
+ const auto expectedDelay = Milliseconds{kHedgingDelayPercentageDefault * maxTimeMS / 100};
+
+ checkHedgeOptions(parameters, cmdObj, rspObj, expectedDelay);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, DefaultWithMaxTimeMSAboveThreshold) {
+ const auto parameters = BSONObj();
+ const auto cmdObj = BSON("find" << kCollName << "maxTimeMS" << 1000000);
+ const auto rspObj = BSON("mode"
+ << "secondaryPreferred"
+ << "hedge" << BSONObj());
+
+ checkHedgeOptions(parameters, cmdObj, rspObj);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, DelayDisabled) {
+ const auto parameters = BSONObj();
+ const auto cmdObj = BSON("find" << kCollName);
+ const auto rspObj = BSON("mode"
+ << "nearest"
+ << "hedge" << BSON("delay" << false));
+ const auto expectedDelay = Milliseconds{0};
+
+ checkHedgeOptions(parameters, cmdObj, rspObj, expectedDelay);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, HedgingDisabledCompletely) {
+ const auto parameters = BSONObj();
+ const auto cmdObj = BSON("find" << kCollName);
+ const auto rspObj = BSON("mode"
+ << "primaryPreferred"
+ << "hedge" << BSON("enabled" << false << "delay" << false));
+
+ checkHedgeOptions(parameters, cmdObj, rspObj);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, SetMaxTimeMSThreshold) {
+ const auto parameters = BSON(kMaxTimeMSThresholdForHedgingFieldName << 1000);
+ const auto rspObj = BSON("mode"
+ << "secondary"
+ << "hedge" << BSONObj());
+
+ auto maxTimeMS = 500;
+ auto expectedDelay = Milliseconds{kHedgingDelayPercentageDefault * maxTimeMS / 100};
+ checkHedgeOptions(
+ parameters, BSON("find" << kCollName << "maxTimeMS" << maxTimeMS), rspObj, expectedDelay);
+
+ maxTimeMS = 1200;
+ expectedDelay = Milliseconds{0};
+ checkHedgeOptions(parameters, BSON("find" << kCollName << "maxTimeMS" << maxTimeMS), rspObj);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, SetHedgingDelayPercentage) {
+ const auto parameters = BSON(kHedgingDelayPercentageFieldName << 50);
+ const auto rspObj = BSON("mode"
+ << "secondaryPreferred"
+ << "hedge" << BSONObj());
+
+ checkHedgeOptions(
+ parameters, BSON("find" << kCollName << "maxTimeMS" << 500), rspObj, Milliseconds{250});
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, SetMaxTimeMSThresholdAndHedgingDelayPercentage) {
+ const auto parameters = BSON(kMaxTimeMSThresholdForHedgingFieldName
+ << 1000 << kHedgingDelayPercentageFieldName << 50);
+ const auto rspObj = BSON("mode"
+ << "secondaryPreferred"
+ << "hedge" << BSONObj());
+
+ checkHedgeOptions(
+ parameters, BSON("find" << kCollName << "maxTimeMS" << 500), rspObj, Milliseconds{250});
+ checkHedgeOptions(parameters, BSON("find" << kCollName << "maxTimeMS" << 1200), rspObj);
+}
+
+TEST_F(HedgeOptionsUtilTestFixture, SetAll) {
+ const auto parameters = BSON(kMaxTimeMSThresholdForHedgingFieldName
+ << 1000 << kHedgingDelayPercentageFieldName << 50
+ << kDefaultHedgingDelayMSFieldName << 800);
+ const auto rspObj = BSON("mode"
+ << "nearest"
+ << "hedge" << BSONObj());
+
+ checkHedgeOptions(
+ parameters, BSON("find" << kCollName << "maxTimeMS" << 500), rspObj, Milliseconds{250});
+ checkHedgeOptions(parameters, BSON("find" << kCollName), rspObj, Milliseconds{800});
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/s/mongos_options.idl b/src/mongo/s/mongos_options.idl
index a9d04e8d39e..f92d2474fad 100644
--- a/src/mongo/s/mongos_options.idl
+++ b/src/mongo/s/mongos_options.idl
@@ -31,33 +31,10 @@ global:
cpp_namespace: "mongo"
cpp_includes:
- "mongo/s/mongos_options.h"
- - "mongo/s/warmup_server_parameters.h"
configs:
section: "Sharding options"
source: [ yaml, cli, ini ]
-server_parameters:
- loadRoutingTableOnStartup:
- description: <-
- Enables precaching of the mongos routing table on startup.
- set_at: [ startup ]
- cpp_varname: "gLoadRoutingTableOnStartup"
- default: true
-
- warmMinConnectionsInShardingTaskExecutorPoolOnStartup:
- description: <-
- Enables prewarming of the connection pool.
- set_at: [ startup ]
- cpp_varname: "gWarmMinConnectionsInShardingTaskExecutorPoolOnStartup"
- default: true
-
- warmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS:
- description: <-
- How long to wait for all hosts to have at least one connection.
- set_at: [ startup ]
- cpp_varname: "gWarmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS"
- default: 2000 # 2secs
-
configs:
"sharding.configDB":
description: >-
diff --git a/src/mongo/s/mongos_server_parameters.idl b/src/mongo/s/mongos_server_parameters.idl
new file mode 100644
index 00000000000..1724d0e13ba
--- /dev/null
+++ b/src/mongo/s/mongos_server_parameters.idl
@@ -0,0 +1,85 @@
+
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+
+global:
+ cpp_namespace: "mongo"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+server_parameters:
+ loadRoutingTableOnStartup:
+ description: >-
+ Enables precaching of the mongos routing table on startup.
+ set_at: [ startup ]
+ cpp_vartype: bool
+ cpp_varname: "gLoadRoutingTableOnStartup"
+ default: true
+
+ warmMinConnectionsInShardingTaskExecutorPoolOnStartup:
+ description: >-
+ Enables prewarming of the connection pool.
+ set_at: [ startup ]
+ cpp_vartype: bool
+ cpp_varname: "gWarmMinConnectionsInShardingTaskExecutorPoolOnStartup"
+ default: true
+
+ warmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS:
+ description: >-
+ How long to wait for all hosts to have at least one connection.
+ set_at: [ startup ]
+ cpp_vartype: int
+ cpp_varname: "gWarmMinConnectionsInShardingTaskExecutorPoolOnStartupWaitMS"
+ default: 2000 # 2secs
+
+ maxTimeMSThresholdForHedging:
+ description: >-
+ The upper threshold for the expected running time of an operation (maxTimeMS)
+ for it to be worth hedging.
+ set_at: [ startup ]
+ cpp_vartype: int
+ cpp_varname: "gMaxTimeMSThresholdForHedging"
+ default: 5000
+
+ hedgingDelayPercentage:
+ description: >-
+ The percentage of maxTimeMS to wait for before dispatching subsequent reads.
+ set_at: [ startup ]
+ cpp_vartype: int
+ cpp_varname: "gHedgingDelayPercentage"
+ default: 25
+
+ defaultHedgingDelayMS:
+ description: >-
+ The default wait time in milliseconds before dispatching subsequent reads if
+ maxTimeMS is not given.
+ set_at: [ startup ]
+ cpp_vartype: int
+ cpp_varname: "gDefaultHedgingDelayMS"
+ default: 1250
diff --git a/src/mongo/s/sharding_initialization.cpp b/src/mongo/s/sharding_initialization.cpp
index e4188d95cfe..313f170fcd2 100644
--- a/src/mongo/s/sharding_initialization.cpp
+++ b/src/mongo/s/sharding_initialization.cpp
@@ -67,11 +67,11 @@
#include "mongo/s/client/sharding_network_connection_hook.h"
#include "mongo/s/cluster_identity_loader.h"
#include "mongo/s/grid.h"
+#include "mongo/s/mongos_server_parameters_gen.h"
#include "mongo/s/query/cluster_cursor_manager.h"
#include "mongo/s/sharding_task_executor.h"
#include "mongo/s/sharding_task_executor_pool_controller.h"
#include "mongo/s/sharding_task_executor_pool_gen.h"
-#include "mongo/s/warmup_server_parameters.h"
#include "mongo/stdx/thread.h"
#include "mongo/util/concurrency/thread_pool.h"
#include "mongo/util/exit.h"