diff --git a/jstests/auth/internal_command_auth_validation.js b/jstests/auth/internal_command_auth_validation.js index 8c0793a6643..6f9b583a72f 100644 --- a/jstests/auth/internal_command_auth_validation.js +++ b/jstests/auth/internal_command_auth_validation.js @@ -707,6 +707,13 @@ const internalCommandsMap = { reshardingUUID: UUID(), }, }, + _shardsvrReshardingRecipientFetchFinalCollectionStats: { + testname: "_shardsvrReshardingRecipientFetchFinalCollectionStats", + command: { + _shardsvrReshardingRecipientFetchFinalCollectionStats: "test.x", + reshardingUUID: UUID(), + }, + }, _shardsvrReshardingDonorStartChangeStreamsMonitor: { testname: "_shardsvrReshardingDonorStartChangeStreamsMonitor", command: { diff --git a/jstests/core/catalog/views/views_all_commands.js b/jstests/core/catalog/views/views_all_commands.js index 089ee9c2910..912c2711993 100644 --- a/jstests/core/catalog/views/views_all_commands.js +++ b/jstests/core/catalog/views/views_all_commands.js @@ -209,6 +209,7 @@ let viewsCommandTests = { _shardsvrRenameIndexMetadata: {skip: isAnInternalCommand}, _shardsvrReshardCollection: {skip: isAnInternalCommand}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: isAnInternalCommand}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: isAnInternalCommand}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: isAnInternalCommand}, _shardsvrReshardingOperationTime: {skip: isAnInternalCommand}, _shardsvrReshardDonorInitialize: {skip: isAnInternalCommand}, diff --git a/jstests/libs/write_concern_all_commands.js b/jstests/libs/write_concern_all_commands.js index bdb995b4243..f8ff5116885 100644 --- a/jstests/libs/write_concern_all_commands.js +++ b/jstests/libs/write_concern_all_commands.js @@ -197,6 +197,7 @@ const wcCommandsTests = { _shardsvrRenameIndexMetadata: {skip: "internal command"}, _shardsvrReshardCollection: {skip: "internal command"}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: "internal command"}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: "internal command"}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: "internal command"}, _shardsvrReshardingOperationTime: {skip: "internal command"}, _shardsvrReshardDonorInitialize: {skip: "internal command"}, @@ -3425,6 +3426,7 @@ const wcTimeseriesCommandsTests = { _shardsvrRenameIndexMetadata: {skip: "internal command"}, _shardsvrReshardCollection: {skip: "internal command"}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: "internal command"}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: "internal command"}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: "internal command"}, _shardsvrReshardingOperationTime: {skip: "internal command"}, _shardsvrReshardDonorInitialize: {skip: "internal command"}, diff --git a/jstests/replsets/all_commands_downgrading_to_upgraded.js b/jstests/replsets/all_commands_downgrading_to_upgraded.js index 0b5bf48c26c..50fa5bf363d 100644 --- a/jstests/replsets/all_commands_downgrading_to_upgraded.js +++ b/jstests/replsets/all_commands_downgrading_to_upgraded.js @@ -143,6 +143,7 @@ const allCommands = { _shardsvrDropDatabaseParticipant: {skip: isAnInternalCommand}, _shardsvrReshardCollection: {skip: isAnInternalCommand}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: isAnInternalCommand}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: isAnInternalCommand}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: isAnInternalCommand}, _shardsvrReshardingOperationTime: {skip: isAnInternalCommand}, _shardsvrReshardDonorInitialize: {skip: isAnInternalCommand}, diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js index 14ed124c832..2693d84d861 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -158,6 +158,7 @@ const allCommands = { _shardsvrBeginMigrationBlockingOperation: {skip: isAnInternalCommand}, _shardsvrEndMigrationBlockingOperation: {skip: isAnInternalCommand}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: isAnInternalCommand}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: isAnInternalCommand}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: isAnInternalCommand}, _shardsvrUpgradeDowngradeViewlessTimeseries: {skip: isAnInternalCommand}, _shardsvrTimeseriesUpgradeDowngradePrepare: {skip: isAnInternalCommand}, diff --git a/jstests/sharding/all_commands_direct_shard_connection_auth.js b/jstests/sharding/all_commands_direct_shard_connection_auth.js index f8929a34779..141c1bfe933 100644 --- a/jstests/sharding/all_commands_direct_shard_connection_auth.js +++ b/jstests/sharding/all_commands_direct_shard_connection_auth.js @@ -131,6 +131,7 @@ const allCommands = { _shardsvrRenameCollectionParticipantUnblock: {skip: isAnInternalCommand}, _shardsvrRenameIndexMetadata: {skip: isAnInternalCommand}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: isAnInternalCommand}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: isAnInternalCommand}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: isAnInternalCommand}, _shardsvrResolveView: {skip: isAnInternalCommand}, _shardsvrRunSearchIndexCommand: {skip: isAnInternalCommand}, diff --git a/jstests/sharding/database_versioning_all_commands.js b/jstests/sharding/database_versioning_all_commands.js index 6bf82118094..97b4770537c 100644 --- a/jstests/sharding/database_versioning_all_commands.js +++ b/jstests/sharding/database_versioning_all_commands.js @@ -1188,6 +1188,7 @@ const allTestCases = { }, }, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: "TODO"}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: "TODO"}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: "TODO"}, _shardsvrReshardingOperationTime: {skip: "TODO"}, _shardsvrResolveView: { diff --git a/jstests/sharding/libs/last_lts_mongod_commands.js b/jstests/sharding/libs/last_lts_mongod_commands.js index d47dd1a626c..d2982a4c117 100644 --- a/jstests/sharding/libs/last_lts_mongod_commands.js +++ b/jstests/sharding/libs/last_lts_mongod_commands.js @@ -49,6 +49,7 @@ export const commandsAddedToMongodSinceLastLTS = [ "_flushShardRegistry", "releaseMemory", "_shardsvrReshardingDonorFetchFinalCollectionStats", + "_shardsvrReshardingRecipientFetchFinalCollectionStats", "_shardsvrReshardingDonorStartChangeStreamsMonitor", "startTrafficRecording", "stopTrafficRecording", diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index 6a5a270fa75..625cb3c5bdf 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -199,6 +199,7 @@ let testCases = { _shardsvrRenameIndexMetadata: {skip: "internal command"}, _shardsvrReshardCollection: {skip: "internal command"}, _shardsvrReshardingDonorFetchFinalCollectionStats: {skip: "internal command"}, + _shardsvrReshardingRecipientFetchFinalCollectionStats: {skip: "internal command"}, _shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: "internal command"}, _shardsvrReshardingOperationTime: {skip: "internal command"}, _shardsvrReshardDonorInitialize: {skip: "internal command"}, diff --git a/src/mongo/db/s/BUILD.bazel b/src/mongo/db/s/BUILD.bazel index f586d42341a..ebb94b7826e 100644 --- a/src/mongo/db/s/BUILD.bazel +++ b/src/mongo/db/s/BUILD.bazel @@ -564,6 +564,7 @@ mongo_cc_library( "shardsvr_resharding_donor_fetch_final_collection_stats_command.cpp", "shardsvr_resharding_donor_start_change_streams_monitor_command.cpp", "shardsvr_resharding_operation_time_command.cpp", + "shardsvr_resharding_recipient_fetch_final_collection_stats_command.cpp", "split_vector_command.cpp", "txn_two_phase_commit_cmds.cpp", ":resharding_test_commands_gen", diff --git a/src/mongo/db/s/resharding/shardsvr_resharding_commands.idl b/src/mongo/db/s/resharding/shardsvr_resharding_commands.idl index 4d3664573ab..f8b21c75f5c 100644 --- a/src/mongo/db/s/resharding/shardsvr_resharding_commands.idl +++ b/src/mongo/db/s/resharding/shardsvr_resharding_commands.idl @@ -46,6 +46,15 @@ structs: type: safeInt64 description: "The change in the number of documents since the provided cloneTimestamp." + ShardsvrReshardingRecipientFetchFinalCollectionStatsResponse: + description: "Response for the _shardsvrReshardingRecipientFetchFinalCollectionStats command." + is_command_reply: true + strict: false + fields: + documentsDelta: + type: safeInt64 + description: "The change in the number of documents during the applying phase." + commands: _shardsvrReshardDonorInitialize: description: @@ -101,6 +110,22 @@ commands: type: uuid description: "The UUID for the resharding operation." + _shardsvrReshardingRecipientFetchFinalCollectionStats: + command_name: _shardsvrReshardingRecipientFetchFinalCollectionStats + cpp_name: ShardsvrReshardingRecipientFetchFinalCollectionStats + description: + "The internal command for querying a resharding recipient shard for the changes in + the number of documents in the collection being resharded during the applying phase." + namespace: type + type: namespacestring + reply_type: ShardsvrReshardingRecipientFetchFinalCollectionStatsResponse + api_version: "" + strict: false + fields: + reshardingUUID: + type: uuid + description: "The UUID for the resharding operation." + _shardsvrReshardRecipientInitialize: description: "The internal command sent by the coordinator to recipient shards to diff --git a/src/mongo/db/s/shardsvr_resharding_recipient_fetch_final_collection_stats_command.cpp b/src/mongo/db/s/shardsvr_resharding_recipient_fetch_final_collection_stats_command.cpp new file mode 100644 index 00000000000..5e517a5cf42 --- /dev/null +++ b/src/mongo/db/s/shardsvr_resharding_recipient_fetch_final_collection_stats_command.cpp @@ -0,0 +1,127 @@ +/** + * Copyright (C) 2026-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 + * . + * + * 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/base/error_codes.h" +#include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/resource_pattern.h" +#include "mongo/db/commands.h" +#include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/s/resharding/resharding_donor_recipient_common.h" +#include "mongo/db/s/resharding/resharding_recipient_service.h" +#include "mongo/db/s/resharding/shardsvr_resharding_commands_gen.h" +#include "mongo/db/service_context.h" +#include "mongo/logv2/log.h" +#include "mongo/s/resharding/resharding_feature_flag_gen.h" +#include "mongo/util/assert_util.h" + +#include + +#include + + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand + +namespace mongo { + +namespace { + +class ShardsvrReshardingRecipientFetchFinalCollectionStatsCommand + : public TypedCommand { +public: + using Request = ShardsvrReshardingRecipientFetchFinalCollectionStats; + using Response = ShardsvrReshardingRecipientFetchFinalCollectionStatsResponse; + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } + + bool adminOnly() const override { + return true; + } + + std::string help() const override { + return "Internal command for querying a resharding recipient shard for the change in the " + "number of documents in the collection being resharded during the applying phase."; + } + + class Invocation final : public InvocationBase { + public: + using InvocationBase::InvocationBase; + + Response typedRun(OperationContext* opCtx) { + opCtx->setAlwaysInterruptAtStepDownOrUp_UNSAFE(); + + uassert(ErrorCodes::IllegalOperation, + "_shardsvrReshardingRecipientFetchFinalCollectionStats is only supported on " + "shardsvr mongod", + serverGlobalParams.clusterRole.has(ClusterRole::ShardServer)); + + auto recipientMachine = resharding::tryGetReshardingStateMachineAndThrowIfShuttingDown< + ReshardingRecipientService, + ReshardingRecipientService::RecipientStateMachine, + ReshardingRecipientDocument>(opCtx, request().getReshardingUUID()); + + uassert(12723301, + str::stream() << "No resharding operation in progress with uuid " + << request().getReshardingUUID(), + recipientMachine); + + uasserted(ErrorCodes::NotImplemented, + "_shardsvrReshardingRecipientFetchFinalCollectionStats is not yet " + "implemented"); + } + + private: + NamespaceString ns() const override { + return request().getCommandParameter(); + } + + bool supportsWriteConcern() const override { + return false; + } + + void doCheckAuthorization(OperationContext* opCtx) const override { + uassert(ErrorCodes::Unauthorized, + "Unauthorized", + AuthorizationSession::get(opCtx->getClient()) + ->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(request().getDbName().tenantId()), + ActionType::internal)); + } + }; +}; + +MONGO_REGISTER_COMMAND(ShardsvrReshardingRecipientFetchFinalCollectionStatsCommand) + .requiresFeatureFlag(resharding::gFeatureFlagReshardingVerification) + .forShard(); + +} // namespace +} // namespace mongo