summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands.cpp14
-rw-r--r--src/mongo/db/commands.h6
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/config/configsvr_move_primary_command.cpp285
-rw-r--r--src/mongo/s/commands/cluster_move_primary_cmd.cpp247
-rw-r--r--src/mongo/s/request_types/move_primary.idl11
6 files changed, 313 insertions, 251 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index ebf796282e6..ce98a97f97f 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -75,6 +75,20 @@ ExportedServerParameter<bool, ServerParameterType::kStartupOnly> testCommandsPar
Command::~Command() = default;
+BSONObj Command::appendPassthroughFields(const BSONObj& cmdObjWithPassthroughFields,
+ const BSONObj& request) {
+ BSONObjBuilder b;
+ b.appendElements(request);
+ for (const auto& elem : cmdObjWithPassthroughFields) {
+ const auto name = elem.fieldNameStringData();
+ // $db is one of the generic arguments, but is implicitly contained in request
+ if (Command::isGenericArgument(name) && !request.hasField(name) && name != "$db") {
+ b.append(elem);
+ }
+ }
+ return b.obj();
+}
+
string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) {
BSONElement first = cmdObj.firstElement();
uassert(ErrorCodes::BadValue,
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 6ad9e536b47..13db6740e6b 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -488,6 +488,12 @@ public:
const BSONObj& cmdObj);
/**
+ * Appends passthrough fields from a cmdObj to a given request.
+ */
+ static BSONObj appendPassthroughFields(const BSONObj& cmdObjWithPassthroughFields,
+ const BSONObj& request);
+
+ /**
* Returns true if the provided argument is one that is handled by the command processing layer
* and should generally be ignored by individual command implementations. In particular,
* commands that fail on unrecognized arguments must not fail for any of these.
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index 841865d36a1..94d4ce8b128 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -202,6 +202,7 @@ env.Library(
'$BUILD_DIR/mongo/db/dbhelpers',
'$BUILD_DIR/mongo/db/index_d',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_global',
+ '$BUILD_DIR/mongo/s/commands/shared_cluster_commands',
'$BUILD_DIR/mongo/s/sharding_request_types',
'balancer',
'collection_metadata',
diff --git a/src/mongo/db/s/config/configsvr_move_primary_command.cpp b/src/mongo/db/s/config/configsvr_move_primary_command.cpp
index b186b811fae..043db353644 100644
--- a/src/mongo/db/s/config/configsvr_move_primary_command.cpp
+++ b/src/mongo/db/s/config/configsvr_move_primary_command.cpp
@@ -17,40 +17,43 @@
* 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 GNU Affero General 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.
+ * must comply with the GNU Affero General 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding
#include "mongo/platform/basic.h"
-#include "mongo/db/audit.h"
+#include "mongo/client/connpool.h"
+#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/auth/privilege.h"
+#include "mongo/db/catalog/document_validation.h"
+#include "mongo/db/client.h"
#include "mongo/db/commands.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/db/repl/repl_set_config.h"
-#include "mongo/db/repl/replication_coordinator.h"
-#include "mongo/s/catalog/sharding_catalog_manager.h"
-#include "mongo/s/catalog/type_shard.h"
+#include "mongo/db/operation_context.h"
+#include "mongo/s/catalog/sharding_catalog_client.h"
+#include "mongo/s/catalog/type_database.h"
+#include "mongo/s/catalog_cache.h"
+#include "mongo/s/client/shard_registry.h"
+#include "mongo/s/commands/cluster_commands_helpers.h"
#include "mongo/s/grid.h"
#include "mongo/s/request_types/move_primary_gen.h"
#include "mongo/util/log.h"
-#include "mongo/util/mongoutils/str.h"
+#include "mongo/util/scopeguard.h"
namespace mongo {
-namespace {
using std::string;
-const long long kMaxSizeMBDefault = 0;
+namespace {
/**
* Internal sharding command run on config servers to change a database's primary shard.
@@ -59,38 +62,48 @@ class ConfigSvrMovePrimaryCommand : public Command {
public:
ConfigSvrMovePrimaryCommand() : Command("_configsvrMovePrimary") {}
- void help(std::stringstream& help) const override {
- help << "Internal command, which is exported by the sharding config server. Do not call "
- "directly. Reassigns the primary shard of a database.";
- }
-
- bool slaveOk() const override {
+ virtual bool slaveOk() const {
return false;
}
- bool adminOnly() const override {
+ virtual bool adminOnly() const {
return true;
}
- bool supportsWriteConcern(const BSONObj& cmd) const override {
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
return true;
}
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) override {
+ virtual void help(std::stringstream& help) const override {
+ help << "Internal command, which is exported by the sharding config server. Do not call "
+ "directly. Reassigns the primary shard of a database.";
+ }
+
+ virtual Status checkAuthForCommand(Client* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) override {
if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
ResourcePattern::forClusterResource(), ActionType::internal)) {
return Status(ErrorCodes::Unauthorized, "Unauthorized");
}
+
return Status::OK();
}
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ const auto nsElt = cmdObj.firstElement();
+ uassert(ErrorCodes::InvalidNamespace,
+ "'movePrimary' must be of type String",
+ nsElt.type() == BSONType::String);
+ return nsElt.str();
+ }
+
bool run(OperationContext* opCtx,
- const std::string& unusedDbName,
+ const std::string& dbname_unused,
const BSONObj& cmdObj,
std::string& errmsg,
- BSONObjBuilder& result) override {
+ BSONObjBuilder& result) {
+
if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) {
return appendCommandStatus(
result,
@@ -98,8 +111,220 @@ public:
"_configsvrMovePrimary can only be run on config servers"));
}
+ auto movePrimaryRequest =
+ MovePrimary::parse(IDLParserErrorContext("ConfigSvrMovePrimary"), cmdObj);
+ const string dbname = parseNs("", cmdObj);
+
+ uassert(
+ ErrorCodes::InvalidNamespace,
+ str::stream() << "invalid db name specified: " << dbname,
+ NamespaceString::validDBName(dbname, NamespaceString::DollarInDbNameBehavior::Allow));
+
+ if (dbname == NamespaceString::kAdminDb || dbname == NamespaceString::kConfigDb ||
+ dbname == NamespaceString::kLocalDb) {
+ return appendCommandStatus(
+ result,
+ {ErrorCodes::InvalidOptions,
+ str::stream() << "Can't move primary for " << dbname << " database"});
+ }
+
+ auto const catalogClient = Grid::get(opCtx)->catalogClient(opCtx);
+ auto const catalogCache = Grid::get(opCtx)->catalogCache();
+ auto const shardRegistry = Grid::get(opCtx)->shardRegistry();
+
+ auto dbType = uassertStatusOK(catalogClient->getDatabase(opCtx, dbname)).value;
+
+ const std::string to = movePrimaryRequest.getTo().toString();
+
+ if (to.empty()) {
+ return appendCommandStatus(
+ result,
+ {ErrorCodes::InvalidOptions,
+ str::stream() << "you have to specify where you want to move it"});
+ }
+
+ const auto fromShard = uassertStatusOK(shardRegistry->getShard(opCtx, dbType.getPrimary()));
+
+ const auto toShard = [&]() {
+ auto toShardStatus = shardRegistry->getShard(opCtx, to);
+ if (!toShardStatus.isOK()) {
+ const std::string msg(
+ str::stream() << "Could not move database '" << dbname << "' to shard '" << to
+ << "' due to "
+ << toShardStatus.getStatus().reason());
+ log() << msg;
+ uasserted(toShardStatus.getStatus().code(), msg);
+ }
+
+ return toShardStatus.getValue();
+ }();
+
+ uassert(ErrorCodes::IllegalOperation,
+ "it is already the primary",
+ fromShard->getId() != toShard->getId());
+
+ log() << "Moving " << dbname << " primary from: " << fromShard->toString()
+ << " to: " << toShard->toString();
+
+ const std::string whyMessage(str::stream() << "Moving primary shard of " << dbname);
+ auto scopedDistLock = uassertStatusOK(catalogClient->getDistLockManager()->lock(
+ opCtx, dbname + "-movePrimary", whyMessage, DistLockManager::kDefaultLockTimeout));
+
+ const auto shardedColls = getAllShardedCollectionsForDb(opCtx, dbname);
+
+ // Record start in changelog
+ uassertStatusOK(catalogClient->logChange(
+ opCtx,
+ "movePrimary.start",
+ dbname,
+ _buildMoveLogEntry(dbname, fromShard->toString(), toShard->toString(), shardedColls),
+ ShardingCatalogClient::kMajorityWriteConcern));
+
+ ScopedDbConnection toconn(toShard->getConnString());
+ ON_BLOCK_EXIT([&toconn] { toconn.done(); });
+
+ // TODO ERH - we need a clone command which replays operations from clone start to now
+ // can just use local.oplog.$main
+ BSONObj cloneRes;
+ bool hasWCError = false;
+
+ {
+ BSONArrayBuilder barr;
+ for (const auto& shardedColl : shardedColls) {
+ barr.append(shardedColl.ns());
+ }
+
+ const bool worked = toconn->runCommand(
+ dbname,
+ BSON("clone" << fromShard->getConnString().toString() << "collsToIgnore"
+ << barr.arr()
+ << bypassDocumentValidationCommandOption()
+ << true
+ << "writeConcern"
+ << opCtx->getWriteConcern().toBSON()),
+ cloneRes);
+
+ if (!worked) {
+ log() << "clone failed" << redact(cloneRes);
+ return appendCommandStatus(
+ result, {ErrorCodes::OperationFailed, str::stream() << "clone failed"});
+ }
+
+ if (auto wcErrorElem = cloneRes["writeConcernError"]) {
+ appendWriteConcernErrorToCmdResponse(toShard->getId(), wcErrorElem, result);
+ hasWCError = true;
+ }
+ }
+
+ // Update the new primary in the config server metadata
+ {
+ auto dbt = uassertStatusOK(catalogClient->getDatabase(opCtx, dbname)).value;
+ dbt.setPrimary(toShard->getId());
+ uassertStatusOK(catalogClient->updateDatabase(opCtx, dbname, dbt));
+ }
+
+ // Ensure the next attempt to retrieve the database or any of its collections will do a full
+ // reload
+ catalogCache->purgeDatabase(dbname);
+
+ const string oldPrimary = fromShard->getConnString().toString();
+
+ ScopedDbConnection fromconn(fromShard->getConnString());
+ ON_BLOCK_EXIT([&fromconn] { fromconn.done(); });
+
+ if (shardedColls.empty()) {
+ // TODO: Collections can be created in the meantime, and we should handle in the future.
+ log() << "movePrimary dropping database on " << oldPrimary
+ << ", no sharded collections in " << dbname;
+
+ try {
+ BSONObj dropDBInfo;
+ fromconn->dropDatabase(dbname.c_str(), opCtx->getWriteConcern(), &dropDBInfo);
+ if (!hasWCError) {
+ if (auto wcErrorElem = dropDBInfo["writeConcernError"]) {
+ appendWriteConcernErrorToCmdResponse(
+ fromShard->getId(), wcErrorElem, result);
+ hasWCError = true;
+ }
+ }
+ } catch (DBException& e) {
+ e.addContext(str::stream() << "movePrimary could not drop the database " << dbname
+ << " on "
+ << oldPrimary);
+ throw;
+ }
+
+ } else if (cloneRes["clonedColls"].type() != Array) {
+ // Legacy behavior from old mongod with sharded collections, *do not* delete
+ // database, but inform user they can drop manually (or ignore).
+ warning() << "movePrimary legacy mongod behavior detected. "
+ << "User must manually remove unsharded collections in database " << dbname
+ << " on " << oldPrimary;
+ } else {
+ // We moved some unsharded collections, but not all
+ BSONObjIterator it(cloneRes["clonedColls"].Obj());
+
+ while (it.more()) {
+ BSONElement el = it.next();
+ if (el.type() == String) {
+ try {
+ log() << "movePrimary dropping cloned collection " << el.String() << " on "
+ << oldPrimary;
+ BSONObj dropCollInfo;
+ fromconn->dropCollection(
+ el.String(), opCtx->getWriteConcern(), &dropCollInfo);
+ if (!hasWCError) {
+ if (auto wcErrorElem = dropCollInfo["writeConcernError"]) {
+ appendWriteConcernErrorToCmdResponse(
+ fromShard->getId(), wcErrorElem, result);
+ hasWCError = true;
+ }
+ }
+
+ } catch (DBException& e) {
+ e.addContext(str::stream()
+ << "movePrimary could not drop the cloned collection "
+ << el.String()
+ << " on "
+ << oldPrimary);
+ throw;
+ }
+ }
+ }
+ }
+
+ result << "primary" << toShard->toString();
+
+ // Record finish in changelog
+ uassertStatusOK(catalogClient->logChange(
+ opCtx,
+ "movePrimary",
+ dbname,
+ _buildMoveLogEntry(dbname, oldPrimary, toShard->toString(), shardedColls),
+ ShardingCatalogClient::kMajorityWriteConcern));
+
return true;
}
+
+private:
+ static BSONObj _buildMoveLogEntry(const std::string& db,
+ const std::string& from,
+ const std::string& to,
+ const std::vector<NamespaceString>& shardedColls) {
+ BSONObjBuilder details;
+ details.append("database", db);
+ details.append("from", from);
+ details.append("to", to);
+
+ BSONArrayBuilder collB(details.subarrayStart("shardedCollections"));
+ for (const auto& shardedColl : shardedColls) {
+ collB.append(shardedColl.ns());
+ }
+ collB.done();
+
+ return details.obj();
+ }
+
} configsvrMovePrimaryCmd;
} // namespace
diff --git a/src/mongo/s/commands/cluster_move_primary_cmd.cpp b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
index 2e0f977753f..4c47ad42982 100644
--- a/src/mongo/s/commands/cluster_move_primary_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2015 MongoDB Inc.
+ * Copyright (C) 2017 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
@@ -30,32 +30,25 @@
#include "mongo/platform/basic.h"
-#include <set>
-
-#include "mongo/client/connpool.h"
-#include "mongo/db/auth/action_set.h"
+#include "mongo/bson/util/bson_extract.h"
+#include "mongo/db/audit.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/catalog/document_validation.h"
-#include "mongo/db/client.h"
-#include "mongo/db/client.h"
#include "mongo/db/commands.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/rpc/write_concern_error_detail.h"
#include "mongo/s/catalog/sharding_catalog_client.h"
-#include "mongo/s/catalog/type_database.h"
+#include "mongo/s/catalog/type_shard.h"
#include "mongo/s/catalog_cache.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/commands/cluster_commands_helpers.h"
#include "mongo/s/grid.h"
#include "mongo/s/request_types/move_primary_gen.h"
#include "mongo/util/log.h"
+#include "mongo/util/scopeguard.h"
namespace mongo {
-using std::shared_ptr;
-using std::set;
using std::string;
namespace {
@@ -72,7 +65,6 @@ public:
return true;
}
-
virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
return true;
}
@@ -101,229 +93,42 @@ public:
}
virtual bool run(OperationContext* opCtx,
- const std::string& dbname_unused,
+ const std::string& dbname,
const BSONObj& cmdObj,
std::string& errmsg,
BSONObjBuilder& result) {
auto movePrimaryRequest = MovePrimary::parse(IDLParserErrorContext("MovePrimary"), cmdObj);
- const string dbname = parseNs("", cmdObj);
-
- uassert(
- ErrorCodes::InvalidNamespace,
- str::stream() << "invalid db name specified: " << dbname,
- NamespaceString::validDBName(dbname, NamespaceString::DollarInDbNameBehavior::Allow));
-
- if (dbname == NamespaceString::kAdminDb || dbname == NamespaceString::kConfigDb ||
- dbname == NamespaceString::kLocalDb) {
- errmsg = "can't move primary for " + dbname + " database";
- return false;
- }
-
- auto const catalogClient = Grid::get(opCtx)->catalogClient(opCtx);
- auto const catalogCache = Grid::get(opCtx)->catalogCache();
- auto const shardRegistry = Grid::get(opCtx)->shardRegistry();
-
- // Flush all cached information. This can't be perfect, but it's better than nothing.
- catalogCache->purgeDatabase(dbname);
-
- auto dbInfo = uassertStatusOK(catalogCache->getDatabase(opCtx, dbname));
-
- const std::string to = movePrimaryRequest.getTo().toString();
-
- if (to.empty()) {
- errmsg = "you have to specify where you want to move it";
- return false;
- }
-
- const auto fromShard = uassertStatusOK(shardRegistry->getShard(opCtx, dbInfo.primaryId()));
-
- const auto toShard = [&]() {
- auto toShardStatus = shardRegistry->getShard(opCtx, to);
- if (!toShardStatus.isOK()) {
- const std::string msg(
- str::stream() << "Could not move database '" << dbname << "' to shard '" << to
- << "' due to "
- << toShardStatus.getStatus().reason());
- log() << msg;
- uasserted(toShardStatus.getStatus().code(), msg);
- }
-
- return toShardStatus.getValue();
- }();
-
- uassert(ErrorCodes::IllegalOperation,
- "it is already the primary",
- fromShard->getId() != toShard->getId());
-
- log() << "Moving " << dbname << " primary from: " << fromShard->toString()
- << " to: " << toShard->toString();
-
- const std::string whyMessage(str::stream() << "Moving primary shard of " << dbname);
- auto scopedDistLock = uassertStatusOK(catalogClient->getDistLockManager()->lock(
- opCtx, dbname + "-movePrimary", whyMessage, DistLockManager::kDefaultLockTimeout));
-
- const auto shardedColls = getAllShardedCollectionsForDb(opCtx, dbname);
-
- // Record start in changelog
- catalogClient
- ->logChange(opCtx,
- "movePrimary.start",
- dbname,
- _buildMoveLogEntry(
- dbname, fromShard->toString(), toShard->toString(), shardedColls),
- ShardingCatalogClient::kMajorityWriteConcern)
- .transitional_ignore();
-
- ScopedDbConnection toconn(toShard->getConnString());
+ const string db = parseNs("", cmdObj);
+ const NamespaceString nss(db);
- // TODO ERH - we need a clone command which replays operations from clone start to now
- // can just use local.oplog.$main
- BSONObj cloneRes;
- bool hasWCError = false;
+ ConfigsvrMovePrimary configMovePrimaryRequest;
+ configMovePrimaryRequest.set_configsvrMovePrimary(nss);
+ configMovePrimaryRequest.setTo(movePrimaryRequest.getTo());
- {
- BSONArrayBuilder barr;
- for (const auto& shardedColl : shardedColls) {
- barr.append(shardedColl.ns());
- }
+ // Invalidate the routing table cache entry for this database so that we reload the
+ // collection the next time it's accessed, even if we receive a failure, e.g. NetworkError.
+ ON_BLOCK_EXIT([opCtx, db] { Grid::get(opCtx)->catalogCache()->purgeDatabase(db); });
- const bool worked = toconn->runCommand(
- dbname,
- BSON("clone" << fromShard->getConnString().toString() << "collsToIgnore"
- << barr.arr()
- << bypassDocumentValidationCommandOption()
- << true
- << "writeConcern"
- << opCtx->getWriteConcern().toBSON()),
- cloneRes);
- toconn.done();
+ auto configShard = Grid::get(opCtx)->shardRegistry()->getConfigShard();
- if (!worked) {
- log() << "clone failed" << redact(cloneRes);
- errmsg = "clone failed";
- return false;
- }
+ auto cmdResponseStatus = uassertStatusOK(configShard->runCommandWithFixedRetryAttempts(
+ opCtx,
+ ReadPreferenceSetting(ReadPreference::PrimaryOnly),
+ "admin",
+ Command::appendPassthroughFields(cmdObj, configMovePrimaryRequest.toBSON()),
+ Shard::RetryPolicy::kIdempotent));
+ uassertStatusOK(cmdResponseStatus.commandStatus);
- if (auto wcErrorElem = cloneRes["writeConcernError"]) {
- appendWriteConcernErrorToCmdResponse(toShard->getId(), wcErrorElem, result);
- hasWCError = true;
- }
+ if (!cmdResponseStatus.writeConcernStatus.isOK()) {
+ appendWriteConcernErrorToCmdResponse(
+ configShard->getId(), cmdResponseStatus.response["writeConcernError"], result);
}
- // Update the new primary in the config server metadata
- {
- auto dbt = uassertStatusOK(catalogClient->getDatabase(opCtx, dbname)).value;
- dbt.setPrimary(toShard->getId());
-
- uassertStatusOK(catalogClient->updateDatabase(opCtx, dbname, dbt));
- }
-
- // Ensure the next attempt to retrieve the database or any of its collections will do a full
- // reload
- catalogCache->purgeDatabase(dbname);
-
- const string oldPrimary = fromShard->getConnString().toString();
-
- ScopedDbConnection fromconn(fromShard->getConnString());
-
- if (shardedColls.empty()) {
- // TODO: Collections can be created in the meantime, and we should handle in the future.
- log() << "movePrimary dropping database on " << oldPrimary
- << ", no sharded collections in " << dbname;
-
- try {
- BSONObj dropDBInfo;
- fromconn->dropDatabase(dbname.c_str(), opCtx->getWriteConcern(), &dropDBInfo);
- if (!hasWCError) {
- if (auto wcErrorElem = dropDBInfo["writeConcernError"]) {
- appendWriteConcernErrorToCmdResponse(
- fromShard->getId(), wcErrorElem, result);
- hasWCError = true;
- }
- }
- } catch (DBException& e) {
- e.addContext(str::stream() << "movePrimary could not drop the database " << dbname
- << " on "
- << oldPrimary);
- throw;
- }
-
- } else if (cloneRes["clonedColls"].type() != Array) {
- // Legacy behavior from old mongod with sharded collections, *do not* delete
- // database, but inform user they can drop manually (or ignore).
- warning() << "movePrimary legacy mongod behavior detected. "
- << "User must manually remove unsharded collections in database " << dbname
- << " on " << oldPrimary;
- } else {
- // We moved some unsharded collections, but not all
- BSONObjIterator it(cloneRes["clonedColls"].Obj());
-
- while (it.more()) {
- BSONElement el = it.next();
- if (el.type() == String) {
- try {
- log() << "movePrimary dropping cloned collection " << el.String() << " on "
- << oldPrimary;
- BSONObj dropCollInfo;
- fromconn->dropCollection(
- el.String(), opCtx->getWriteConcern(), &dropCollInfo);
- if (!hasWCError) {
- if (auto wcErrorElem = dropCollInfo["writeConcernError"]) {
- appendWriteConcernErrorToCmdResponse(
- fromShard->getId(), wcErrorElem, result);
- hasWCError = true;
- }
- }
-
- } catch (DBException& e) {
- e.addContext(str::stream()
- << "movePrimary could not drop the cloned collection "
- << el.String()
- << " on "
- << oldPrimary);
- throw;
- }
- }
- }
- }
-
- fromconn.done();
-
- result << "primary" << toShard->toString();
-
- // Record finish in changelog
- catalogClient
- ->logChange(opCtx,
- "movePrimary",
- dbname,
- _buildMoveLogEntry(dbname, oldPrimary, toShard->toString(), shardedColls),
- ShardingCatalogClient::kMajorityWriteConcern)
- .transitional_ignore();
-
return true;
}
-private:
- static BSONObj _buildMoveLogEntry(const std::string& db,
- const std::string& from,
- const std::string& to,
- const std::vector<NamespaceString>& shardedColls) {
- BSONObjBuilder details;
- details.append("database", db);
- details.append("from", from);
- details.append("to", to);
-
- BSONArrayBuilder collB(details.subarrayStart("shardedCollections"));
- for (const auto& shardedColl : shardedColls) {
- collB.append(shardedColl.ns());
- }
- collB.done();
-
- return details.obj();
- }
-
} clusterMovePrimaryCmd;
} // namespace
diff --git a/src/mongo/s/request_types/move_primary.idl b/src/mongo/s/request_types/move_primary.idl
index a8909f7fd4b..d4f79660e60 100644
--- a/src/mongo/s/request_types/move_primary.idl
+++ b/src/mongo/s/request_types/move_primary.idl
@@ -48,3 +48,14 @@ structs:
to:
type: string
description: "The shard serving as the destination for un-sharded collections."
+
+ ConfigsvrMovePrimary:
+ description: "The internal movePrimary command on the config server"
+ strict: false
+ fields:
+ _configsvrMovePrimary:
+ type: namespacestring
+ description: "The namespace of the database whose primary shard is to be reassigned."
+ to:
+ type: string
+ description: "The shard serving as the destination for un-sharded collections." \ No newline at end of file