diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/s/commands | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/s/commands')
30 files changed, 258 insertions, 497 deletions
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 237324eb92a..be0eb7d5203 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -53,8 +53,6 @@ env.Library( 'cluster_find_cmd_s.cpp', 'cluster_fle2_compact_cmd.cpp', 'cluster_fsync_cmd.cpp', - 'cluster_fsync_unlock_cmd.cpp', - 'cluster_fsync_unlock_cmd.idl', 'cluster_ftdc_commands.cpp', 'cluster_get_cluster_parameter_cmd.cpp', 'cluster_get_last_error_cmd.cpp', @@ -86,6 +84,7 @@ env.Library( 'cluster_set_allow_migrations_cmd.cpp', 'cluster_set_cluster_parameter_cmd.cpp', 'cluster_set_feature_compatibility_version_cmd.cpp', + 'cluster_set_free_monitoring_cmd.cpp' if get_option("enable-free-mon") == 'on' else [], 'cluster_set_index_commit_quorum_cmd.cpp', 'cluster_set_user_write_block_mode_command.cpp', 'cluster_shard_collection_cmd.cpp', @@ -103,7 +102,6 @@ env.Library( LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/api_parameters', '$BUILD_DIR/mongo/db/auth/auth_checks', - '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch_info', '$BUILD_DIR/mongo/db/change_stream_options_manager', '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_cmds_idl', '$BUILD_DIR/mongo/db/commands/core', @@ -132,7 +130,6 @@ env.Library( '$BUILD_DIR/mongo/db/query/command_request_response', '$BUILD_DIR/mongo/db/query/cursor_response_idl', '$BUILD_DIR/mongo/db/query/map_reduce_output_format', - '$BUILD_DIR/mongo/db/query/query_shape/query_shape', '$BUILD_DIR/mongo/db/read_write_concern_defaults', '$BUILD_DIR/mongo/db/repl/hello_auth', '$BUILD_DIR/mongo/db/repl/hello_command', diff --git a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp index d3067b4769e..f85ae09aeb2 100644 --- a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp +++ b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp @@ -232,10 +232,8 @@ public: opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObjToSend)), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, - {} /*query*/, - {} /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + {}, + {}); BSONObjBuilder shardStats; std::map<std::string, long long> counts; diff --git a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp index 42e318aaa57..d295ca18c71 100644 --- a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp +++ b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp @@ -33,7 +33,6 @@ #include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/catalog/collection_uuid_mismatch_info.h" #include "mongo/db/coll_mod_gen.h" #include "mongo/db/coll_mod_reply_validation.h" #include "mongo/db/commands.h" @@ -94,17 +93,8 @@ public: "namespace"_attr = nss, "command"_attr = redact(cmdObj)); - auto swDbInfo = Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, cmd.getDbName()); - if (swDbInfo == ErrorCodes::NamespaceNotFound) { - uassert(CollectionUUIDMismatchInfo(cmd.getDbName().toString(), - *cmd.getCollectionUUID(), - nss.coll().toString(), - boost::none), - "Database does not exist", - !cmd.getCollectionUUID()); - } - const auto dbInfo = uassertStatusOK(swDbInfo); - + const auto dbInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, cmd.getDbName())); ShardsvrCollMod collModCommand(nss); collModCommand.setCollModRequest(cmd.getCollModRequest()); auto cmdResponse = diff --git a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp index c6206bce5be..8c657bc453f 100644 --- a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp +++ b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp @@ -51,17 +51,8 @@ bool nonShardedCollectionCommandPassthrough(OperationContext* opCtx, str::stream() << "Can't do command: " << cmdName << " on a sharded collection", !cm.isSharded()); - auto responses = scatterGatherVersionedTargetByRoutingTable(opCtx, - dbName, - nss, - cm, - cmdObj, - ReadPreferenceSetting::get(opCtx), - retryPolicy, - {} /*query*/, - {} /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + auto responses = scatterGatherVersionedTargetByRoutingTable( + opCtx, dbName, nss, cm, cmdObj, ReadPreferenceSetting::get(opCtx), retryPolicy, {}, {}); invariant(responses.size() == 1); const auto cmdResponse = uassertStatusOK(std::move(responses.front().swResponse)); diff --git a/src/mongo/s/commands/cluster_count_cmd.cpp b/src/mongo/s/commands/cluster_count_cmd.cpp index 94e6c7c0eee..48545c7c0d7 100644 --- a/src/mongo/s/commands/cluster_count_cmd.cpp +++ b/src/mongo/s/commands/cluster_count_cmd.cpp @@ -131,9 +131,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, countRequest.getQuery(), - collation, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + collation); } catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) { // Rewrite the count command as an aggregation. auto countRequest = CountCommandRequest::parse(IDLParserErrorContext("count"), cmdObj); @@ -237,9 +235,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, targetingQuery, - targetingCollation, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + targetingCollation); } catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) { CountCommandRequest countRequest(NamespaceStringOrUUID(NamespaceString{})); try { @@ -288,14 +284,14 @@ private: BSONElement l = cmd["limit"]; if (s.isNumber()) { - num = num - s.safeNumberLong(); + num = num - s.numberLong(); if (num < 0) { num = 0; } } if (l.isNumber()) { - auto limit = l.safeNumberLong(); + long long limit = l.numberLong(); if (limit < 0) { limit = -limit; } diff --git a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp index 8f4928444c4..8c4c8af8784 100644 --- a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp @@ -89,6 +89,8 @@ public: "namespace"_attr = nss, "command"_attr = redact(cmdObj)); + cluster::createDatabase(opCtx, dbName); + auto targeter = ChunkManagerTargeter(opCtx, nss); auto routingInfo = targeter.getRoutingInfo(); auto cmdToBeSent = cmdObj; @@ -106,10 +108,8 @@ public: applyReadWriteConcern(opCtx, this, cmdToBeSent)), ReadPreferenceSetting(ReadPreference::PrimaryOnly), Shard::RetryPolicy::kNoRetry, - BSONObj() /*query*/, - BSONObj() /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + BSONObj() /* query */, + BSONObj() /* collation */); std::string errmsg; const bool ok = diff --git a/src/mongo/s/commands/cluster_data_size_cmd.cpp b/src/mongo/s/commands/cluster_data_size_cmd.cpp index 1c87c6a98f0..7d645d1a51c 100644 --- a/src/mongo/s/commands/cluster_data_size_cmd.cpp +++ b/src/mongo/s/commands/cluster_data_size_cmd.cpp @@ -85,10 +85,8 @@ public: opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, - {} /*query*/, - {} /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + {}, + {}); // yes these are doubles... double size = 0; diff --git a/src/mongo/s/commands/cluster_distinct_cmd.cpp b/src/mongo/s/commands/cluster_distinct_cmd.cpp index f34377258e4..70ae5f4b671 100644 --- a/src/mongo/s/commands/cluster_distinct_cmd.cpp +++ b/src/mongo/s/commands/cluster_distinct_cmd.cpp @@ -132,9 +132,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, targetingQuery, - targetingCollation, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + targetingCollation); } catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) { auto parsedDistinct = ParsedDistinct::parse( opCtx, ex->getNamespace(), cmdObj, ExtensionsCallbackNoop(), true); @@ -219,9 +217,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, query, - collation, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + collation); } catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) { auto parsedDistinct = ParsedDistinct::parse( opCtx, ex->getNamespace(), cmdObj, ExtensionsCallbackNoop(), true); diff --git a/src/mongo/s/commands/cluster_drop_collection_cmd.cpp b/src/mongo/s/commands/cluster_drop_collection_cmd.cpp index 40e9196371f..e16f473ab3c 100644 --- a/src/mongo/s/commands/cluster_drop_collection_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_collection_cmd.cpp @@ -33,7 +33,6 @@ #include "mongo/base/status.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/catalog/collection_uuid_mismatch_info.h" #include "mongo/db/commands.h" #include "mongo/db/drop_gen.h" #include "mongo/db/operation_context.h" @@ -117,13 +116,6 @@ public: // Ensure our reply conforms to the IDL-defined reply structure. return DropReply::parse({"drop"}, resultObj); } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>&) { - uassert(CollectionUUIDMismatchInfo(request().getDbName().toString(), - *request().getCollectionUUID(), - request().getNamespace().coll().toString(), - boost::none), - "Database does not exist", - !request().getCollectionUUID()); - // If the namespace isn't found, treat the drop as a success but inform about the // failure. DropReply reply; diff --git a/src/mongo/s/commands/cluster_filemd5_cmd.cpp b/src/mongo/s/commands/cluster_filemd5_cmd.cpp index 3248d9ce0ba..d351a7be7a3 100644 --- a/src/mongo/s/commands/cluster_filemd5_cmd.cpp +++ b/src/mongo/s/commands/cluster_filemd5_cmd.cpp @@ -98,9 +98,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, routingQuery, - CollationSpec::kSimpleSpec, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + CollationSpec::kSimpleSpec); invariant(shardResults.size() == 1); const auto shardResponse = uassertStatusOK(std::move(shardResults[0].swResponse)); uassertStatusOK(shardResponse.status); diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index 195adef15e2..740d1561487 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -69,8 +69,6 @@ namespace mongo { namespace { -constexpr size_t kMaxDatabaseCreationAttempts = 3u; - const ReadPreferenceSetting kPrimaryOnlyReadPreference(ReadPreference::PrimaryOnly); const char kLegacyRuntimeConstantsField[] = "runtimeConstants"; @@ -307,27 +305,6 @@ void handleWouldChangeOwningShardErrorTransactionLegacy(OperationContext* opCtx, } } -ShardId targetSingleShard(boost::intrusive_ptr<ExpressionContext> expCtx, - const ChunkManager& cm, - const BSONObj& query, - const BSONObj& collation) { - std::set<ShardId> shardIds; - - // For now, set bypassIsFieldHashedCheck to be true in order to skip the - // isFieldHashedCheck in the special case where _id is hashed and used as the shard - // key. This means that we always assume that a findAndModify request using _id is - // targetable to a single shard. - cm.getShardIdsForQuery(expCtx, query, collation, &shardIds, true); - - uassert(ErrorCodes::ShardKeyNotFound, - str::stream() << "Query with sharded findAndModify expected to only target one " - "shard, but the query targeted " - << shardIds.size() << " shard(s)", - shardIds.size() == 1); - - return *shardIds.begin(); -} - class FindAndModifyCmd : public BasicCommand { public: FindAndModifyCmd() @@ -415,14 +392,12 @@ public: const BSONObj collation = getCollation(cmdObj); const auto let = getLet(cmdObj); const auto rc = getLegacyRuntimeConstants(cmdObj); - ShardId shardId; - { - auto expCtx = makeExpressionContextWithDefaultsForTargeter( - opCtx, nss, collation, verbosity, let, rc); - shardId = targetSingleShard(expCtx, cm, query, collation); - } + const BSONObj shardKey = + getShardKey(opCtx, cm, nss, query, collation, verbosity, let, rc); + const auto chunk = cm.findIntersectingChunk(shardKey, collation); - shard = uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardId)); + shard = uassertStatusOK( + Grid::get(opCtx)->shardRegistry()->getShard(opCtx, chunk.getShardId())); } else { shard = uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, cm.dbPrimary())); @@ -484,50 +459,31 @@ public: // Collect metrics. _updateMetrics.collectMetrics(cmdObj); - const auto cm = [&]() { - size_t attempts = 1u; - while (true) { - try { - // Technically, findAndModify should only be creating database if upsert is - // true, but this would require that the parsing be pulled into this function. - cluster::createDatabase(opCtx, nss.db()); - return uassertStatusOK(getCollectionRoutingInfoForTxnCmd(opCtx, nss)); - } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>&) { - LOGV2_INFO( - 8584300, - "Failed initialization of routing info because the database has been " - "concurrently dropped", - logAttrs(nss), - "attemptNumber"_attr = attempts, - "maxAttempts"_attr = kMaxDatabaseCreationAttempts); - - if (attempts++ >= kMaxDatabaseCreationAttempts) { - // The maximum number of attempts has been reached, so the procedure fails - // as it could be a logical error. At this point, it is unlikely that the - // error is caused by concurrent drop database operations. - throw; - } - } - } - }(); + // Technically, findAndModify should only be creating database if upsert is true, but this + // would require that the parsing be pulled into this function. + cluster::createDatabase(opCtx, nss.db()); // Append mongoS' runtime constants to the command object before forwarding it to the shard. auto cmdObjForShard = appendLegacyRuntimeConstantsToCommandObject(opCtx, cmdObj); + const auto cm = uassertStatusOK(getCollectionRoutingInfoForTxnCmd(opCtx, nss)); if (cm.isSharded()) { const BSONObj query = cmdObjForShard.getObjectField("query"); const BSONObj collation = getCollation(cmdObjForShard); const auto let = getLet(cmdObjForShard); const auto rc = getLegacyRuntimeConstants(cmdObjForShard); - ShardId shardId; - { - auto expCtx = makeExpressionContextWithDefaultsForTargeter( - opCtx, nss, collation, boost::none, let, rc); - shardId = targetSingleShard(expCtx, cm, query, collation); - } + const BSONObj shardKey = + getShardKey(opCtx, cm, nss, query, collation, boost::none, let, rc); + + // For now, set bypassIsFieldHashedCheck to be true in order to skip the + // isFieldHashedCheck in the special case where _id is hashed and used as the shard key. + // This means that we always assume that a findAndModify request using _id is targetable + // to a single shard. + auto chunk = cm.findIntersectingChunk(shardKey, collation, true); + _runCommand(opCtx, - shardId, - cm.getVersion(shardId), + chunk.getShardId(), + cm.getVersion(chunk.getShardId()), boost::none, nss, applyReadWriteConcern(opCtx, this, cmdObjForShard), diff --git a/src/mongo/s/commands/cluster_find_cmd.h b/src/mongo/s/commands/cluster_find_cmd.h index 6476d883200..87d25934d0c 100644 --- a/src/mongo/s/commands/cluster_find_cmd.h +++ b/src/mongo/s/commands/cluster_find_cmd.h @@ -38,9 +38,6 @@ #include "mongo/db/fle_crud.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/cursor_response.h" -#include "mongo/db/query/query_shape/query_shape.h" -#include "mongo/db/query/query_stats/find_key.h" -#include "mongo/db/query/query_stats/query_stats.h" #include "mongo/db/stats/counters.h" #include "mongo/db/views/resolved_view.h" #include "mongo/rpc/get_status_from_command_result.h" @@ -155,9 +152,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, findCommand->getFilter(), - findCommand->getCollation(), - findCommand->getLet(), - findCommand->getLegacyRuntimeConstants()); + findCommand->getCollation()); millisElapsed = timer.millis(); const char* mongosStageName = @@ -204,23 +199,21 @@ public: Impl::checkCanRunHere(opCtx); - auto&& parsedFindResult = uassertStatusOK(parsed_find_command::parse( - opCtx, - _parseCmdObjectToFindCommandRequest(opCtx, ns(), _request.body), - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures)); - auto& expCtx = parsedFindResult.first; - auto& parsedFind = parsedFindResult.second; - - if (!_didDoFLERewrite) { - query_stats::registerRequest(opCtx, expCtx->ns, [&]() { - // This callback is either never invoked or invoked - // immediately within registerRequest, so - // use-after-move of parsedFind isn't an issue. - return std::make_unique<query_stats::FindKey>(expCtx, *parsedFind); - }); - } - auto cq = uassertStatusOK(CanonicalQuery::canonicalize(expCtx, std::move(parsedFind))); + ON_BLOCK_EXIT([opCtx] { + Grid::get(opCtx)->catalogCache()->checkAndRecordOperationBlockedByRefresh( + opCtx, mongo::LogicalOp::opQuery); + }); + + auto findCommand = _parseCmdObjectToFindCommandRequest(opCtx, ns(), _request.body); + + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = uassertStatusOK( + CanonicalQuery::canonicalize(opCtx, + std::move(findCommand), + false, /* isExplain */ + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures)); try { // Do the work to generate the first batch of results. This blocks waiting to get @@ -274,7 +267,7 @@ public: * were supplied with the command, and sets the constant runtime values that will be * forwarded to each shard. */ - std::unique_ptr<FindCommandRequest> _parseCmdObjectToFindCommandRequest( + static std::unique_ptr<FindCommandRequest> _parseCmdObjectToFindCommandRequest( OperationContext* opCtx, NamespaceString nss, BSONObj cmdObj) { auto findCommand = query_request_helper::makeFromFindCommand( std::move(cmdObj), @@ -301,7 +294,6 @@ public: invariant(findCommand->getNamespaceOrUUID().nss()); processFLEFindS( opCtx, findCommand->getNamespaceOrUUID().nss().get(), findCommand.get()); - _didDoFLERewrite = true; } return findCommand; @@ -309,7 +301,6 @@ public: const OpMsgRequest& _request; const StringData _dbName; - bool _didDoFLERewrite{false}; }; }; diff --git a/src/mongo/s/commands/cluster_fle2_compact_cmd.cpp b/src/mongo/s/commands/cluster_fle2_compact_cmd.cpp index 7abae202f17..b1cecbf555e 100644 --- a/src/mongo/s/commands/cluster_fle2_compact_cmd.cpp +++ b/src/mongo/s/commands/cluster_fle2_compact_cmd.cpp @@ -32,7 +32,6 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/fle2_compact_gen.h" -#include "mongo/db/curop.h" #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" diff --git a/src/mongo/s/commands/cluster_fsync_cmd.cpp b/src/mongo/s/commands/cluster_fsync_cmd.cpp index 55316c964ac..e82469acee3 100644 --- a/src/mongo/s/commands/cluster_fsync_cmd.cpp +++ b/src/mongo/s/commands/cluster_fsync_cmd.cpp @@ -31,18 +31,10 @@ #include "mongo/client/read_preference.h" #include "mongo/client/remote_command_targeter.h" -#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_registry.h" -#include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" -#include "mongo/s/sharding_feature_flags_gen.h" -#include "mongo/util/assert_util.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand namespace mongo { namespace { @@ -75,47 +67,53 @@ public: out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } - void unlockLockedShards(OperationContext* opCtx, const std::string& dbname) { - - auto request = OpMsgRequest::fromDBAndBody(dbname, BSON("fsyncUnlock" << 1)); - auto response = CommandHelpers::runCommandDirectly(opCtx, request); - } - bool errmsgRun(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& result) override { - - BSONObj fsyncCmdObj = cmdObj; if (cmdObj["lock"].trueValue()) { - auto forBackupField = BSON("forBackup" << true); - fsyncCmdObj = fsyncCmdObj.addFields(forBackupField); + errmsg = "can't do lock through mongos"; + return false; } - auto shardResults = scatterGatherUnversionedTargetConfigServerAndShards( - opCtx, - dbname, - applyReadWriteConcern( - opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(fsyncCmdObj)), - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - Shard::RetryPolicy::kIdempotent); + BSONObjBuilder sub; - BSONObjBuilder rawResult; - const auto response = appendRawResponses(opCtx, &errmsg, &rawResult, shardResults); + bool ok = true; + + auto const shardRegistry = Grid::get(opCtx)->shardRegistry(); + const auto shardIds = shardRegistry->getAllShardIdsNoReload(); + + for (const ShardId& shardId : shardIds) { + auto shardStatus = shardRegistry->getShard(opCtx, shardId); + if (!shardStatus.isOK()) { + continue; + } + const auto s = shardStatus.getValue(); + + auto response = uassertStatusOK(s->runCommandWithFixedRetryAttempts( + opCtx, + ReadPreferenceSetting{ReadPreference::PrimaryOnly}, + "admin", + BSON("fsync" << 1), + Shard::RetryPolicy::kIdempotent)); + uassertStatusOK(response.commandStatus); + BSONObj x = std::move(response.response); + + sub.append(s->getId().toString(), x); + + if (!x["ok"].trueValue()) { + ok = false; + errmsg = x["errmsg"].String(); + } + } // This field has had dummy value since MMAP went away. It is undocumented. // Maintaining it so as not to cause unnecessary user pain across upgrades. result.append("numFiles", 1); - result.append("all", rawResult.obj()); - if (!response.responseOK) { - if (cmdObj["lock"].trueValue()) { - unlockLockedShards(opCtx, dbname); - } - return false; - } + result.append("all", sub.obj()); - return true; + return ok; } } clusterFsyncCmd; diff --git a/src/mongo/s/commands/cluster_fsync_unlock_cmd.cpp b/src/mongo/s/commands/cluster_fsync_unlock_cmd.cpp deleted file mode 100644 index 5275298a7bb..00000000000 --- a/src/mongo/s/commands/cluster_fsync_unlock_cmd.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (C) 2023-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/client/remote_command_targeter.h" -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/commands.h" -#include "mongo/s/async_requests_sender.h" -#include "mongo/s/client/shard.h" -#include "mongo/s/client/shard_registry.h" -#include "mongo/s/cluster_commands_helpers.h" -#include "mongo/s/commands/cluster_fsync_unlock_cmd_gen.h" -#include "mongo/s/grid.h" -#include "mongo/s/sharding_feature_flags_gen.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand - -namespace mongo { - -namespace { -class FsyncUnlockCommand : public TypedCommand<FsyncUnlockCommand> { -public: - using Request = ClusterFsyncUnlock; - - - 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) { - BSONObj fsyncUnlockCmdObj = BSON("fsyncUnlock" << 1); - - auto responses = scatterGatherUnversionedTargetConfigServerAndShards( - opCtx, - NamespaceString::kAdminDb, - applyReadWriteConcern( - opCtx, - this, - CommandHelpers::filterCommandRequestForPassthrough(fsyncUnlockCmdObj)), - ReadPreferenceSetting::get(opCtx), - Shard::RetryPolicy::kIdempotent); - - BSONObjBuilder result; - std::string errmsg; - const auto rawResponsesResult = appendRawResponses(opCtx, &errmsg, &result, responses); - - if (!errmsg.empty()) { - CommandHelpers::appendSimpleCommandStatus( - result, rawResponsesResult.responseOK, errmsg); - } - - return Response(result.obj()); - } - - private: - NamespaceString ns() const override { - return {}; - } - - bool supportsWriteConcern() const override { - return false; - } - - void doCheckAuthorization(OperationContext* opCtx) const override { - uassert(ErrorCodes::Unauthorized, - "Unauthorized", - AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns()), - ActionType::fsyncUnlock)); - } - }; - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - - bool maintenanceOk() const override { - return false; - } - - bool adminOnly() const override { - return true; - } - - std::string help() const override { - return "invoke fsync unlock on all shards belonging to the cluster"; - } -} fsyncUnlockCmd; - -} // namespace -} // namespace mongo diff --git a/src/mongo/s/commands/cluster_fsync_unlock_cmd.idl b/src/mongo/s/commands/cluster_fsync_unlock_cmd.idl deleted file mode 100644 index c0d1be0aa0c..00000000000 --- a/src/mongo/s/commands/cluster_fsync_unlock_cmd.idl +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2023-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" - -commands: - clusterFsyncUnlock: - description: "The command for calling fsync unlock on all shards of a cluster." - command_name: fsyncUnlock - cpp_name: clusterFsyncUnlock - strict: false - namespace: ignored - api_version: "" 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 4b6d49ebae1..1058e6ebafd 100644 --- a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp @@ -66,11 +66,6 @@ public: using InvocationBase::InvocationBase; Reply typedRun(OperationContext* opCtx) { - uassert(ErrorCodes::UnknownFeatureCompatibilityVersion, - "FCV is not yet initialized, retry the command after FCV initialization has " - "completed", - serverGlobalParams.featureCompatibility.isVersionInitialized()); - uassert( ErrorCodes::IllegalOperation, "featureFlagClusterWideConfig not enabled", diff --git a/src/mongo/s/commands/cluster_hello_cmd.cpp b/src/mongo/s/commands/cluster_hello_cmd.cpp index 13b199f8ad3..5600a29661d 100644 --- a/src/mongo/s/commands/cluster_hello_cmd.cpp +++ b/src/mongo/s/commands/cluster_hello_cmd.cpp @@ -133,12 +133,6 @@ public: // "hello" is exempt from error code rewrites. rpc::RewriteStateChangeErrors::setEnabled(opCtx, false); - // Negotiate compressors before logging metadata so we can include the result in the log - // line. - auto result = replyBuilder->getBodyBuilder(); - MessageCompressorManager::forSession(opCtx->getClient()->session()) - .serverNegotiate(cmd.getCompression(), &result); - auto client = opCtx->getClient(); if (ClientMetadata::tryFinalize(client)) { audit::logClientMetadata(client); @@ -172,6 +166,7 @@ public: !clientTopologyVersion && !maxAwaitTimeMS); } + auto result = replyBuilder->getBodyBuilder(); const auto* mongosTopCoord = MongosTopologyCoordinator::get(opCtx); auto mongosHelloResponse = @@ -224,6 +219,9 @@ public: sp->append(opCtx, result, kAutomationServiceDescriptorFieldName); } + MessageCompressorManager::forSession(opCtx->getClient()->session()) + .serverNegotiate(cmd.getCompression(), &result); + if (opCtx->isExhaust()) { LOGV2_DEBUG(23872, 3, "Using exhaust for hello protocol"); diff --git a/src/mongo/s/commands/cluster_index_filter_cmd.cpp b/src/mongo/s/commands/cluster_index_filter_cmd.cpp index 48aec39e5cb..f6c5bd37777 100644 --- a/src/mongo/s/commands/cluster_index_filter_cmd.cpp +++ b/src/mongo/s/commands/cluster_index_filter_cmd.cpp @@ -104,9 +104,7 @@ public: ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, query, - CollationSpec::kSimpleSpec, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + CollationSpec::kSimpleSpec); // Sort shard responses by shard id. std::sort(shardResponses.begin(), diff --git a/src/mongo/s/commands/cluster_map_reduce_agg.cpp b/src/mongo/s/commands/cluster_map_reduce_agg.cpp index 746ba39c7bc..52a61ab9325 100644 --- a/src/mongo/s/commands/cluster_map_reduce_agg.cpp +++ b/src/mongo/s/commands/cluster_map_reduce_agg.cpp @@ -187,7 +187,6 @@ bool runAggregationMapReduce(OperationContext* opCtx, cm, involvedNamespaces, false, // hasChangeStream - false, // startsWithDocuments true, // allowedToPassthrough false); // perShardCursor try { @@ -231,15 +230,14 @@ bool runAggregationMapReduce(OperationContext* opCtx, namespaces, privileges, &tempResults, - false, // hasChangeStream - false)); // startsWithDocuments + false)); // hasChangeStream break; } case cluster_aggregation_planner::AggregationTargeter::TargetingPolicy:: kSpecificShardOnly: { // It should not be possible to pass $_passthroughToShard to a map reduce command. - MONGO_UNREACHABLE_TASSERT(6273805); + MONGO_UNREACHABLE_TASSERT(6273803); } } } catch (DBException& e) { diff --git a/src/mongo/s/commands/cluster_move_range_cmd.cpp b/src/mongo/s/commands/cluster_move_range_cmd.cpp index fd2f77ea9f5..c06ca4a5c47 100644 --- a/src/mongo/s/commands/cluster_move_range_cmd.cpp +++ b/src/mongo/s/commands/cluster_move_range_cmd.cpp @@ -100,7 +100,7 @@ public: uassert(ErrorCodes::Unauthorized, "Unauthorized", AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns()), + ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::moveChunk)); } }; diff --git a/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp index e3411fbda2c..96499720ea6 100644 --- a/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp +++ b/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp @@ -110,9 +110,7 @@ bool ClusterPlanCacheClearCmd::run(OperationContext* opCtx, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, query, - CollationSpec::kSimpleSpec, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + CollationSpec::kSimpleSpec); // Sort shard responses by shard id. std::sort(shardResponses.begin(), diff --git a/src/mongo/s/commands/cluster_profile_cmd.cpp b/src/mongo/s/commands/cluster_profile_cmd.cpp index 022b44011c0..c2564c19b1d 100644 --- a/src/mongo/s/commands/cluster_profile_cmd.cpp +++ b/src/mongo/s/commands/cluster_profile_cmd.cpp @@ -33,7 +33,6 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/profile_common.h" #include "mongo/db/commands/profile_gen.h" -#include "mongo/db/commands/set_profiling_filter_globally_cmd.h" #include "mongo/db/profile_filter_impl.h" namespace mongo { @@ -54,6 +53,7 @@ protected: OperationContext* opCtx, const std::string& dbName, const ProfileCmdRequest& request) const final { + invariant(!opCtx->lockState()->isW()); const auto profilingLevel = request.getCommandParameter(); @@ -85,7 +85,5 @@ protected: } profileCmd; -SetProfilingFilterGloballyCmd setProfilingFilterGloballyCmd; - } // namespace } // namespace mongo diff --git a/src/mongo/s/commands/cluster_rename_collection_cmd.cpp b/src/mongo/s/commands/cluster_rename_collection_cmd.cpp index a5c3d9d385c..4d4d88907a6 100644 --- a/src/mongo/s/commands/cluster_rename_collection_cmd.cpp +++ b/src/mongo/s/commands/cluster_rename_collection_cmd.cpp @@ -32,7 +32,6 @@ #include "mongo/platform/basic.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/catalog/collection_uuid_mismatch_info.h" #include "mongo/db/commands.h" #include "mongo/db/commands/rename_collection_common.h" #include "mongo/db/commands/rename_collection_gen.h" @@ -75,21 +74,6 @@ public: "Can't rename a collection to itself", fromNss != toNss); - if (fromNss.isTimeseriesBucketsCollection()) { - uassert( - ErrorCodes::IllegalOperation, - "Renaming system.buckets collections is not allowed", - AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), - ActionType::setUserWriteBlockMode)); - - uassert(ErrorCodes::IllegalOperation, - str::stream() - << "Cannot rename time-series buckets collection {" << fromNss.ns() - << "} to a non-time-series buckets namespace {" << toNss.ns() << "}", - toNss.isTimeseriesBucketsCollection()); - } - RenameCollectionRequest renameCollReq(request().getTo()); renameCollReq.setStayTemp(request().getStayTemp()); renameCollReq.setExpectedSourceUUID(request().getCollectionUUID()); @@ -106,22 +90,9 @@ public: ShardsvrRenameCollection renameCollRequest(fromNss); renameCollRequest.setDbName(fromNss.db()); renameCollRequest.setRenameCollectionRequest(renameCollReq); - renameCollRequest.setAllowEncryptedCollectionRename( - AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), - ActionType::setUserWriteBlockMode)); auto catalogCache = Grid::get(opCtx)->catalogCache(); - auto swDbInfo = Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, fromNss.db()); - if (swDbInfo == ErrorCodes::NamespaceNotFound) { - uassert(CollectionUUIDMismatchInfo(fromNss.db().toString(), - *request().getCollectionUUID(), - fromNss.coll().toString(), - boost::none), - "Database does not exist", - !request().getCollectionUUID()); - } - const auto dbInfo = uassertStatusOK(swDbInfo); + const auto dbInfo = uassertStatusOK(catalogCache->getDatabase(opCtx, fromNss.db())); auto cri = uassertStatusOK(catalogCache->getCollectionRoutingInfo(opCtx, fromNss)); auto shard = uassertStatusOK( diff --git a/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp b/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp new file mode 100644 index 00000000000..d54cd80b219 --- /dev/null +++ b/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2018-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/auth/authorization_session.h" +#include "mongo/db/commands.h" + +namespace mongo { +namespace { + +class ClusterSetFreeMonitoring : public BasicCommand { +public: + ClusterSetFreeMonitoring() : BasicCommand("setFreeMonitoring") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { + return AllowedOnSecondary::kNever; + } + + bool supportsWriteConcern(const BSONObj& cmd) const final { + return false; + } + + std::string help() const final { + return "setFreeMonitoring command must be run against mongod instances"; + } + + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const final { + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), ActionType::setFreeMonitoring)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + + bool run(OperationContext* opCtx, + const std::string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) final { + uasserted(ErrorCodes::CommandFailed, help()); + return true; + } + +} clusterSetFreeMonitoring; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp b/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp index f494e41a6a6..8727a9da078 100644 --- a/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp +++ b/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp @@ -117,10 +117,8 @@ public: opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kNotIdempotent, - BSONObj() /*query*/, - BSONObj() /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + BSONObj() /* query */, + BSONObj() /* collation */); std::string errmsg; const bool ok = diff --git a/src/mongo/s/commands/cluster_validate_cmd.cpp b/src/mongo/s/commands/cluster_validate_cmd.cpp index 285d23fc29d..52285704516 100644 --- a/src/mongo/s/commands/cluster_validate_cmd.cpp +++ b/src/mongo/s/commands/cluster_validate_cmd.cpp @@ -84,10 +84,8 @@ public: opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, - {} /*query*/, - {} /*collation*/, - boost::none /*letParameters*/, - boost::none /*runtimeConstants*/); + {}, + {}); Status firstFailedShardStatus = Status::OK(); bool isValid = true; diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index 8590832acc6..10d04ba0b82 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -145,6 +145,11 @@ boost::optional<WouldChangeOwningShardInfo> getWouldChangeOwningShardErrorInfo( void handleWouldChangeOwningShardErrorRetryableWrite(OperationContext* opCtx, BatchedCommandRequest* request, BatchedCommandResponse* response) { + // Strip write concern because this command will be sent as part of a + // transaction and the write concern has already been loaded onto the opCtx and + // will be picked up by the transaction API. + request->unsetWriteConcern(); + // Strip runtime constants because they will be added again when the API sends this command // through the service entry point. request->unsetLegacyRuntimeConstants(); @@ -313,6 +318,11 @@ bool handleWouldChangeOwningShardError(OperationContext* opCtx, auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx); readConcernArgs = repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern); + // Ensure the retried operation does not include WC inside the transaction. The + // transaction commit will still use the WC, because it uses the WC from the opCtx + // (which has been set previously in Strategy). + request->unsetWriteConcern(); + documentShardKeyUpdateUtil::startTransactionForShardKeyUpdate(opCtx); // Clear the error details from the response object before sending the write again response->unsetErrDetails(); @@ -497,6 +507,29 @@ bool ClusterWriteCmd::InvocationBase::runImpl(OperationContext* opCtx, BatchWriteExecStats stats; BatchedCommandResponse response; + // The batched request will only have WC if it was supplied by the client. Otherwise, the + // batched request should use the WC from the opCtx. + if (!batchedRequest.hasWriteConcern()) { + if (opCtx->getWriteConcern().usedDefaultConstructedWC) { + // Pass writeConcern: {}, rather than {w: 1, wtimeout: 0}, so as to not override the + // configsvr w:majority upconvert. + batchedRequest.setWriteConcern(BSONObj()); + } else { + batchedRequest.setWriteConcern(opCtx->getWriteConcern().toBSON()); + } + } + + // Write ops are never allowed to have writeConcern inside transactions. Normally + // disallowing WC on non-terminal commands in a transaction is handled earlier, during + // command dispatch. However, if this is a regular write operation being automatically + // retried inside a transaction (such as changing a document's shard key across shards), + // then batchedRequest will have a writeConcern (added by the if() above) from when it was + // initially run outside a transaction. Thus it's necessary to unconditionally clear the + // writeConcern when in a transaction. + if (TransactionRouter::get(opCtx)) { + batchedRequest.unsetWriteConcern(); + } + cluster::write(opCtx, batchedRequest, &stats, &response); bool updatedShardKey = false; @@ -522,17 +555,22 @@ bool ClusterWriteCmd::InvocationBase::runImpl(OperationContext* opCtx, // TODO: increase opcounters by more than one auto& debug = CurOp::get(opCtx)->debug(); + auto catalogCache = Grid::get(opCtx)->catalogCache(); switch (_batchedRequest.getBatchType()) { case BatchedCommandRequest::BatchType_Insert: for (size_t i = 0; i < numAttempts; ++i) { globalOpCounters.gotInsert(); } + catalogCache->checkAndRecordOperationBlockedByRefresh(opCtx, + mongo::LogicalOp::opInsert); debug.additiveMetrics.ninserted = response.getN(); break; case BatchedCommandRequest::BatchType_Update: for (size_t i = 0; i < numAttempts; ++i) { globalOpCounters.gotUpdate(); } + catalogCache->checkAndRecordOperationBlockedByRefresh(opCtx, + mongo::LogicalOp::opUpdate); // The response.getN() count is the sum of documents matched and upserted. if (response.isUpsertDetailsSet()) { @@ -565,6 +603,8 @@ bool ClusterWriteCmd::InvocationBase::runImpl(OperationContext* opCtx, for (size_t i = 0; i < numAttempts; ++i) { globalOpCounters.gotDelete(); } + catalogCache->checkAndRecordOperationBlockedByRefresh(opCtx, + mongo::LogicalOp::opDelete); debug.additiveMetrics.ndeleted = response.getN(); break; } diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index e12b3385a13..13d061e9e6d 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -426,6 +426,14 @@ public: explicit RunInvocation(ParseAndRunCommand* parc) : _parc(parc) {} + ~RunInvocation() { + if (!_shouldAffectCommandCounter) + return; + auto opCtx = _parc->_rec->getOpCtx(); + Grid::get(opCtx)->catalogCache()->checkAndRecordOperationBlockedByRefresh( + opCtx, mongo::LogicalOp::opCommand); + } + Future<void> run(); private: @@ -434,6 +442,7 @@ private: ParseAndRunCommand* const _parc; boost::optional<RouterOperationContextSession> _routerSession; + bool _shouldAffectCommandCounter = false; }; /* @@ -698,53 +707,31 @@ Status ParseAndRunCommand::RunInvocation::_setup() { (opCtx->getClient()->session() && (opCtx->getClient()->session()->getTags() & transport::Session::kInternalClient)); - bool canApplyDefaultWC = supportsWriteConcern && + if (supportsWriteConcern && !clientSuppliedWriteConcern && (!TransactionRouter::get(opCtx) || isTransactionCommand(_parc->_commandName)) && - !opCtx->getClient()->isInDirectClient(); - - if (canApplyDefaultWC) { - auto getDefaultWC = ([&]() { - auto rwcDefaults = + !opCtx->getClient()->isInDirectClient()) { + if (isInternalClient) { + uassert( + 5569900, + "received command without explicit writeConcern on an internalClient connection {}"_format( + redact(request.body.toString())), + request.body.hasField(WriteConcernOptions::kWriteConcernField)); + } else { + // This command is not from a DBDirectClient or internal client, and supports WC, but + // wasn't given one - so apply the default, if there is one. + const auto rwcDefaults = ReadWriteConcernDefaults::get(opCtx->getServiceContext()).getDefault(opCtx); - auto wcDefault = rwcDefaults.getDefaultWriteConcern(); - const auto defaultWriteConcernSource = rwcDefaults.getDefaultWriteConcernSource(); - customDefaultWriteConcernWasApplied = defaultWriteConcernSource && - defaultWriteConcernSource == DefaultWriteConcernSourceEnum::kGlobal; - return wcDefault; - }); - - if (!clientSuppliedWriteConcern) { - if (isInternalClient) { - uassert( - 5569900, - "received command without explicit writeConcern on an internalClient connection {}"_format( - redact(request.body.toString())), - request.body.hasField(WriteConcernOptions::kWriteConcernField)); - } else { - // This command is not from a DBDirectClient or internal client, and supports WC, - // but wasn't given one - so apply the default, if there is one. - const auto wcDefault = getDefaultWC(); - // Default WC can be 'boost::none' if the implicit default is used and set to 'w:1'. - if (wcDefault) { - _parc->_wc = *wcDefault; - LOGV2_DEBUG(22766, - 2, - "Applying default writeConcern on command", - "command"_attr = request.getCommandName(), - "writeConcern"_attr = *wcDefault); - } - } - } - // Client supplied a write concern object without 'w' field. - else if (_parc->_wc->isExplicitWithoutWField()) { - const auto wcDefault = getDefaultWC(); - // Default WC can be 'boost::none' if the implicit default is used and set to 'w:1'. - if (wcDefault) { - clientSuppliedWriteConcern = false; - _parc->_wc->w = wcDefault->w; - if (_parc->_wc->syncMode == WriteConcernOptions::SyncMode::UNSET) { - _parc->_wc->syncMode = wcDefault->syncMode; - } + if (const auto wcDefault = rwcDefaults.getDefaultWriteConcern()) { + _parc->_wc = *wcDefault; + const auto defaultWriteConcernSource = rwcDefaults.getDefaultWriteConcernSource(); + customDefaultWriteConcernWasApplied = defaultWriteConcernSource && + defaultWriteConcernSource == DefaultWriteConcernSourceEnum::kGlobal; + LOGV2_DEBUG(22766, + 2, + "Applying default writeConcern on {command} of {writeConcern}", + "Applying default writeConcern on command", + "command"_attr = request.getCommandName(), + "writeConcern"_attr = *wcDefault); } } } @@ -911,6 +898,7 @@ Status ParseAndRunCommand::RunInvocation::_setup() { if (command->shouldAffectCommandCounter()) { globalOpCounters.gotCommand(); + _shouldAffectCommandCounter = true; } return Status::OK(); @@ -1048,21 +1036,10 @@ void ParseAndRunCommand::RunAndRetry::_onNeedRetargetting(Status& status) { auto opCtx = _parc->_rec->getOpCtx(); const auto staleNs = staleInfo->getNss(); - const auto& originalNs = _parc->_invocation->ns(); auto catalogCache = Grid::get(opCtx)->catalogCache(); catalogCache->invalidateShardOrEntireCollectionEntryForShardedCollection( staleNs, staleInfo->getVersionWanted(), staleInfo->getShardId()); - if ((staleNs.isTimeseriesBucketsCollection() || originalNs.isTimeseriesBucketsCollection()) && - staleNs != originalNs) { - // A timeseries might've been created, so we need to invalidate the original namespace - // version. - Grid::get(opCtx) - ->catalogCache() - ->invalidateShardOrEntireCollectionEntryForShardedCollection( - originalNs, boost::none, staleInfo->getShardId()); - } - catalogCache->setOperationShouldBlockBehindCatalogCacheRefresh(opCtx, true); _checkRetryForTransaction(status); @@ -1193,13 +1170,6 @@ public: Future<DbResponse> run(); private: - std::string _getDatabaseStringForLogging() const try { - // `getDatabase` throws if the request doesn't have a '$db' field. - return _rec->getRequest().getDatabase().toString(); - } catch (const DBException& ex) { - return ex.toString(); - } - void _parseMessage(); Future<void> _execute(); @@ -1242,7 +1212,7 @@ Future<void> ClientCommand::_execute() { 3, "Command begin db: {db} msg id: {headerId}", "Command begin", - "db"_attr = _getDatabaseStringForLogging(), + "db"_attr = _rec->getRequest().getDatabase().toString(), "headerId"_attr = _rec->getMessage().header().getId()); return future_util::makeState<ParseAndRunCommand>(_rec, _errorBuilder) @@ -1252,7 +1222,7 @@ Future<void> ClientCommand::_execute() { 3, "Command end db: {db} msg id: {headerId}", "Command end", - "db"_attr = _getDatabaseStringForLogging(), + "db"_attr = _rec->getRequest().getDatabase().toString(), "headerId"_attr = _rec->getMessage().header().getId()); }) .tapError([this](Status status) { @@ -1261,7 +1231,7 @@ Future<void> ClientCommand::_execute() { 1, "Exception thrown while processing command on {db} msg id: {headerId} {error}", "Exception thrown while processing command", - "db"_attr = _getDatabaseStringForLogging(), + "db"_attr = _rec->getRequest().getDatabase().toString(), "headerId"_attr = _rec->getMessage().header().getId(), "error"_attr = redact(status)); diff --git a/src/mongo/s/commands/strategy.h b/src/mongo/s/commands/strategy.h index 73916229f7f..1e04130f657 100644 --- a/src/mongo/s/commands/strategy.h +++ b/src/mongo/s/commands/strategy.h @@ -41,8 +41,8 @@ public: /** * Executes a command from either OP_QUERY or OP_MSG wire protocols. * - * Catches StaleConfig errors and retries the command automatically after refreshing the - * metadata for the failing namespace. + * Catches StaleConfigException errors and retries the command automatically after refreshing + * the metadata for the failing namespace. */ static Future<DbResponse> clientCommand(std::shared_ptr<RequestExecutionContext> rec); }; |
