From 5eea91ee17a4e4cbf339768d3494675142a18978 Mon Sep 17 00:00:00 2001 From: Tess Avitabile Date: Fri, 17 Jan 2020 15:39:42 +0000 Subject: SERVER-44520 Make mongo's isMaster wait maxAwaitTimeMS --- src/mongo/s/commands/cluster_is_master_cmd.cpp | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/mongo/s/commands/cluster_is_master_cmd.cpp') diff --git a/src/mongo/s/commands/cluster_is_master_cmd.cpp b/src/mongo/s/commands/cluster_is_master_cmd.cpp index af00e62bd09..ccd0d7d00d5 100644 --- a/src/mongo/s/commands/cluster_is_master_cmd.cpp +++ b/src/mongo/s/commands/cluster_is_master_cmd.cpp @@ -26,9 +26,11 @@ * exception statement from all source files in the program, then also delete * it in the license file. */ +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand #include "mongo/platform/basic.h" +#include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/sasl_mechanism_registry.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" @@ -38,7 +40,9 @@ #include "mongo/db/wire_version.h" #include "mongo/rpc/metadata/client_metadata.h" #include "mongo/rpc/metadata/client_metadata_ismaster.h" +#include "mongo/rpc/topology_version_gen.h" #include "mongo/transport/message_compressor_manager.h" +#include "mongo/util/log.h" #include "mongo/util/map_util.h" #include "mongo/util/net/socket_utils.h" #include "mongo/util/version.h" @@ -47,6 +51,13 @@ namespace mongo { MONGO_FAIL_POINT_DEFINE(waitInIsMaster); +TopologyVersion mongosTopologyVersion; + +MONGO_INITIALIZER(GenerateMongosTopologyVersion)(InitializerContext*) { + mongosTopologyVersion = TopologyVersion(OID::gen(), 0); + return Status::OK(); +} + namespace { class CmdIsMaster : public BasicCommand { @@ -112,6 +123,44 @@ public: opCtx->getClient(), std::move(swParseClientMetadata.getValue())); } + // If a client is following the awaitable isMaster protocol, maxAwaitTimeMS should be + // present if and only if topologyVersion is present in the request. + auto topologyVersionElement = cmdObj["topologyVersion"]; + auto maxAwaitTimeMSField = cmdObj["maxAwaitTimeMS"]; + if (topologyVersionElement && maxAwaitTimeMSField) { + auto clientTopologyVersion = TopologyVersion::parse( + IDLParserErrorContext("TopologyVersion"), topologyVersionElement.Obj()); + uassert(51758, + "topologyVersion must have a non-negative counter", + clientTopologyVersion.getCounter() >= 0); + + long long maxAwaitTimeMS; + uassertStatusOK(bsonExtractIntegerField(cmdObj, "maxAwaitTimeMS", &maxAwaitTimeMS)); + uassert(51759, "maxAwaitTimeMS must be a non-negative integer", maxAwaitTimeMS >= 0); + + LOG(3) << "Using maxAwaitTimeMS for awaitable isMaster protocol."; + + if (clientTopologyVersion.getProcessId() == mongosTopologyVersion.getProcessId()) { + uassert(51761, + str::stream() + << "Received a topology version with counter: " + << clientTopologyVersion.getCounter() + << " which is greater than the mongos topology version counter: " + << mongosTopologyVersion.getCounter(), + clientTopologyVersion.getCounter() == mongosTopologyVersion.getCounter()); + + // The topologyVersion never changes on a running mongos process, so just sleep for + // maxAwaitTimeMS. + opCtx->sleepFor(Milliseconds(maxAwaitTimeMS)); + } + } else { + uassert(51760, + (topologyVersionElement + ? "A request with a 'topologyVersion' must include 'maxAwaitTimeMS'" + : "A request with 'maxAwaitTimeMS' must include a 'topologyVersion'"), + !topologyVersionElement && !maxAwaitTimeMSField); + } + result.appendBool("ismaster", true); result.append("msg", "isdbgrid"); result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); @@ -138,6 +187,9 @@ public: auto& saslMechanismRegistry = SASLServerMechanismRegistry::get(opCtx->getServiceContext()); saslMechanismRegistry.advertiseMechanismNamesForUser(opCtx, cmdObj, &result); + BSONObjBuilder topologyVersionBuilder(result.subobjStart("topologyVersion")); + mongosTopologyVersion.serialize(&topologyVersionBuilder); + return true; } -- cgit v1.2.1