summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/views/views_all_commands.js1
-rw-r--r--jstests/replsets/db_reads_while_recovering_all_commands.js1
-rw-r--r--jstests/sharding/configsvr_remove_tags.js88
-rw-r--r--jstests/sharding/read_write_concern_defaults_application.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js1
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/config/configsvr_remove_tags_command.cpp144
-rw-r--r--src/mongo/db/transaction_validation.cpp3
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/request_types/remove_tags.idl43
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