diff options
Diffstat (limited to 'src/mongo/s/client')
| -rw-r--r-- | src/mongo/s/client/shard_registry.cpp | 97 | ||||
| -rw-r--r-- | src/mongo/s/client/shard_registry.h | 8 | ||||
| -rw-r--r-- | src/mongo/s/client/sharding_connection_hook.cpp | 8 | ||||
| -rw-r--r-- | src/mongo/s/client/sharding_network_connection_hook.cpp | 14 | ||||
| -rw-r--r-- | src/mongo/s/client/sharding_network_connection_hook.h | 6 |
5 files changed, 91 insertions, 42 deletions
diff --git a/src/mongo/s/client/shard_registry.cpp b/src/mongo/s/client/shard_registry.cpp index d722a9116ec..0b1691af82b 100644 --- a/src/mongo/s/client/shard_registry.cpp +++ b/src/mongo/s/client/shard_registry.cpp @@ -130,12 +130,8 @@ ShardRegistry::Cache::LookupResult ShardRegistry::_lookup(OperationContext* opCt // Check if we need to refresh from the configsvrs. If so, then do that and get the results, // otherwise (this is a lookup only to incorporate updated connection strings from the RSM), // then get the equivalent values from the previously cached data. - auto [returnData, - returnTopologyTime, - returnForceReloadIncrement, - removedShards, - fetchedFromConfigServers] = [&]() - -> std::tuple<ShardRegistryData, Timestamp, Increment, ShardRegistryData::ShardMap, bool> { + auto [returnData, returnTopologyTime, returnForceReloadIncrement, removedShards] = + [&]() -> std::tuple<ShardRegistryData, Timestamp, Increment, ShardRegistryData::ShardMap> { if (timeInStore.topologyTime > cachedData.getTime().topologyTime || timeInStore.forceReloadIncrement > cachedData.getTime().forceReloadIncrement) { auto [reloadedData, maxTopologyTime] = @@ -144,14 +140,12 @@ ShardRegistry::Cache::LookupResult ShardRegistry::_lookup(OperationContext* opCt auto [mergedData, removedShards] = ShardRegistryData::mergeExisting(*cachedData, reloadedData); - return { - mergedData, maxTopologyTime, timeInStore.forceReloadIncrement, removedShards, true}; + return {mergedData, maxTopologyTime, timeInStore.forceReloadIncrement, removedShards}; } else { return {*cachedData, cachedData.getTime().topologyTime, cachedData.getTime().forceReloadIncrement, - {}, - false}; + {}}; } }(); @@ -186,11 +180,6 @@ ShardRegistry::Cache::LookupResult ShardRegistry::_lookup(OperationContext* opCt } } - // The registry is "up" once there has been a successful lookup from the config servers. - if (fetchedFromConfigServers) { - _isUp.store(true); - } - Time returnTime{returnTopologyTime, rsmIncrementForConnStrings, returnForceReloadIncrement}; LOGV2_DEBUG(4620251, 2, @@ -218,9 +207,9 @@ void ShardRegistry::startupPeriodicReloader(OperationContext* opCtx) { AsyncTry([this] { LOGV2_DEBUG(22726, 1, "Reloading shardRegistry"); - return _reloadInternal(); + return _reloadAsyncNoRetry(); }) - .until([](auto sw) { + .until([](auto&& sw) { if (!sw.isOK()) { LOGV2(22727, "Error running periodic reload of shard registry", @@ -232,7 +221,7 @@ void ShardRegistry::startupPeriodicReloader(OperationContext* opCtx) { }) .withDelayBetweenIterations(kRefreshPeriod) // This call is optional. .on(_executor, CancellationToken::uncancelable()) - .getAsync([](auto sw) { + .getAsync([](auto&& sw) { LOGV2_DEBUG(22725, 1, "Exiting periodic shard registry reloader", @@ -295,6 +284,49 @@ StatusWith<std::shared_ptr<Shard>> ShardRegistry::getShard(OperationContext* opC return {ErrorCodes::ShardNotFound, str::stream() << "Shard " << shardId << " not found"}; } +SemiFuture<std::shared_ptr<Shard>> ShardRegistry::getShard(ExecutorPtr executor, + const ShardId& shardId) noexcept { + + // Fetch the shard registry data associated to the latest known topology time + return _getDataAsync() + .thenRunOn(executor) + .then([this, executor, shardId](auto&& cachedData) { + // First check if this is a non config shard lookup + if (auto shard = cachedData->findShard(shardId)) { + return SemiFuture<std::shared_ptr<Shard>>::makeReady(std::move(shard)); + } + + // then check if this is a config shard (this call is blocking in any case) + { + stdx::lock_guard<Latch> lk(_mutex); + if (auto shard = _configShardData.findShard(shardId)) { + return SemiFuture<std::shared_ptr<Shard>>::makeReady(std::move(shard)); + } + } + + // If the shard was not found, force reload the shard regitry data and try again. + // + // This is to cover the following scenario: + // 1. Primary of the replicaset fetch the list of shards and store it on disk + // 2. Primary crash before the latest VectorClock topology time is majority written to + // disk + // 3. A new primary with a stale ShardRegistry is elected and read the set of shards + // from disk and calls ShardRegistry::getShard + + return _reloadAsync() + .thenRunOn(executor) + .then([this, executor, shardId](auto&& cachedData) -> std::shared_ptr<Shard> { + auto shard = cachedData->findShard(shardId); + uassert(ErrorCodes::ShardNotFound, + str::stream() << "Shard " << shardId << " not found", + shard); + return shard; + }) + .semi(); + }) + .semi(); +} + std::vector<ShardId> ShardRegistry::getAllShardIds(OperationContext* opCtx) { auto shardIds = _getData(opCtx)->getAllShardIds(); if (shardIds.empty()) { @@ -380,8 +412,18 @@ std::unique_ptr<Shard> ShardRegistry::createConnection(const ConnectionString& c return _shardFactory->createUniqueShard(ShardId("<unnamed>"), connStr); } -bool ShardRegistry::isUp() const { - return _isUp.load(); +bool ShardRegistry::isUp() { + if (_isUp.load()) + return true; + + // Before the first lookup is completed, the latest cached value is either empty or it is + // associated to the default constructed time + const auto latestCached = _cache->peekLatestCached(_kSingleton); + if (latestCached && latestCached.getTime() != Time()) { + _isUp.store(true); + return true; + } + return false; } void ShardRegistry::toBSON(BSONObjBuilder* result) const { @@ -400,23 +442,26 @@ void ShardRegistry::toBSON(BSONObjBuilder* result) const { } void ShardRegistry::reload(OperationContext* opCtx) { + _reloadAsync().get(opCtx); +} + +SharedSemiFuture<ShardRegistry::Cache::ValueHandle> ShardRegistry::_reloadAsync() { if (MONGO_unlikely(TestingProctor::instance().isEnabled())) { // Some unit tests don't support running the reload's AsyncTry on the fixed executor. - _reloadInternal().get(opCtx); + return _reloadAsyncNoRetry(); } else { - AsyncTry([=]() mutable { return _reloadInternal(); }) + return AsyncTry([=]() mutable { return _reloadAsyncNoRetry(); }) .until([](auto sw) mutable { return sw.getStatus() != ErrorCodes::ReadConcernMajorityNotAvailableYet; }) .withBackoffBetweenIterations(kExponentialBackoff) - .on(Grid::get(opCtx)->getExecutorPool()->getFixedExecutor(), + .on(Grid::get(getGlobalServiceContext())->getExecutorPool()->getFixedExecutor(), CancellationToken::uncancelable()) - .semi() - .get(opCtx); + .share(); } } -SharedSemiFuture<ShardRegistry::Cache::ValueHandle> ShardRegistry::_reloadInternal() { +SharedSemiFuture<ShardRegistry::Cache::ValueHandle> ShardRegistry::_reloadAsyncNoRetry() { // Make the next acquire do a lookup. auto value = _forceReloadIncrement.addAndFetch(1); LOGV2_DEBUG(4620253, 2, "Forcing ShardRegistry reload", "newForceReloadIncrement"_attr = value); diff --git a/src/mongo/s/client/shard_registry.h b/src/mongo/s/client/shard_registry.h index 2c329f11b4c..aceb45db9d2 100644 --- a/src/mongo/s/client/shard_registry.h +++ b/src/mongo/s/client/shard_registry.h @@ -239,6 +239,9 @@ public: */ StatusWith<std::shared_ptr<Shard>> getShard(OperationContext* opCtx, const ShardId& shardId); + SemiFuture<std::shared_ptr<Shard>> getShard(ExecutorPtr executor, + const ShardId& shardId) noexcept; + /** * Returns a vector containing all known shard IDs. * The order of the elements is not guaranteed. @@ -272,7 +275,7 @@ public: * The ShardRegistry is "up" once a successful lookup from the config servers has been * completed. */ - bool isUp() const; + bool isUp(); void toBSON(BSONObjBuilder* result) const; @@ -438,7 +441,8 @@ private: void _initializeCacheIfNecessary() const; - SharedSemiFuture<Cache::ValueHandle> _reloadInternal(); + SharedSemiFuture<Cache::ValueHandle> _reloadAsync(); + SharedSemiFuture<Cache::ValueHandle> _reloadAsyncNoRetry(); /** * Factory to create shards. Never changed after startup so safe to access outside of _mutex. diff --git a/src/mongo/s/client/sharding_connection_hook.cpp b/src/mongo/s/client/sharding_connection_hook.cpp index 0a7374a240e..bc72c6ea064 100644 --- a/src/mongo/s/client/sharding_connection_hook.cpp +++ b/src/mongo/s/client/sharding_connection_hook.cpp @@ -73,14 +73,14 @@ void ShardingConnectionHook::onCreate(DBClientBase* conn) { if (conn->type() == ConnectionString::ConnectionType::kStandalone) { - BSONObj isMasterResponse; - if (!conn->runCommand("admin", BSON("ismaster" << 1), isMasterResponse)) { - uassertStatusOK(getStatusFromCommandResult(isMasterResponse)); + BSONObj helloResponse; + if (!conn->runCommand("admin", BSON("hello" << 1), helloResponse)) { + uassertStatusOK(getStatusFromCommandResult(helloResponse)); } long long configServerModeNumber; Status status = - bsonExtractIntegerField(isMasterResponse, "configsvr", &configServerModeNumber); + bsonExtractIntegerField(helloResponse, "configsvr", &configServerModeNumber); if (status == ErrorCodes::NoSuchKey) { // This isn't a config server we're talking to. diff --git a/src/mongo/s/client/sharding_network_connection_hook.cpp b/src/mongo/s/client/sharding_network_connection_hook.cpp index a6229316eaa..60368d2eb0f 100644 --- a/src/mongo/s/client/sharding_network_connection_hook.cpp +++ b/src/mongo/s/client/sharding_network_connection_hook.cpp @@ -48,12 +48,12 @@ namespace mongo { Status ShardingNetworkConnectionHook::validateHost( const HostAndPort& remoteHost, const BSONObj&, - const executor::RemoteCommandResponse& isMasterReply) { - return validateHostImpl(remoteHost, isMasterReply); + const executor::RemoteCommandResponse& helloReply) { + return validateHostImpl(remoteHost, helloReply); } Status ShardingNetworkConnectionHook::validateHostImpl( - const HostAndPort& remoteHost, const executor::RemoteCommandResponse& isMasterReply) { + const HostAndPort& remoteHost, const executor::RemoteCommandResponse& helloReply) { auto shard = Grid::get(getGlobalServiceContext())->shardRegistry()->getShardForHostNoReload(remoteHost); if (!shard) { @@ -62,11 +62,11 @@ Status ShardingNetworkConnectionHook::validateHostImpl( } long long configServerModeNumber; - auto status = bsonExtractIntegerField(isMasterReply.data, "configsvr", &configServerModeNumber); + auto status = bsonExtractIntegerField(helloReply.data, "configsvr", &configServerModeNumber); switch (status.code()) { case ErrorCodes::OK: { - // The ismaster response indicates remoteHost is a config server. + // The hello response indicates remoteHost is a config server. if (!shard->isConfig()) { return {ErrorCodes::InvalidOptions, str::stream() << "Surprised to discover that " << remoteHost.toString() @@ -75,7 +75,7 @@ Status ShardingNetworkConnectionHook::validateHostImpl( return Status::OK(); } case ErrorCodes::NoSuchKey: { - // The ismaster response indicates that remoteHost is not a config server, or that + // The hello response indicates that remoteHost is not a config server, or that // the config server is running a version prior to the 3.1 development series. if (!shard->isConfig()) { return Status::OK(); @@ -86,7 +86,7 @@ Status ShardingNetworkConnectionHook::validateHostImpl( << " does not believe it is a config server"}; } default: - // The ismaster response was malformed. + // The hello response was malformed. return status; } } diff --git a/src/mongo/s/client/sharding_network_connection_hook.h b/src/mongo/s/client/sharding_network_connection_hook.h index c77428e56d9..d3715dcec1b 100644 --- a/src/mongo/s/client/sharding_network_connection_hook.h +++ b/src/mongo/s/client/sharding_network_connection_hook.h @@ -45,18 +45,18 @@ public: /** * Checks that the given host is valid to be used in this sharded cluster, based on its - * isMaster response. + * "hello" response. */ Status validateHost(const HostAndPort& remoteHost, const BSONObj& request, - const executor::RemoteCommandResponse& isMasterReply) override; + const executor::RemoteCommandResponse& helloReply) override; /** * Implementation of validateHost can be called without a ShardingNetworkConnectionHook * instance. */ static Status validateHostImpl(const HostAndPort& remoteHost, - const executor::RemoteCommandResponse& isMasterReply); + const executor::RemoteCommandResponse& helloReply); /** * Makes a SetShardVersion request for initializing sharding information on the new connection. |
