summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVarun Ravichandran <varun.ravichandran@mongodb.com>2022-05-09 14:50:24 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-05-28 03:13:16 +0000
commitc9e3facf5dd94fd39066f54d44ee846f750c988b (patch)
tree415dd8026b69345e965a5ee57c19b6a9a964b7b2 /src
parent136275a221896f712ee6ba874f6fb0aeb260cb28 (diff)
downloadmongo-c9e3facf5dd94fd39066f54d44ee846f750c988b.tar.gz
SERVER-62264: Periodically refresh cluster server parameters on mongos
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/SConscript8
-rw-r--r--src/mongo/db/commands/get_cluster_parameter_command.cpp73
-rw-r--r--src/mongo/db/commands/get_cluster_parameter_invocation.cpp195
-rw-r--r--src/mongo/db/commands/get_cluster_parameter_invocation.h61
-rw-r--r--src/mongo/db/s/SConscript4
-rw-r--r--src/mongo/idl/SConscript16
-rw-r--r--src/mongo/idl/cluster_server_parameter_refresher.cpp207
-rw-r--r--src/mongo/idl/cluster_server_parameter_refresher.h76
-rw-r--r--src/mongo/idl/cluster_server_parameter_refresher.idl48
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/commands/SConscript2
-rw-r--r--src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp132
-rw-r--r--src/mongo/s/mongos_main.cpp5
13 files changed, 634 insertions, 194 deletions
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index ceaa29595f8..073190f124e 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -587,6 +587,7 @@ env.Library(
'$BUILD_DIR/mongo/db/transaction_api',
'$BUILD_DIR/mongo/idl/idl_parser',
'$BUILD_DIR/mongo/util/net/ssl_manager',
+ 'cluster_server_parameter_commands_invocation',
'core',
'create_command',
'kill_common',
@@ -597,7 +598,6 @@ env.Library(
'rwc_defaults_commands',
'server_status',
'servers',
- 'set_cluster_parameter_invocation',
'set_feature_compatibility_version_idl',
'set_index_commit_quorum_idl',
'set_user_write_block_mode_idl',
@@ -611,13 +611,15 @@ env.Library(
)
env.Library(
- target='set_cluster_parameter_invocation',
+ target='cluster_server_parameter_commands_invocation',
source=[
+ 'get_cluster_parameter_invocation.cpp',
'set_cluster_parameter_invocation.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/audit',
+ '$BUILD_DIR/mongo/s/grid',
'$BUILD_DIR/mongo/s/write_ops/cluster_write_ops',
'cluster_server_parameter_cmds_idl',
],
@@ -821,11 +823,11 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/db/repl/storage_interface_impl",
"$BUILD_DIR/mongo/db/service_context_d_test_fixture",
'$BUILD_DIR/mongo/idl/idl_parser',
+ "cluster_server_parameter_commands_invocation",
"core",
"create_command",
"mongod",
"servers",
- "set_cluster_parameter_invocation",
"standalone",
],
)
diff --git a/src/mongo/db/commands/get_cluster_parameter_command.cpp b/src/mongo/db/commands/get_cluster_parameter_command.cpp
index d20ba275743..9a3ac246e23 100644
--- a/src/mongo/db/commands/get_cluster_parameter_command.cpp
+++ b/src/mongo/db/commands/get_cluster_parameter_command.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
+#include "mongo/db/commands/get_cluster_parameter_invocation.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/idl/cluster_server_parameter_gen.h"
#include "mongo/logv2/log.h"
@@ -68,11 +69,6 @@ public:
using InvocationBase::InvocationBase;
Reply typedRun(OperationContext* opCtx) {
- uassert(
- ErrorCodes::IllegalOperation,
- "featureFlagClusterWideConfig not enabled",
- gFeatureFlagClusterWideConfig.isEnabled(serverGlobalParams.featureCompatibility));
-
// TODO SERVER-65249: This will eventually be made specific to the parameter being set
// so that some parameters will be able to use getClusterParameter even on standalones.
uassert(ErrorCodes::IllegalOperation,
@@ -80,71 +76,8 @@ public:
repl::ReplicationCoordinator::get(opCtx)->getReplicationMode() !=
repl::ReplicationCoordinator::modeNone);
- const stdx::variant<std::string, std::vector<std::string>>& cmdBody =
- request().getCommandParameter();
- ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
- std::vector<BSONObj> parameterValues;
- std::vector<std::string> parameterNames;
-
- audit::logGetClusterParameter(opCtx->getClient(), cmdBody);
-
- // For each parameter, generate a BSON representation of it and retrieve its name.
- auto makeBSON = [&](ServerParameter* requestedParameter) {
- // Skip any disabled cluster parameters.
- if (requestedParameter->isEnabled()) {
- BSONObjBuilder bob;
- requestedParameter->append(opCtx, bob, requestedParameter->name());
- parameterValues.push_back(bob.obj());
- parameterNames.push_back(requestedParameter->name());
- }
- };
-
- stdx::visit(
- visit_helper::Overloaded{
- [&](const std::string& strParameterName) {
- if (strParameterName == "*"_sd) {
- // Retrieve all cluster parameter values.
- Map clusterParameterMap = clusterParameters->getMap();
- parameterValues.reserve(clusterParameterMap.size());
- parameterNames.reserve(clusterParameterMap.size());
- for (const auto& param : clusterParameterMap) {
- makeBSON(param.second);
- }
- } else {
- // Any other string must correspond to a single parameter name. Return
- // an error if a disabled cluster parameter is explicitly requested.
- ServerParameter* sp = clusterParameters->get(strParameterName);
- uassert(ErrorCodes::BadValue,
- str::stream() << "Server parameter: '" << strParameterName
- << "' is currently disabled",
- sp->isEnabled());
- makeBSON(sp);
- }
- },
- [&](const std::vector<std::string>& listParameterNames) {
- uassert(ErrorCodes::BadValue,
- "Must supply at least one cluster server parameter name to "
- "getClusterParameter",
- listParameterNames.size() > 0);
- parameterValues.reserve(listParameterNames.size());
- parameterNames.reserve(listParameterNames.size());
- for (const auto& requestedParameterName : listParameterNames) {
- ServerParameter* sp = clusterParameters->get(requestedParameterName);
- uassert(ErrorCodes::BadValue,
- str::stream() << "Server parameter: '" << requestedParameterName
- << "' is currently disabled'",
- sp->isEnabled());
- makeBSON(sp);
- }
- }},
- cmdBody);
-
- LOGV2_DEBUG(6226100,
- 2,
- "Retrieved parameter values for cluster server parameters",
- "parameterNames"_attr = parameterNames);
-
- return Reply(parameterValues);
+ GetClusterParameterInvocation invocation;
+ return invocation.getCachedParameters(opCtx, request());
}
private:
diff --git a/src/mongo/db/commands/get_cluster_parameter_invocation.cpp b/src/mongo/db/commands/get_cluster_parameter_invocation.cpp
new file mode 100644
index 00000000000..b95acf4896f
--- /dev/null
+++ b/src/mongo/db/commands/get_cluster_parameter_invocation.cpp
@@ -0,0 +1,195 @@
+/**
+ * Copyright (C) 2022-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/db/audit.h"
+#include "mongo/db/commands/get_cluster_parameter_invocation.h"
+#include "mongo/idl/cluster_server_parameter_gen.h"
+#include "mongo/logv2/log.h"
+#include "mongo/s/grid.h"
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand
+
+namespace mongo {
+
+std::pair<std::vector<std::string>, std::vector<BSONObj>>
+GetClusterParameterInvocation::retrieveRequestedParameters(OperationContext* opCtx,
+ const CmdBody& cmdBody) {
+ uassert(ErrorCodes::IllegalOperation,
+ "featureFlagClusterWideConfig not enabled",
+ gFeatureFlagClusterWideConfig.isEnabled(serverGlobalParams.featureCompatibility));
+
+ ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
+ std::vector<std::string> parameterNames;
+ std::vector<BSONObj> parameterValues;
+
+ audit::logGetClusterParameter(opCtx->getClient(), cmdBody);
+
+ // For each parameter, generate a BSON representation of it and retrieve its name.
+ auto makeBSON = [&](ServerParameter* requestedParameter) {
+ // Skip any disabled cluster parameters.
+ if (requestedParameter->isEnabled()) {
+ BSONObjBuilder bob;
+ requestedParameter->append(opCtx, bob, requestedParameter->name());
+ parameterValues.push_back(bob.obj().getOwned());
+ parameterNames.push_back(requestedParameter->name());
+ }
+ };
+
+ stdx::visit(
+ visit_helper::Overloaded{
+ [&](const std::string& strParameterName) {
+ if (strParameterName == "*"_sd) {
+ // Retrieve all cluster parameter values.
+ Map clusterParameterMap = clusterParameters->getMap();
+ parameterValues.reserve(clusterParameterMap.size());
+ parameterNames.reserve(clusterParameterMap.size());
+ for (const auto& param : clusterParameterMap) {
+ makeBSON(param.second);
+ }
+ } else {
+ // Any other string must correspond to a single parameter name. Return
+ // an error if a disabled cluster parameter is explicitly requested.
+ ServerParameter* sp = clusterParameters->get(strParameterName);
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Server parameter: '" << strParameterName
+ << "' is currently disabled",
+ sp->isEnabled());
+ makeBSON(sp);
+ }
+ },
+ [&](const std::vector<std::string>& listParameterNames) {
+ uassert(ErrorCodes::BadValue,
+ "Must supply at least one cluster server parameter name to "
+ "getClusterParameter",
+ listParameterNames.size() > 0);
+ parameterValues.reserve(listParameterNames.size());
+ parameterNames.reserve(listParameterNames.size());
+ for (const auto& requestedParameterName : listParameterNames) {
+ ServerParameter* sp = clusterParameters->get(requestedParameterName);
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Server parameter: '" << requestedParameterName
+ << "' is currently disabled'",
+ sp->isEnabled());
+ makeBSON(sp);
+ }
+ }},
+ cmdBody);
+
+ return {std::move(parameterNames), std::move(parameterValues)};
+}
+
+GetClusterParameterInvocation::Reply GetClusterParameterInvocation::getCachedParameters(
+ OperationContext* opCtx, const GetClusterParameter& request) {
+ const CmdBody& cmdBody = request.getCommandParameter();
+
+ auto [parameterNames, parameterValues] = retrieveRequestedParameters(opCtx, cmdBody);
+
+ LOGV2_DEBUG(6226100,
+ 2,
+ "Retrieved parameter values for cluster server parameters",
+ "parameterNames"_attr = parameterNames);
+
+ return Reply(parameterValues);
+}
+
+GetClusterParameterInvocation::Reply GetClusterParameterInvocation::getDurableParameters(
+ OperationContext* opCtx, const GetClusterParameter& request) {
+ auto configServers = Grid::get(opCtx)->shardRegistry()->getConfigShard();
+
+ // Create the query document such that all documents in config.clusterParmeters with _id
+ // in the requested list of ServerParameters are returned.
+ const CmdBody& cmdBody = request.getCommandParameter();
+ ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
+
+ BSONObjBuilder queryDocBuilder;
+ BSONObjBuilder inObjBuilder = queryDocBuilder.subobjStart("_id"_sd);
+ BSONArrayBuilder parameterNameBuilder = inObjBuilder.subarrayStart("$in"_sd);
+
+ auto [requestedParameterNames, parameterValues] = retrieveRequestedParameters(opCtx, cmdBody);
+
+ for (const auto& parameterValue : parameterValues) {
+ parameterNameBuilder.append(parameterValue["_id"_sd].String());
+ }
+
+ parameterNameBuilder.doneFast();
+ inObjBuilder.doneFast();
+
+ // Perform the majority read on the config server primary.
+ BSONObj query = queryDocBuilder.obj();
+ LOGV2_DEBUG(6226101, 2, "Querying config servers for cluster parameters", "query"_attr = query);
+ auto findResponse = uassertStatusOK(
+ configServers->exhaustiveFindOnConfig(opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ repl::ReadConcernLevel::kMajorityReadConcern,
+ NamespaceString::kClusterParametersNamespace,
+ query,
+ BSONObj(),
+ boost::none));
+
+ // Any parameters that are not included in the response don't have a cluster parameter
+ // document yet, which means they still are using the default value.
+ std::vector<BSONObj> retrievedParameters = std::move(findResponse.docs);
+ if (retrievedParameters.size() < requestedParameterNames.size()) {
+ std::vector<std::string> onDiskParameterNames;
+ onDiskParameterNames.reserve(retrievedParameters.size());
+ std::transform(
+ retrievedParameters.begin(),
+ retrievedParameters.end(),
+ std::back_inserter(onDiskParameterNames),
+ [&](const auto& onDiskParameter) { return onDiskParameter["_id"_sd].String(); });
+
+ // Sort and find the set difference of the requested parameters and the parameters
+ // returned.
+ std::vector<std::string> defaultParameterNames;
+
+ defaultParameterNames.reserve(requestedParameterNames.size() - onDiskParameterNames.size());
+
+ std::sort(onDiskParameterNames.begin(), onDiskParameterNames.end());
+ std::sort(requestedParameterNames.begin(), requestedParameterNames.end());
+ std::set_difference(requestedParameterNames.begin(),
+ requestedParameterNames.end(),
+ onDiskParameterNames.begin(),
+ onDiskParameterNames.end(),
+ std::back_inserter(defaultParameterNames));
+
+ for (const auto& defaultParameterName : defaultParameterNames) {
+ auto defaultParameter = clusterParameters->get(defaultParameterName);
+ BSONObjBuilder bob;
+ defaultParameter->append(opCtx, bob, defaultParameterName);
+ retrievedParameters.push_back(bob.obj());
+ }
+ }
+
+ return Reply(retrievedParameters);
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/commands/get_cluster_parameter_invocation.h b/src/mongo/db/commands/get_cluster_parameter_invocation.h
new file mode 100644
index 00000000000..66b63737c27
--- /dev/null
+++ b/src/mongo/db/commands/get_cluster_parameter_invocation.h
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2022-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.
+ */
+
+#pragma once
+
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
+#include "mongo/idl/server_parameter.h"
+
+namespace mongo {
+
+class GetClusterParameterInvocation {
+public:
+ using Request = GetClusterParameter;
+ using Reply = GetClusterParameter::Reply;
+ using Map = ServerParameterSet::Map;
+ using CmdBody = stdx::variant<std::string, std::vector<std::string>>;
+
+ GetClusterParameterInvocation() = default;
+
+ // Retrieves in-memory parameters. Used by mongod getClusterParameter and mongoses
+ // with featureFlagClusterWideConfigM2 enabled.
+ Reply getCachedParameters(OperationContext* opCtx, const GetClusterParameter& request);
+
+ // Retrieves durable cluster server parameters from config server. Used by mongoses with
+ // featureFlagClusterWideConfigM2 disabled.
+ Reply getDurableParameters(OperationContext* opCtx, const GetClusterParameter& request);
+
+private:
+ // Parses the command body and retrieves the BSON representation and names of the requested
+ // cluster parameters.
+ std::pair<std::vector<std::string>, std::vector<BSONObj>> retrieveRequestedParameters(
+ OperationContext* opCtx, const CmdBody& cmdBody);
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index e0cf8313b31..6fbd14c7300 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -285,8 +285,8 @@ env.Library(
'$BUILD_DIR/mongo/db/audit',
'$BUILD_DIR/mongo/db/catalog/collection_options',
'$BUILD_DIR/mongo/db/catalog_raii',
+ '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_commands_invocation',
'$BUILD_DIR/mongo/db/commands/mongod_fcv',
- '$BUILD_DIR/mongo/db/commands/set_cluster_parameter_invocation',
'$BUILD_DIR/mongo/db/commands/set_feature_compatibility_version_idl',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/concurrency/exception_util',
@@ -447,12 +447,12 @@ env.Library(
'$BUILD_DIR/mongo/db/bson/dotted_path_support',
'$BUILD_DIR/mongo/db/catalog/catalog_helpers',
'$BUILD_DIR/mongo/db/cloner',
+ '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_commands_invocation',
'$BUILD_DIR/mongo/db/commands/core',
'$BUILD_DIR/mongo/db/commands/create_command',
'$BUILD_DIR/mongo/db/commands/mongod_fcv',
'$BUILD_DIR/mongo/db/commands/rename_collection_idl',
'$BUILD_DIR/mongo/db/commands/server_status',
- '$BUILD_DIR/mongo/db/commands/set_cluster_parameter_invocation',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/db/commands/txn_cmd_request',
'$BUILD_DIR/mongo/db/fle_crud',
diff --git a/src/mongo/idl/SConscript b/src/mongo/idl/SConscript
index 6ac300aaae0..df82f0216e1 100644
--- a/src/mongo/idl/SConscript
+++ b/src/mongo/idl/SConscript
@@ -92,6 +92,22 @@ env.Library(
)
env.Library(
+ target='cluster_server_parameter_refresher',
+ source=[
+ 'cluster_server_parameter_refresher.cpp',
+ 'cluster_server_parameter_refresher.idl',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/audit',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/s/grid',
+ 'cluster_server_parameter',
+ ],
+)
+
+env.Library(
target='cluster_server_parameter_test_parameter',
source=[
'cluster_server_parameter_test.idl',
diff --git a/src/mongo/idl/cluster_server_parameter_refresher.cpp b/src/mongo/idl/cluster_server_parameter_refresher.cpp
new file mode 100644
index 00000000000..42f49040305
--- /dev/null
+++ b/src/mongo/idl/cluster_server_parameter_refresher.cpp
@@ -0,0 +1,207 @@
+/**
+ * Copyright (C) 2022-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/idl/cluster_server_parameter_refresher.h"
+
+#include "mongo/db/audit.h"
+#include "mongo/idl/cluster_server_parameter_refresher_gen.h"
+#include "mongo/logv2/log.h"
+#include "mongo/s/grid.h"
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
+
+namespace mongo {
+namespace {
+
+const auto getClusterServerParameterRefresher =
+ ServiceContext::declareDecoration<std::unique_ptr<ClusterServerParameterRefresher>>();
+
+Seconds loadInterval() {
+ return Seconds(clusterServerParameterRefreshIntervalSecs.load());
+}
+
+StatusWith<std::vector<BSONObj>> getClusterParametersFromConfigServer(
+ OperationContext* opCtx, const LogicalTime& latestTime) {
+ BSONObjBuilder queryObjBuilder;
+ BSONObjBuilder clusterParameterTimeObjBuilder =
+ queryObjBuilder.subobjStart("clusterParameterTime"_sd);
+ clusterParameterTimeObjBuilder.appendTimestamp("$gt"_sd, latestTime.asTimestamp().asInt64());
+ clusterParameterTimeObjBuilder.doneFast();
+
+ BSONObj query = queryObjBuilder.obj();
+
+ // Attempt to retrieve cluster parameter documents from the config server.
+ // exhaustiveFindOnConfig makes up to 3 total attempts if it receives a retriable error before
+ // giving up.
+ LOGV2_DEBUG(6226404, 3, "Retrieving cluster server parameters from config server");
+ auto configServers = Grid::get(opCtx)->shardRegistry()->getConfigShard();
+ auto swFindResponse =
+ configServers->exhaustiveFindOnConfig(opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ repl::ReadConcernLevel::kMajorityReadConcern,
+ NamespaceString::kClusterParametersNamespace,
+ query,
+ BSONObj(),
+ boost::none);
+
+ // If the error is not retriable or persists beyond the max number of retry attempts, give up
+ // and throw an error.
+ if (!swFindResponse.isOK()) {
+ return swFindResponse.getStatus();
+ }
+
+ return swFindResponse.getValue().docs;
+}
+
+} // namespace
+
+Status clusterServerParameterRefreshIntervalSecsNotify(const int& newValue) {
+ LOGV2_DEBUG(6226400,
+ 5,
+ "Set clusterServerParameterRefresher interval seconds",
+ "clusterServerParameterRefreshIntervalSecs"_attr = loadInterval());
+ if (hasGlobalServiceContext()) {
+ auto service = getGlobalServiceContext();
+ if (getClusterServerParameterRefresher(service)) {
+ getClusterServerParameterRefresher(service)->setPeriod(loadInterval());
+ }
+ }
+
+ return Status::OK();
+}
+
+ClusterServerParameterRefresher* ClusterServerParameterRefresher::get(OperationContext* opCtx) {
+ return get(opCtx->getServiceContext());
+}
+
+ClusterServerParameterRefresher* ClusterServerParameterRefresher::get(ServiceContext* serviceCtx) {
+ return getClusterServerParameterRefresher(serviceCtx).get();
+}
+
+void ClusterServerParameterRefresher::setPeriod(Milliseconds period) {
+ _job->setPeriod(period);
+}
+
+Status ClusterServerParameterRefresher::refreshParameters(OperationContext* opCtx) {
+ // Query the config servers for all cluster parameter documents with
+ // clusterParameterTime greater than the largest in-memory timestamp.
+ auto swClusterParameterDocs =
+ getClusterParametersFromConfigServer(opCtx, _latestClusterParameterTime);
+ if (!swClusterParameterDocs.isOK()) {
+ LOGV2_WARNING(6226401,
+ "Could not refresh cluster server parameters from config servers. Will retry "
+ "after refresh interval elapses",
+ "clusterServerParameterRefreshIntervalSecs"_attr = loadInterval(),
+ "reason"_attr = swClusterParameterDocs.getStatus().reason());
+ return swClusterParameterDocs.getStatus();
+ }
+
+ // Set each in-memory cluster parameter that was returned in the response. Then, advance the
+ // latest clusterParameterTime to the latest one returned if all of the cluster parameters are
+ // successfully set in-memory.
+ Timestamp latestTime;
+ bool isSuccessful = true;
+ Status setStatus = Status::OK();
+ ServerParameterSet* clusterParameterCache = ServerParameterSet::getClusterParameterSet();
+ std::vector<BSONObj> clusterParameterDocs = swClusterParameterDocs.getValue();
+ std::vector<BSONObj> updatedParameters;
+ updatedParameters.reserve(clusterParameterDocs.size());
+
+ for (const auto& clusterParameterDoc : clusterParameterDocs) {
+ Timestamp clusterParameterTime = clusterParameterDoc["clusterParameterTime"_sd].timestamp();
+ latestTime = (clusterParameterTime > latestTime) ? clusterParameterTime : latestTime;
+
+ auto clusterParameterName = clusterParameterDoc["_id"_sd].String();
+ ServerParameter* sp = clusterParameterCache->get(clusterParameterName);
+
+ BSONObjBuilder oldClusterParameterBob;
+ sp->append(opCtx, oldClusterParameterBob, clusterParameterName);
+
+ setStatus = sp->set(clusterParameterDoc);
+ if (!setStatus.isOK()) {
+ LOGV2_WARNING(6226402,
+ "Could not set in-memory cluster server parameter",
+ "parameter"_attr = clusterParameterName,
+ "reason"_attr = setStatus.reason());
+ isSuccessful = false;
+ }
+
+ BSONObjBuilder updatedClusterParameterBob;
+ sp->append(opCtx, updatedClusterParameterBob, clusterParameterName);
+ BSONObj updatedClusterParameterBSON = updatedClusterParameterBob.obj().getOwned();
+
+ audit::logUpdateCachedClusterParameter(opCtx->getClient(),
+ oldClusterParameterBob.obj().getOwned(),
+ updatedClusterParameterBSON);
+
+ updatedParameters.emplace_back(
+ updatedClusterParameterBSON.removeField("clusterParameterTime"_sd));
+ }
+
+ if (isSuccessful) {
+ _latestClusterParameterTime = LogicalTime(latestTime);
+ LOGV2_DEBUG(6226403,
+ 3,
+ "Updated cluster server parameters",
+ "clusterParameterDocuments"_attr = updatedParameters);
+ }
+
+ return setStatus;
+}
+
+void ClusterServerParameterRefresher::start(ServiceContext* serviceCtx, OperationContext* opCtx) {
+ auto refresher = std::make_unique<ClusterServerParameterRefresher>();
+
+ auto periodicRunner = serviceCtx->getPeriodicRunner();
+ invariant(periodicRunner);
+
+ PeriodicRunner::PeriodicJob job(
+ "ClusterServerParameterRefresher",
+ [serviceCtx](Client* client) { getClusterServerParameterRefresher(serviceCtx)->run(); },
+ loadInterval());
+
+ refresher->_job = std::make_unique<PeriodicJobAnchor>(periodicRunner->makeJob(std::move(job)));
+
+ // Make sure the invalidator is moved to the service context by the time we call start()
+ getClusterServerParameterRefresher(serviceCtx) = std::move(refresher);
+ getClusterServerParameterRefresher(serviceCtx)->_job->start();
+}
+
+void ClusterServerParameterRefresher::run() {
+ auto opCtx = cc().makeOperationContext();
+ auto status = refreshParameters(opCtx.get());
+ if (!status.isOK()) {
+ LOGV2_DEBUG(
+ 6226405, 1, "Cluster server parameter refresh failed", "reason"_attr = status.reason());
+ }
+}
+
+} // namespace mongo
diff --git a/src/mongo/idl/cluster_server_parameter_refresher.h b/src/mongo/idl/cluster_server_parameter_refresher.h
new file mode 100644
index 00000000000..b1b3397e501
--- /dev/null
+++ b/src/mongo/idl/cluster_server_parameter_refresher.h
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2022-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.
+ */
+#pragma once
+
+#include "mongo/db/operation_context.h"
+#include "mongo/db/service_context.h"
+
+namespace mongo {
+
+/**
+ * Runs a background job on mongos only that periodically refreshes its in-memory cache of cluster
+ * server parameters with updated values from the config servers.
+ */
+class ClusterServerParameterRefresher {
+public:
+ ClusterServerParameterRefresher() = default;
+
+ static ClusterServerParameterRefresher* get(OperationContext* opCtx);
+ static ClusterServerParameterRefresher* get(ServiceContext* serviceCtx);
+
+ /**
+ * Create a new ClusterServerParameterRefresher as a decorator on the service context
+ * and start the background job.
+ */
+ static void start(ServiceContext* serviceCtx, OperationContext* opCtx);
+
+ /**
+ * Refreshes all cluster server parameters that have been updated on the config servers since
+ * _latestClusterParameterTime. Called periodically in the run method, which executes in a
+ * background thread. Also called in-line during getClusterParameter on mongos to ensure that
+ * cached values returned are up-to-date.
+ */
+ Status refreshParameters(OperationContext* opCtx);
+
+ /**
+ * Set the period of the background job. This should only be used internally (by the
+ * setParameter).
+ */
+ void setPeriod(Milliseconds period);
+
+private:
+ void run();
+
+ std::unique_ptr<PeriodicJobAnchor> _job;
+ LogicalTime _latestClusterParameterTime = LogicalTime::kUninitialized;
+};
+
+Status clusterServerParameterRefreshIntervalSecsNotify(const int& newValue);
+
+} // namespace mongo
diff --git a/src/mongo/idl/cluster_server_parameter_refresher.idl b/src/mongo/idl/cluster_server_parameter_refresher.idl
new file mode 100644
index 00000000000..6609b83f544
--- /dev/null
+++ b/src/mongo/idl/cluster_server_parameter_refresher.idl
@@ -0,0 +1,48 @@
+# Copyright (C) 2022-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"
+ cpp_includes:
+ - "mongo/idl/cluster_server_parameter_refresher.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+server_parameters:
+ clusterServerParameterRefreshIntervalSecs:
+ description: >
+ On a mongos instance, specifies the interval (in seconds) at which the mongos instance
+ refreshes its in-memory cache of cluster server parameters.
+ cpp_varname: clusterServerParameterRefreshIntervalSecs
+ cpp_vartype: AtomicWord<int>
+ set_at: [startup, runtime]
+ default: 30
+ on_update: clusterServerParameterRefreshIntervalSecsNotify
+ validator:
+ gte: 1
+ lte: 86400
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index ac21f54fe9c..2ad44fbf093 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -539,6 +539,7 @@ env.Library(
'$BUILD_DIR/mongo/db/service_liaison_mongos',
'$BUILD_DIR/mongo/db/session_catalog',
'$BUILD_DIR/mongo/db/startup_warnings_common',
+ '$BUILD_DIR/mongo/idl/cluster_server_parameter_refresher',
'$BUILD_DIR/mongo/transport/service_entry_point',
'$BUILD_DIR/mongo/transport/transport_layer_manager',
'$BUILD_DIR/mongo/util/latch_analyzer'
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript
index 543fa0a59b8..d83d9c5c638 100644
--- a/src/mongo/s/commands/SConscript
+++ b/src/mongo/s/commands/SConscript
@@ -104,6 +104,7 @@ env.Library(
'$BUILD_DIR/mongo/db/auth/auth_checks',
'$BUILD_DIR/mongo/db/change_stream_options_manager',
'$BUILD_DIR/mongo/db/commands/cluster_server_parameter_cmds_idl',
+ '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_commands_invocation',
'$BUILD_DIR/mongo/db/commands/core',
'$BUILD_DIR/mongo/db/commands/create_command',
'$BUILD_DIR/mongo/db/commands/current_op_common',
@@ -143,6 +144,7 @@ env.Library(
'$BUILD_DIR/mongo/db/views/views',
'$BUILD_DIR/mongo/executor/async_multicaster',
'$BUILD_DIR/mongo/executor/async_request_executor',
+ '$BUILD_DIR/mongo/idl/cluster_server_parameter_refresher',
'$BUILD_DIR/mongo/idl/server_parameter',
'$BUILD_DIR/mongo/rpc/rewrite_state_change_errors',
'$BUILD_DIR/mongo/s/load_balancer_support',
diff --git a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp
index a86e662c947..3e741c4071b 100644
--- a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp
+++ b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp
@@ -34,7 +34,9 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
+#include "mongo/db/commands/get_cluster_parameter_invocation.h"
#include "mongo/idl/cluster_server_parameter_gen.h"
+#include "mongo/idl/cluster_server_parameter_refresher.h"
#include "mongo/logv2/log.h"
#include "mongo/s/cluster_commands_helpers.h"
#include "mongo/s/grid.h"
@@ -61,7 +63,7 @@ public:
}
std::string help() const override {
- return "Get majority-written cluster parameter value(s) from the config servers";
+ return "Refresh and get cached cluster server parameter value from mongos.";
}
class Invocation final : public InvocationBase {
@@ -69,126 +71,18 @@ public:
using InvocationBase::InvocationBase;
Reply typedRun(OperationContext* opCtx) {
- uassert(
- ErrorCodes::IllegalOperation,
- "featureFlagClusterWideConfig not enabled",
- gFeatureFlagClusterWideConfig.isEnabled(serverGlobalParams.featureCompatibility));
-
- // For now, the mongos implementation retrieves the names of the requested cluster
- // server parameters and queries them from the config.clusterParameters namespace on
- // the config servers. This may change after SERVER-62264, when cluster server
- // parameters will be cached on mongoses as well.
- auto configServers = Grid::get(opCtx)->shardRegistry()->getConfigShard();
-
- // Create the query document such that all documents in config.clusterParmeters with _id
- // in the requested list of ServerParameters are returned.
- const stdx::variant<std::string, std::vector<std::string>>& cmdBody =
- request().getCommandParameter();
- ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
-
- audit::logGetClusterParameter(opCtx->getClient(), cmdBody);
-
- std::vector<std::string> requestedParameterNames;
- BSONObjBuilder queryDocBuilder;
- BSONObjBuilder inObjBuilder = queryDocBuilder.subobjStart("_id"_sd);
- BSONArrayBuilder parameterNameBuilder = inObjBuilder.subarrayStart("$in"_sd);
-
- stdx::visit(
- visit_helper::Overloaded{
- [&](const std::string& strParameterName) {
- if (strParameterName == "*"_sd) {
- // Append all cluster parameter names.
- Map clusterParameterMap = clusterParameters->getMap();
- requestedParameterNames.reserve(clusterParameterMap.size());
- for (const auto& param : clusterParameterMap) {
- // Skip any disabled test parameters.
- if (param.second->isEnabled()) {
- parameterNameBuilder.append(param.first);
- requestedParameterNames.push_back(param.first);
- }
- }
- } else {
- // Return an error if a disabled cluster parameter is explicitly
- // requested.
- uassert(ErrorCodes::BadValue,
- str::stream() << "Server parameter: '" << strParameterName
- << "' is currently disabled'",
- clusterParameters->get(strParameterName)->isEnabled());
- parameterNameBuilder.append(strParameterName);
- requestedParameterNames.push_back(strParameterName);
- }
- },
- [&](const std::vector<std::string>& listParameterNames) {
- uassert(ErrorCodes::BadValue,
- "Must supply at least one cluster server parameter name to "
- "getClusterParameter",
- listParameterNames.size() > 0);
- requestedParameterNames.reserve(listParameterNames.size());
- for (const auto& requestedParameterName : listParameterNames) {
- // Return an error if a disabled cluster parameter is explicitly
- // requested.
- uassert(ErrorCodes::BadValue,
- str::stream() << "Server parameter: '" << requestedParameterName
- << "' is currently disabled'",
- clusterParameters->get(requestedParameterName)->isEnabled());
- parameterNameBuilder.append(requestedParameterName);
- requestedParameterNames.push_back(requestedParameterName);
- }
- }},
- cmdBody);
-
- parameterNameBuilder.doneFast();
- inObjBuilder.doneFast();
-
- // Perform the majority read on the config server primary.
- BSONObj query = queryDocBuilder.obj();
- LOGV2(6226101, "Querying config servers for cluster parameters", "query"_attr = query);
- auto findResponse = uassertStatusOK(configServers->exhaustiveFindOnConfig(
- opCtx,
- ReadPreferenceSetting{ReadPreference::PrimaryOnly},
- repl::ReadConcernLevel::kMajorityReadConcern,
- NamespaceString::kClusterParametersNamespace,
- query,
- BSONObj(),
- boost::none));
-
- // Any parameters that are not included in the response don't have a cluster parameter
- // document yet, which means they still are using the default value.
- std::vector<BSONObj> retrievedParameters = std::move(findResponse.docs);
- if (retrievedParameters.size() < requestedParameterNames.size()) {
- std::vector<std::string> onDiskParameterNames;
- onDiskParameterNames.reserve(retrievedParameters.size());
- std::transform(retrievedParameters.begin(),
- retrievedParameters.end(),
- std::back_inserter(onDiskParameterNames),
- [&](const auto& onDiskParameter) {
- return onDiskParameter["_id"_sd].String();
- });
-
- // Sort and find the set difference of the requested parameters and the parameters
- // returned.
- std::vector<std::string> defaultParameterNames;
-
- defaultParameterNames.reserve(requestedParameterNames.size() -
- onDiskParameterNames.size());
-
- std::sort(onDiskParameterNames.begin(), onDiskParameterNames.end());
- std::sort(requestedParameterNames.begin(), requestedParameterNames.end());
- std::set_difference(requestedParameterNames.begin(),
- requestedParameterNames.end(),
- onDiskParameterNames.begin(),
- onDiskParameterNames.end(),
- std::back_inserter(defaultParameterNames));
-
- for (const auto& defaultParameterName : defaultParameterNames) {
- auto defaultParameter = clusterParameters->get(defaultParameterName);
- BSONObjBuilder bob;
- defaultParameter->append(opCtx, bob, defaultParameterName);
- retrievedParameters.push_back(bob.obj());
- }
+ GetClusterParameterInvocation invocation;
+ if (gFeatureFlagClusterWideConfigM2.isEnabled(
+ serverGlobalParams.featureCompatibility)) {
+ // Refresh cached cluster server parameters via a majority read from the config
+ // servers.
+ uassertStatusOK(
+ ClusterServerParameterRefresher::get(opCtx)->refreshParameters(opCtx));
+
+ return invocation.getCachedParameters(opCtx, request());
}
- return Reply(retrievedParameters);
+ return invocation.getDurableParameters(opCtx, request());
}
private:
diff --git a/src/mongo/s/mongos_main.cpp b/src/mongo/s/mongos_main.cpp
index 8927a858ee0..0a1ffa80f9a 100644
--- a/src/mongo/s/mongos_main.cpp
+++ b/src/mongo/s/mongos_main.cpp
@@ -68,6 +68,7 @@
#include "mongo/db/vector_clock_metadata_hook.h"
#include "mongo/db/wire_version.h"
#include "mongo/executor/task_executor_pool.h"
+#include "mongo/idl/cluster_server_parameter_refresher.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/process_id.h"
#include "mongo/rpc/metadata/egress_metadata_hook_list.h"
@@ -764,6 +765,10 @@ ExitCode runMongosServer(ServiceContext* serviceContext) {
clusterCursorCleanupJob.go();
UserCacheInvalidator::start(serviceContext, opCtx);
+ if (gFeatureFlagClusterWideConfigM2.isEnabled(serverGlobalParams.featureCompatibility)) {
+ ClusterServerParameterRefresher::start(serviceContext, opCtx);
+ }
+
if (audit::initializeSynchronizeJob) {
audit::initializeSynchronizeJob(serviceContext);
}