diff options
author | Cheahuychou Mao <cheahuychou.mao@mongodb.com> | 2020-01-21 11:32:46 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-01-29 03:30:29 +0000 |
commit | 367f47f7f19a6344039a15e3d0748508ad9c6c2c (patch) | |
tree | a9daabfa3c33534496c55bd4d20b87f131c0ba96 | |
parent | 5fd95451f78ad667eccca8d4934873529a35e746 (diff) | |
download | mongo-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.js | 38 | ||||
-rw-r--r-- | jstests/sharding/hedging_metrics_server_status.js | 2 | ||||
-rw-r--r-- | src/mongo/executor/remote_command_request.cpp | 37 | ||||
-rw-r--r-- | src/mongo/executor/remote_command_request.h | 40 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 29 | ||||
-rw-r--r-- | src/mongo/s/async_requests_sender.cpp | 10 | ||||
-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.cpp | 229 | ||||
-rw-r--r-- | src/mongo/s/mongos_options.idl | 23 | ||||
-rw-r--r-- | src/mongo/s/mongos_server_parameters.idl | 85 | ||||
-rw-r--r-- | src/mongo/s/sharding_initialization.cpp | 2 |
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" |