diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/catalog/drop_indexes.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/drop_indexes.idl | 37 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/shardsvr_drop_indexes_command.cpp | 220 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/cluster_commands_helpers.cpp | 1 | ||||
-rw-r--r-- | src/mongo/s/cluster_commands_helpers.h | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_drop_indexes_cmd.cpp | 110 | ||||
-rw-r--r-- | src/mongo/s/request_types/sharded_ddl_commands.idl | 11 | ||||
-rw-r--r-- | src/mongo/s/stale_shard_version_helpers.h | 8 |
11 files changed, 303 insertions, 111 deletions
diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp index 200fdf8ed0f..2c10eb005c5 100644 --- a/src/mongo/db/catalog/drop_indexes.cpp +++ b/src/mongo/db/catalog/drop_indexes.cpp @@ -282,7 +282,8 @@ std::vector<UUID> abortActiveIndexBuilders(OperationContext* opCtx, void dropReadyIndexes(OperationContext* opCtx, Collection* collection, const std::vector<std::string>& indexNames, - DropIndexesReply* reply) { + DropIndexesReply* reply, + bool forceDropShardKeyIndex) { invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X)); if (indexNames.empty()) { @@ -294,7 +295,7 @@ void dropReadyIndexes(OperationContext* opCtx, CollectionShardingState::get(opCtx, collection->ns())->getCollectionDescription(opCtx); if (indexNames.front() == "*") { - if (collDescription.isSharded()) { + if (collDescription.isSharded() && !forceDropShardKeyIndex) { indexCatalog->dropIndexes( opCtx, collection, @@ -561,7 +562,8 @@ DropIndexesReply dropIndexes(OperationContext* opCtx, // This is necessary to check shard version. OldClientContext ctx(opCtx, (*collection)->ns().ns()); - dropReadyIndexes(opCtx, collection->getWritableCollection(opCtx), indexNames, &reply); + dropReadyIndexes( + opCtx, collection->getWritableCollection(opCtx), indexNames, &reply, false); wunit.commit(); }); @@ -611,8 +613,11 @@ Status dropIndexesForApplyOps(OperationContext* opCtx, OldClientContext ctx(opCtx, nss.ns()); DropIndexesReply ignoredReply; - dropReadyIndexes( - opCtx, collection.getWritableCollection(opCtx), swIndexNames.getValue(), &ignoredReply); + dropReadyIndexes(opCtx, + collection.getWritableCollection(opCtx), + swIndexNames.getValue(), + &ignoredReply, + true); wunit.commit(); return Status::OK(); diff --git a/src/mongo/db/drop_indexes.idl b/src/mongo/db/drop_indexes.idl index a8e60f78a9f..ad6d9283536 100644 --- a/src/mongo/db/drop_indexes.idl +++ b/src/mongo/db/drop_indexes.idl @@ -50,20 +50,9 @@ structs: optional: true unstable: false -commands: - dropIndexes: - description: "Parser for the dropIndexes command" - command_name: dropIndexes - command_alias: deleteIndexes - namespace: concatenate_with_db - cpp_name: dropIndexes - strict: true - api_version: "1" - access_check: - simple: - privilege: - resource_pattern: exact_namespace - action_type: dropIndex + DropIndexesRequest: + description: dropIndexes command request + strict: false fields: index: description: An index name, or array of names, or "*" for all indexes, or an index @@ -85,5 +74,23 @@ commands: type: uuid description: "The expected UUID of the collection." optional: true - unstable: true + unstable: true + +commands: + dropIndexes: + description: "Parser for the dropIndexes command" + command_name: dropIndexes + command_alias: deleteIndexes + namespace: concatenate_with_db + cpp_name: dropIndexes + strict: true + api_version: "1" + access_check: + simple: + privilege: + resource_pattern: exact_namespace + action_type: dropIndex + inline_chained_structs: true + chained_structs: + DropIndexesRequest: DropIndexesRequest reply_type: DropIndexesReply diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index f6befa3d2c3..c1f953c72e0 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -416,6 +416,7 @@ env.Library( 'shardsvr_drop_collection_participant_command.cpp', 'shardsvr_drop_database_command.cpp', 'shardsvr_drop_database_participant_command.cpp', + 'shardsvr_drop_indexes_command.cpp', 'shardsvr_get_stats_for_balancing_command.cpp', 'shardsvr_merge_chunks_command.cpp', 'shardsvr_move_primary_command.cpp', diff --git a/src/mongo/db/s/shardsvr_drop_indexes_command.cpp b/src/mongo/db/s/shardsvr_drop_indexes_command.cpp new file mode 100644 index 00000000000..0c6d2d4260b --- /dev/null +++ b/src/mongo/db/s/shardsvr_drop_indexes_command.cpp @@ -0,0 +1,220 @@ +/** + * 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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding + +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/catalog/collection_catalog.h" +#include "mongo/db/commands.h" +#include "mongo/db/curop.h" +#include "mongo/db/s/database_sharding_state.h" +#include "mongo/db/s/dist_lock_manager.h" +#include "mongo/db/s/sharding_state.h" +#include "mongo/db/timeseries/timeseries_commands_conversion_helper.h" +#include "mongo/logv2/log.h" +#include "mongo/s/chunk_manager_targeter.h" +#include "mongo/s/cluster_commands_helpers.h" +#include "mongo/s/grid.h" +#include "mongo/s/request_types/sharded_ddl_commands_gen.h" +#include "mongo/s/stale_shard_version_helpers.h" + +namespace mongo { +namespace { + +struct StaleConfigRetryState { + std::set<ShardId> shardsWithSuccessResponses; + std::vector<AsyncRequestsSender::Response> shardSuccessResponses; +}; + +void updateStateForStaleConfigRetry(OperationContext* opCtx, + const RawResponsesResult& response, + StaleConfigRetryState* retryState) { + std::set<ShardId> okShardIds; + std::set_union(response.shardsWithSuccessResponses.begin(), + response.shardsWithSuccessResponses.end(), + retryState->shardsWithSuccessResponses.begin(), + retryState->shardsWithSuccessResponses.end(), + std::inserter(okShardIds, okShardIds.begin())); + + retryState->shardsWithSuccessResponses = std::move(okShardIds); + retryState->shardSuccessResponses = std::move(response.successResponses); +} + +class ShardsvrDropIndexesCommand final : public TypedCommand<ShardsvrDropIndexesCommand> { +public: + using Request = ShardsvrDropIndexes; + + bool skipApiVersionCheck() const override { + // Internal command (server to server). + return true; + } + + std::string help() const override { + return "Internal command. Do not call directly. Drops indexes."; + } + + bool adminOnly() const override { + return false; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } + + class Invocation final : public InvocationBase { + public: + using InvocationBase::InvocationBase; + + /** + * Intermediate wrapper to interface with ReplyBuilderInterface. + */ + class Response { + public: + Response(BSONObj obj) : _obj(std::move(obj)) {} + + void serialize(BSONObjBuilder* builder) const { + builder->appendElements(_obj); + } + + private: + const BSONObj _obj; + }; + + Response typedRun(OperationContext* opCtx); + + private: + NamespaceString ns() const override { + return request().getNamespace(); + } + + bool supportsWriteConcern() const override { + return true; + } + + void doCheckAuthorization(OperationContext* opCtx) const override { + uassert(ErrorCodes::Unauthorized, + "Unauthorized", + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)); + } + }; + +} shardsvrDropIndexesCommand; + +ShardsvrDropIndexesCommand::Invocation::Response ShardsvrDropIndexesCommand::Invocation::typedRun( + OperationContext* opCtx) { + uassertStatusOK(ShardingState::get(opCtx)->canAcceptShardedCommands()); + CommandHelpers::uassertCommandRunWithMajority(Request::kCommandName, opCtx->getWriteConcern()); + + // Since this operation is not directly writing locally we need to force its db profile level + // increase in order to be logged in "<db>.system.profile". + CurOp::get(opCtx)->raiseDbProfileLevel( + CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(ns().db())); + + DropIndexes dropIdxCmd(ns()); + dropIdxCmd.setDropIndexesRequest(request().getDropIndexesRequest()); + + const auto lockTimeout = [&]() -> Milliseconds { + if (auto sfp = globalFailPointRegistry().find("overrideDDLLockTimeout")->scoped(); + MONGO_unlikely(sfp.isActive())) { + if (auto timeoutElem = sfp.getData()["timeoutMillisecs"]; timeoutElem.ok()) { + const auto timeoutMillisecs = Milliseconds(timeoutElem.safeNumberLong()); + LOGV2(649100, "Overriding DDL lock timeout", "timeout"_attr = timeoutMillisecs); + return timeoutMillisecs; + } + } + return DistLockManager::kDefaultLockTimeout; + }(); + + auto distLockManager = DistLockManager::get(opCtx); + auto dbLocalLock = distLockManager->lockDirectLocally(opCtx, ns().db(), lockTimeout); + + // Check under the dbLock if this is still the primary shard for the database + DatabaseShardingState::checkIsPrimaryShardForDb(opCtx, ns().db()); + + auto nsLocalLock = distLockManager->lockDirectLocally(opCtx, ns().ns(), lockTimeout); + + StaleConfigRetryState retryState; + return shardVersionRetry(opCtx, Grid::get(opCtx)->catalogCache(), ns(), "dropIndexes", [&] { + // If the collection is sharded, we target only the primary shard and the shards that own + // chunks for the collection. + auto targeter = ChunkManagerTargeter(opCtx, ns()); + auto routingInfo = targeter.getRoutingInfo(); + + auto cmdToBeSent = dropIdxCmd.toBSON({}); + if (targeter.timeseriesNamespaceNeedsRewrite(ns())) { + cmdToBeSent = + timeseries::makeTimeseriesCommand(cmdToBeSent, + ns(), + DropIndexes::kCommandName, + DropIndexes::kIsTimeseriesNamespaceFieldName); + } + + cmdToBeSent = CommandHelpers::filterCommandRequestForPassthrough( + CommandHelpers::appendMajorityWriteConcern(cmdToBeSent)); + + auto shardResponses = + scatterGatherVersionedTargetByRoutingTableNoThrowOnStaleShardVersionErrors( + opCtx, + ns().db(), + targeter.getNS(), + routingInfo, + retryState.shardsWithSuccessResponses, + applyReadWriteConcern( + opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdToBeSent)), + ReadPreferenceSetting::get(opCtx), + Shard::RetryPolicy::kNotIdempotent, + BSONObj() /* query */, + BSONObj() /* collation */); + + // Append responses we've received from previous retries of this operation due to a stale + // config error. + shardResponses.insert(shardResponses.end(), + retryState.shardSuccessResponses.begin(), + retryState.shardSuccessResponses.end()); + + std::string errmsg; + BSONObjBuilder output; + const auto aggregateResponse = + appendRawResponses(opCtx, &errmsg, &output, std::move(shardResponses)); + + // If we have a stale config error, update the success shards for the upcoming retry. + if (!aggregateResponse.responseOK && aggregateResponse.firstStaleConfigError) { + updateStateForStaleConfigRetry(opCtx, aggregateResponse, &retryState); + uassertStatusOK(*aggregateResponse.firstStaleConfigError); + } + + CommandHelpers::appendSimpleCommandStatus(output, aggregateResponse.responseOK, errmsg); + return Response(output.obj()); + }); +} + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp index abe386549c5..8b0a2f512b7 100644 --- a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp +++ b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp @@ -247,10 +247,14 @@ DropIndexes makeTimeseriesDropIndexesCommand(OperationContext* opCtx, << " Command request: " << redact(origCmd.toBSON({})), bucketsIndexSpecWithStatus.isOK()); - return DropIndexes(ns, std::move(bucketsIndexSpecWithStatus.getValue())); + DropIndexes dropIndexCmd(ns); + dropIndexCmd.setDropIndexesRequest({std::move(bucketsIndexSpecWithStatus.getValue())}); + return dropIndexCmd; } - return DropIndexes(ns, origIndex); + DropIndexes dropIndexCmd(ns); + dropIndexCmd.setDropIndexesRequest(origIndex); + return dropIndexCmd; } } // namespace mongo::timeseries diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 7432c3a3b86..f8ee64d895c 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -233,6 +233,7 @@ env.Library( '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_cmds_idl', '$BUILD_DIR/mongo/db/commands/set_user_write_block_mode_idl', '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/index_commands_idl', '$BUILD_DIR/mongo/db/namespace_string', '$BUILD_DIR/mongo/db/query/query_request', '$BUILD_DIR/mongo/db/repl/optime', diff --git a/src/mongo/s/cluster_commands_helpers.cpp b/src/mongo/s/cluster_commands_helpers.cpp index 8a508f449f1..5c0469ab245 100644 --- a/src/mongo/s/cluster_commands_helpers.cpp +++ b/src/mongo/s/cluster_commands_helpers.cpp @@ -475,7 +475,6 @@ RawResponsesResult appendRawResponses( std::string* errmsg, BSONObjBuilder* output, const std::vector<AsyncRequestsSender::Response>& shardResponses) { - std::vector<AsyncRequestsSender::Response> successARSResponses; std::vector<std::pair<ShardId, BSONObj>> successResponsesReceived; std::vector<std::pair<ShardId, Status>> shardNotFoundErrorsReceived; diff --git a/src/mongo/s/cluster_commands_helpers.h b/src/mongo/s/cluster_commands_helpers.h index 1a9428c5547..f342b7f799e 100644 --- a/src/mongo/s/cluster_commands_helpers.h +++ b/src/mongo/s/cluster_commands_helpers.h @@ -235,7 +235,7 @@ AsyncRequestsSender::Response executeCommandAgainstShardWithMinKeyChunk( * string representation of all errors to 'errmsg.' * * ShardNotFound responses are not treated as errors if any shard returned success. We allow - * ShardNotFound errors to be ignored as errors since this node may not heave realized that a + * ShardNotFound errors to be ignored as errors since this node may not have realized that a * shard has been removed. * * Returns: diff --git a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp index 24f2f507137..28e3e74e7e4 100644 --- a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp @@ -32,49 +32,17 @@ #include "mongo/platform/basic.h" #include "mongo/db/commands.h" -#include "mongo/db/drop_indexes_gen.h" -#include "mongo/db/timeseries/timeseries_commands_conversion_helper.h" #include "mongo/logv2/log.h" #include "mongo/rpc/get_status_from_command_result.h" -#include "mongo/s/chunk_manager_targeter.h" #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" +#include "mongo/s/request_types/sharded_ddl_commands_gen.h" namespace mongo { namespace { constexpr auto kRawFieldName = "raw"_sd; -struct StaleConfigRetryState { - std::set<ShardId> shardsWithSuccessResponses; - std::vector<AsyncRequestsSender::Response> shardSuccessResponses; -}; - -const OperationContext::Decoration<std::unique_ptr<StaleConfigRetryState>> staleConfigRetryState = - OperationContext::declareDecoration<std::unique_ptr<StaleConfigRetryState>>(); - -StaleConfigRetryState createAndRetrieveStateFromStaleConfigRetry(OperationContext* opCtx) { - if (!staleConfigRetryState(opCtx)) { - staleConfigRetryState(opCtx) = std::make_unique<StaleConfigRetryState>(); - } - - return *staleConfigRetryState(opCtx); -} - -void updateStateForStaleConfigRetry(OperationContext* opCtx, - const StaleConfigRetryState& retryState, - const RawResponsesResult& response) { - std::set<ShardId> okShardIds; - std::set_union(response.shardsWithSuccessResponses.begin(), - response.shardsWithSuccessResponses.end(), - retryState.shardsWithSuccessResponses.begin(), - retryState.shardsWithSuccessResponses.end(), - std::inserter(okShardIds, okShardIds.begin())); - - staleConfigRetryState(opCtx)->shardsWithSuccessResponses = std::move(okShardIds); - staleConfigRetryState(opCtx)->shardSuccessResponses = std::move(response.successResponses); -} - class DropIndexesCmd : public BasicCommandWithRequestParser<DropIndexesCmd> { public: using Request = DropIndexes; @@ -128,6 +96,15 @@ public: const RequestParser& requestParser, BSONObjBuilder& output) final { auto nss = requestParser.request().getNamespace(); + + uassert(ErrorCodes::IllegalOperation, + "Cannot drop indexes in 'config' database in sharded cluster", + nss.db() != NamespaceString::kConfigDb); + + uassert(ErrorCodes::IllegalOperation, + "Cannot drop indexes in 'admin' database in sharded cluster", + nss.db() != NamespaceString::kAdminDb); + LOGV2_DEBUG(22751, 1, "dropIndexes: {namespace} cmd: {command}", @@ -135,61 +112,24 @@ public: "namespace"_attr = nss, "command"_attr = redact(cmdObj)); - // dropIndexes can be retried on a stale config error. If a previous attempt already - // successfully dropped the index on shards, those shards will return an IndexNotFound - // error when retried. We instead maintain the record of shards that have already - // successfully dropped the index, so that we don't try to contact those shards again - // across stale config retries. - const auto retryState = createAndRetrieveStateFromStaleConfigRetry(opCtx); - - // If the collection is sharded, we target only the primary shard and the shards that own - // chunks for the collection. - auto targeter = ChunkManagerTargeter(opCtx, nss); - auto routingInfo = targeter.getRoutingInfo(); - - auto cmdToBeSent = cmdObj; - if (targeter.timeseriesNamespaceNeedsRewrite(nss)) { - cmdToBeSent = timeseries::makeTimeseriesCommand( - cmdToBeSent, nss, getName(), DropIndexes::kIsTimeseriesNamespaceFieldName); - } + ShardsvrDropIndexes shardsvrDropIndexCmd(nss); + shardsvrDropIndexCmd.setDropIndexesRequest(requestParser.request().getDropIndexesRequest()); - auto shardResponses = - scatterGatherVersionedTargetByRoutingTableNoThrowOnStaleShardVersionErrors( - opCtx, - nss.db(), - targeter.getNS(), - routingInfo, - retryState.shardsWithSuccessResponses, - applyReadWriteConcern( - opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdToBeSent)), - ReadPreferenceSetting::get(opCtx), - Shard::RetryPolicy::kNotIdempotent, - BSONObj() /* query */, - BSONObj() /* collation */); - - // Append responses we've received from previous retries of this operation due to a stale - // config error. - shardResponses.insert(shardResponses.end(), - retryState.shardSuccessResponses.begin(), - retryState.shardSuccessResponses.end()); - - std::string errmsg; - const auto aggregateResponse = - appendRawResponses(opCtx, &errmsg, &output, std::move(shardResponses)); - - // If we have a stale config error, update the success shards for the upcoming retry. - if (!aggregateResponse.responseOK && aggregateResponse.firstStaleConfigError) { - updateStateForStaleConfigRetry(opCtx, retryState, aggregateResponse); - uassertStatusOK(*aggregateResponse.firstStaleConfigError); - } + const CachedDatabaseInfo dbInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName)); - CommandHelpers::appendSimpleCommandStatus(output, aggregateResponse.responseOK, errmsg); + auto cmdResponse = executeCommandAgainstDatabasePrimary( + opCtx, + dbName, + dbInfo, + CommandHelpers::appendMajorityWriteConcern(shardsvrDropIndexCmd.toBSON({}), + opCtx->getWriteConcern()), + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + Shard::RetryPolicy::kNotIdempotent); - if (aggregateResponse.responseOK) { - LOGV2(5706401, "Indexes dropped", "namespace"_attr = nss); - } - - return aggregateResponse.responseOK; + const auto remoteResponse = uassertStatusOK(cmdResponse.swResponse); + CommandHelpers::filterCommandReplyForPassthrough(remoteResponse.data, &output); + return true; } const AuthorizationContract* getAuthorizationContract() const final { diff --git a/src/mongo/s/request_types/sharded_ddl_commands.idl b/src/mongo/s/request_types/sharded_ddl_commands.idl index 8f40c11e835..2c86a3d199a 100644 --- a/src/mongo/s/request_types/sharded_ddl_commands.idl +++ b/src/mongo/s/request_types/sharded_ddl_commands.idl @@ -36,6 +36,7 @@ global: imports: - "mongo/db/commands/rename_collection.idl" - "mongo/db/commands/set_user_write_block_mode.idl" + - "mongo/db/drop_indexes.idl" - "mongo/db/drop_database.idl" - "mongo/db/keypattern.idl" - "mongo/db/coll_mod.idl" @@ -395,6 +396,16 @@ commands: Verifies that the shard key index has the same unique setting as the command. type: optionalBool + _shardsvrDropIndexes: + description: "Parser for the _shardsvrDropIndexes command" + command_name: _shardsvrDropIndexes + cpp_name: ShardsvrDropIndexes + namespace: concatenate_with_db + api_version: "" + strict: false + chained_structs: + DropIndexesRequest: DropIndexesRequest + _configsvrCreateDatabase: description: "The internal createDatabase command on the config server" api_version: "" diff --git a/src/mongo/s/stale_shard_version_helpers.h b/src/mongo/s/stale_shard_version_helpers.h index c1c7e8443bc..a3771a41552 100644 --- a/src/mongo/s/stale_shard_version_helpers.h +++ b/src/mongo/s/stale_shard_version_helpers.h @@ -111,9 +111,13 @@ auto shardVersionRetry(ServiceContext* service, _callbackFn = std::move(callbackFn), executor, cancelToken] { - ThreadClient tc(taskDescription, service); + boost::optional<ThreadClient> threadClient; + if (!haveClient()) { + threadClient.emplace(taskDescription, service); + } + CancelableOperationContextFactory opCtxFactory(cancelToken, executor); - auto cancelableOpCtx = opCtxFactory.makeOperationContext(tc.get()); + auto cancelableOpCtx = opCtxFactory.makeOperationContext(&cc()); auto opCtx = cancelableOpCtx.get(); catalogCache->setOperationShouldBlockBehindCatalogCacheRefresh(opCtx, *numAttempts); |