diff options
-rw-r--r-- | jstests/core/views/views_all_commands.js | 1 | ||||
-rw-r--r-- | jstests/replsets/db_reads_while_recovering_all_commands.js | 1 | ||||
-rw-r--r-- | jstests/sharding/configsvr_remove_tags.js | 88 | ||||
-rw-r--r-- | jstests/sharding/read_write_concern_defaults_application.js | 1 | ||||
-rw-r--r-- | jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js | 1 | ||||
-rw-r--r-- | jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js | 1 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/config/configsvr_remove_tags_command.cpp | 144 | ||||
-rw-r--r-- | src/mongo/db/transaction_validation.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/request_types/remove_tags.idl | 43 |
11 files changed, 284 insertions, 1 deletions
diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index cbf327b1493..e7db4bbae74 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -102,6 +102,7 @@ let viewsCommandTests = { _configsvrRenameCollectionMetadata: {skip: isAnInternalCommand}, _configsvrRemoveShard: {skip: isAnInternalCommand}, _configsvrRemoveShardFromZone: {skip: isAnInternalCommand}, + _configsvrRemoveTags: {skip: isAnInternalCommand}, _configsvrReshardCollection: {skip: isAnInternalCommand}, _configsvrSetAllowMigrations: {skip: isAnInternalCommand}, _configsvrShardCollection: {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 1cc2ffb30d5..48ac6950557 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -50,6 +50,7 @@ const allCommands = { _configsvrRefineCollectionShardKey: {skip: isPrimaryOnly}, _configsvrRemoveShard: {skip: isPrimaryOnly}, _configsvrRemoveShardFromZone: {skip: isPrimaryOnly}, + _configsvrRemoveTags: {skip: isPrimaryOnly}, _configsvrRenameCollectionMetadata: {skip: isAnInternalCommand}, _configsvrReshardCollection: {skip: isPrimaryOnly}, _configsvrSetAllowMigrations: {skip: isPrimaryOnly}, diff --git a/jstests/sharding/configsvr_remove_tags.js b/jstests/sharding/configsvr_remove_tags.js new file mode 100644 index 00000000000..b43df3adef8 --- /dev/null +++ b/jstests/sharding/configsvr_remove_tags.js @@ -0,0 +1,88 @@ +/* + * Test the _configsvrRemoveTags internal command. + * @tags: [ + * requires_fcv_50, + * ] + */ + +(function() { +'use strict'; + +load("jstests/libs/retryable_writes_util.js"); + +function runConfigsvrRemoveTagsWithRetries(conn, ns, lsid, txnNumber) { + var res; + assert.soon(() => { + res = st.configRS.getPrimary().adminCommand({ + _configsvrRemoveTags: ns, + lsid: lsid, + txnNumber: txnNumber, + writeConcern: {w: "majority"} + }); + + if (RetryableWritesUtil.isRetryableCode(res.code) || + RetryableWritesUtil.errmsgContainsRetryableCodeName(res.errmsg) || + (res.writeConcernError && + RetryableWritesUtil.isRetryableCode(res.writeConcernError.code))) { + return false; // Retry + } + + return true; + }); + + return res; +} + +let st = new ShardingTest({mongos: 1, shards: 1}); + +const configDB = st.s.getDB('config'); + +const dbName = "test"; +const collName = "foo"; +const anotherCollName = "bar"; +const ns = dbName + "." + collName; +const anotherNs = dbName + "." + anotherCollName; + +let lsid = assert.commandWorked(st.s.getDB("admin").runCommand({startSession: 1})).id; + +// Create a zone +assert.commandWorked(st.s.adminCommand({addShardToZone: st.shard0.shardName, zone: 'zone0'})); + +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: ns, min: {x: 0}, max: {x: 10}, zone: 'zone0'})); +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: ns, min: {x: 10}, max: {x: 20}, zone: 'zone0'})); + +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: anotherNs, min: {x: 0}, max: {x: 10}, zone: 'zone0'})); +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: anotherNs, min: {x: 10}, max: {x: 20}, zone: 'zone0'})); + +assert.eq(2, configDB.tags.countDocuments({ns: ns})); +assert.eq(2, configDB.tags.countDocuments({ns: anotherNs})); + +// Remove tags matching 'ns' +assert.commandWorked( + runConfigsvrRemoveTagsWithRetries(st.configRS.getPrimary(), ns, lsid, NumberLong(1))); + +assert.eq(0, configDB.tags.countDocuments({ns: ns})); +assert.eq(2, configDB.tags.countDocuments({ns: anotherNs})); + +// Create new zones +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: ns, min: {x: 50}, max: {x: 60}, zone: 'zone0'})); +assert.commandWorked( + st.s.adminCommand({updateZoneKeyRange: ns, min: {x: 70}, max: {x: 80}, zone: 'zone0'})); + +assert.eq(2, configDB.tags.countDocuments({ns: ns})); + +// Check that _configsvrRemoveTags with a txnNumber lesser than the previous one for this session +assert.commandFailedWithCode( + runConfigsvrRemoveTagsWithRetries(st.configRS.getPrimary(), ns, lsid, NumberLong(0)), + ErrorCodes.TransactionTooOld); + +assert.eq(2, configDB.tags.countDocuments({ns: ns})); +assert.eq(2, configDB.tags.countDocuments({ns: anotherNs})); + +st.stop(); +})(); diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index 73f9d47617d..477ec0bee83 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -99,6 +99,7 @@ let testCases = { _configsvrRefineCollectionShardKey: {skip: "internal command"}, _configsvrRemoveShard: {skip: "internal command"}, _configsvrRemoveShardFromZone: {skip: "internal command"}, + _configsvrRemoveTags: {skip: "internal command"}, _configsvrRenameCollection: {skip: "internal command"}, _configsvrRenameCollectionMetadata: {skip: "internal command"}, _configsvrReshardCollection: {skip: "internal command"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js index 819e8eb29f7..4fe5768bdc0 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js @@ -66,6 +66,7 @@ let testCases = { _configsvrMoveChunk: {skip: "primary only"}, _configsvrMovePrimary: {skip: "primary only"}, _configsvrRemoveShardFromZone: {skip: "primary only"}, + _configsvrRemoveTags: {skip: "primary only"}, _configsvrReshardCollection: {skip: "primary only"}, _configsvrSetAllowMigrations: {skip: "primary only"}, _configsvrShardCollection: {skip: "primary only"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js index f36fa0792e6..321d4cede33 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js @@ -56,6 +56,7 @@ let testCases = { _configsvrMoveChunk: {skip: "primary only"}, _configsvrMovePrimary: {skip: "primary only"}, _configsvrRemoveShardFromZone: {skip: "primary only"}, + _configsvrRemoveTags: {skip: "primary only"}, _configsvrReshardCollection: {skip: "primary only"}, _configsvrSetAllowMigrations: {skip: "primary only"}, _configsvrShardCollection: {skip: "primary only"}, diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index 3d2c1a0e698..9545bd25389 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -317,6 +317,7 @@ env.Library( 'config/configsvr_refine_collection_shard_key_command.cpp', 'config/configsvr_remove_shard_command.cpp', 'config/configsvr_remove_shard_from_zone_command.cpp', + 'config/configsvr_remove_tags_command.cpp', 'config/configsvr_rename_collection_metadata_command.cpp', 'config/configsvr_reshard_collection_cmd.cpp', 'config/configsvr_set_allow_migrations_command.cpp', diff --git a/src/mongo/db/s/config/configsvr_remove_tags_command.cpp b/src/mongo/db/s/config/configsvr_remove_tags_command.cpp new file mode 100644 index 00000000000..dbb884783fc --- /dev/null +++ b/src/mongo/db/s/config/configsvr_remove_tags_command.cpp @@ -0,0 +1,144 @@ +/** + * Copyright (C) 2021-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/platform/basic.h" + +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/cancelable_operation_context.h" +#include "mongo/db/commands.h" +#include "mongo/db/dbdirectclient.h" +#include "mongo/db/repl/repl_client_info.h" +#include "mongo/db/session_catalog_mongod.h" +#include "mongo/db/transaction_participant.h" +#include "mongo/s/catalog/sharding_catalog_client.h" +#include "mongo/s/catalog/type_tags.h" +#include "mongo/s/grid.h" +#include "mongo/s/request_types/remove_tags_gen.h" + +namespace mongo { +namespace { + +class ConfigsvrRemoveTagsCommand final : public TypedCommand<ConfigsvrRemoveTagsCommand> { +public: + using Request = ConfigsvrRemoveTags; + + class Invocation final : public InvocationBase { + public: + using InvocationBase::InvocationBase; + + void typedRun(OperationContext* opCtx) { + const NamespaceString& nss = ns(); + + opCtx->setAlwaysInterruptAtStepDownOrUp(); + + uassert(ErrorCodes::IllegalOperation, + "_configsvrRemoveTags can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); + uassert(ErrorCodes::InvalidOptions, + "_configsvrRemoveTags must be called with majority writeConcern", + opCtx->getWriteConcern().wMode == WriteConcernOptions::kMajority); + + // Set the operation context read concern level to local for reads into the config + // database. + repl::ReadConcernArgs::get(opCtx) = + repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern); + + auto txnParticipant = TransactionParticipant::get(opCtx); + uassert( + 5748800, "_configsvrRemoveTags must be run as a retryable write", txnParticipant); + + { + auto newClient = opCtx->getServiceContext()->makeClient("RemoveTagsMetadata"); + { + stdx::lock_guard<Client> lk(*newClient.get()); + newClient->setSystemOperationKillableByStepdown(lk); + } + + AlternativeClientRegion acr(newClient); + auto executor = + Grid::get(opCtx->getServiceContext())->getExecutorPool()->getFixedExecutor(); + auto newOpCtxPtr = CancelableOperationContext( + cc().makeOperationContext(), opCtx->getCancellationToken(), executor); + + uassertStatusOK( + Grid::get(newOpCtxPtr.get()) + ->catalogClient() + ->removeConfigDocuments(newOpCtxPtr.get(), + TagsType::ConfigNS, + BSON(TagsType::ns(nss.ns())), + ShardingCatalogClient::kLocalWriteConcern)); + } + + // Since we no write happened on this txnNumber, we need to make a dummy write so that + // secondaries can be aware of this txn. + DBDirectClient client(opCtx); + client.update(NamespaceString::kServerConfigurationNamespace.ns(), + BSON("_id" + << "RemoveTagsMetadataStats"), + BSON("$inc" << BSON("count" << 1)), + true /* upsert */, + false /* multi */); + } + + private: + NamespaceString ns() const override { + return request().getCommandParameter(); + } + + 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)); + } + }; + + std::string help() const override { + return "Internal command, which is exported by the sharding config server. Do not call " + "directly. Removes the zone tags for the specified ns."; + } + + bool adminOnly() const override { + return true; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } +} configsvrRemoveTagsCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/transaction_validation.cpp b/src/mongo/db/transaction_validation.cpp index f0dc4e69887..d0ceebc6edb 100644 --- a/src/mongo/db/transaction_validation.cpp +++ b/src/mongo/db/transaction_validation.cpp @@ -50,7 +50,8 @@ const StringMap<int> retryableWriteCommands = {{"delete", 1}, {"findAndModify", 1}, {"insert", 1}, {"update", 1}, - {"_recvChunkStart", 1}}; + {"_recvChunkStart", 1}, + {"_configsvrRemoveTags", 1}}; // Commands that can be sent with session info but should not check out a session. const StringMap<int> skipSessionCheckoutList = { diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 97ade90b2d8..5695f532133 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -169,6 +169,7 @@ env.Library( 'request_types/move_primary.idl', 'request_types/refine_collection_shard_key.idl', 'request_types/remove_shard_from_zone_request_type.cpp', + 'request_types/remove_tags.idl', 'request_types/reshard_collection.idl', 'request_types/resharding_operation_time.idl', 'request_types/set_allow_migrations.idl', diff --git a/src/mongo/s/request_types/remove_tags.idl b/src/mongo/s/request_types/remove_tags.idl new file mode 100644 index 00000000000..c0d91aae56c --- /dev/null +++ b/src/mongo/s/request_types/remove_tags.idl @@ -0,0 +1,43 @@ +# Copyright (C) 2021-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: + _configsvrRemoveTags: + command_name: _configsvrRemoveTags + cpp_name: ConfigsvrRemoveTags + description: "internal _configsvrRemoveTags command for config server" + namespace: type + api_version: "" + type: namespacestring + strict: false |