summaryrefslogtreecommitdiff
path: root/src/mongo/s/commands/cluster_move_primary_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/s/commands/cluster_move_primary_cmd.cpp')
-rw-r--r--src/mongo/s/commands/cluster_move_primary_cmd.cpp365
1 files changed, 174 insertions, 191 deletions
diff --git a/src/mongo/s/commands/cluster_move_primary_cmd.cpp b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
index 227830f410d..f9d401a26b6 100644
--- a/src/mongo/s/commands/cluster_move_primary_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
@@ -51,242 +51,225 @@
namespace mongo {
- using std::shared_ptr;
- using std::set;
- using std::string;
+using std::shared_ptr;
+using std::set;
+using std::string;
namespace {
- class MoveDatabasePrimaryCommand : public Command {
- public:
- MoveDatabasePrimaryCommand() : Command("movePrimary", false, "moveprimary") { }
+class MoveDatabasePrimaryCommand : public Command {
+public:
+ MoveDatabasePrimaryCommand() : Command("movePrimary", false, "moveprimary") {}
- virtual bool slaveOk() const {
- return true;
- }
+ virtual bool slaveOk() const {
+ return true;
+ }
- virtual bool adminOnly() const {
- return true;
- }
+ virtual bool adminOnly() const {
+ return true;
+ }
- virtual bool isWriteCommandForConfigServer() const {
- return false;
- }
+ virtual bool isWriteCommandForConfigServer() const {
+ return false;
+ }
+
+ virtual void help(std::stringstream& help) const {
+ help << " example: { moveprimary : 'foo' , to : 'localhost:9999' }";
+ }
- virtual void help(std::stringstream& help) const {
- help << " example: { moveprimary : 'foo' , to : 'localhost:9999' }";
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(parseNs(dbname, cmdObj)), ActionType::moveChunk)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
}
- virtual Status checkAuthForCommand(ClientBasic* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
+ return Status::OK();
+ }
- if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(
- parseNs(dbname, cmdObj)),
- ActionType::moveChunk)) {
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
- }
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ return cmdObj.firstElement().str();
+ }
+
+ virtual bool run(OperationContext* txn,
+ const std::string& dbname_unused,
+ BSONObj& cmdObj,
+ int options,
+ std::string& errmsg,
+ BSONObjBuilder& result) {
+ const string dbname = parseNs("", cmdObj);
- return Status::OK();
+ if (dbname.empty() || !nsIsDbOnly(dbname)) {
+ errmsg = "invalid db name specified: " + dbname;
+ return false;
}
- virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
- return cmdObj.firstElement().str();
+ if (dbname == "admin" || dbname == "config" || dbname == "local") {
+ errmsg = "can't move primary for " + dbname + " database";
+ return false;
}
- virtual bool run(OperationContext* txn,
- const std::string& dbname_unused,
- BSONObj& cmdObj,
- int options,
- std::string& errmsg,
- BSONObjBuilder& result) {
+ // Flush all cached information. This can't be perfect, but it's better than nothing.
+ grid.catalogCache()->invalidate(dbname);
- const string dbname = parseNs("", cmdObj);
+ auto status = grid.catalogCache()->getDatabase(dbname);
+ if (!status.isOK()) {
+ return appendCommandStatus(result, status.getStatus());
+ }
- if (dbname.empty() || !nsIsDbOnly(dbname)) {
- errmsg = "invalid db name specified: " + dbname;
- return false;
- }
+ shared_ptr<DBConfig> config = status.getValue();
- if (dbname == "admin" || dbname == "config" || dbname == "local") {
- errmsg = "can't move primary for " + dbname + " database";
- return false;
- }
+ const string to = cmdObj["to"].valuestrsafe();
+ if (!to.size()) {
+ errmsg = "you have to specify where you want to move it";
+ return false;
+ }
- // Flush all cached information. This can't be perfect, but it's better than nothing.
- grid.catalogCache()->invalidate(dbname);
+ shared_ptr<Shard> toShard = grid.shardRegistry()->getShard(to);
+ if (!toShard) {
+ string msg(str::stream() << "Could not move database '" << dbname << "' to shard '"
+ << to << "' because the shard does not exist");
+ log() << msg;
+ return appendCommandStatus(result, Status(ErrorCodes::ShardNotFound, msg));
+ }
- auto status = grid.catalogCache()->getDatabase(dbname);
- if (!status.isOK()) {
- return appendCommandStatus(result, status.getStatus());
- }
+ shared_ptr<Shard> fromShard = grid.shardRegistry()->getShard(config->getPrimaryId());
+ invariant(fromShard);
- shared_ptr<DBConfig> config = status.getValue();
+ if (fromShard->getConnString().sameLogicalEndpoint(toShard->getConnString())) {
+ errmsg = "it is already the primary";
+ return false;
+ }
- const string to = cmdObj["to"].valuestrsafe();
- if (!to.size()) {
- errmsg = "you have to specify where you want to move it";
- return false;
- }
+ if (!grid.catalogManager()->isShardHost(toShard->getConnString())) {
+ errmsg = "that server isn't known to me";
+ return false;
+ }
- shared_ptr<Shard> toShard = grid.shardRegistry()->getShard(to);
- if (!toShard) {
- string msg(str::stream() << "Could not move database '" << dbname
- << "' to shard '" << to
- << "' because the shard does not exist");
- log() << msg;
- return appendCommandStatus(result,
- Status(ErrorCodes::ShardNotFound, msg));
- }
+ log() << "Moving " << dbname << " primary from: " << fromShard->toString()
+ << " to: " << toShard->toString();
- shared_ptr<Shard> fromShard =
- grid.shardRegistry()->getShard(config->getPrimaryId());
- invariant(fromShard);
+ string whyMessage(str::stream() << "Moving primary shard of " << dbname);
+ auto scopedDistLock =
+ grid.catalogManager()->getDistLockManager()->lock(dbname + "-movePrimary", whyMessage);
- if (fromShard->getConnString().sameLogicalEndpoint(toShard->getConnString())) {
- errmsg = "it is already the primary";
- return false;
- }
+ if (!scopedDistLock.isOK()) {
+ return appendCommandStatus(result, scopedDistLock.getStatus());
+ }
- if (!grid.catalogManager()->isShardHost(toShard->getConnString())) {
- errmsg = "that server isn't known to me";
- return false;
- }
+ set<string> shardedColls;
+ config->getAllShardedCollections(shardedColls);
- log() << "Moving " << dbname << " primary from: "
- << fromShard->toString() << " to: " << toShard->toString();
+ // Record start in changelog
+ BSONObj moveStartDetails =
+ _buildMoveEntry(dbname, fromShard->toString(), toShard->toString(), shardedColls);
- string whyMessage(str::stream() << "Moving primary shard of " << dbname);
- auto scopedDistLock = grid.catalogManager()->getDistLockManager()->lock(
- dbname + "-movePrimary", whyMessage);
+ grid.catalogManager()->logChange(txn, "movePrimary.start", dbname, moveStartDetails);
- if (!scopedDistLock.isOK()) {
- return appendCommandStatus(result, scopedDistLock.getStatus());
- }
+ BSONArrayBuilder barr;
+ barr.append(shardedColls);
- set<string> shardedColls;
- config->getAllShardedCollections(shardedColls);
-
- // Record start in changelog
- BSONObj moveStartDetails = _buildMoveEntry(dbname,
- fromShard->toString(),
- toShard->toString(),
- shardedColls);
-
- grid.catalogManager()->logChange(txn, "movePrimary.start", dbname, moveStartDetails);
-
- BSONArrayBuilder barr;
- barr.append(shardedColls);
-
- ScopedDbConnection toconn(toShard->getConnString());
-
- // TODO ERH - we need a clone command which replays operations from clone start to now
- // can just use local.oplog.$main
- BSONObj cloneRes;
- bool worked = toconn->runCommand(
- dbname.c_str(),
- BSON("clone" << fromShard->getConnString().toString()
- << "collsToIgnore" << barr.arr()
- << bypassDocumentValidationCommandOption() << true),
- cloneRes);
- toconn.done();
-
- if (!worked) {
- log() << "clone failed" << cloneRes;
- errmsg = "clone failed";
- return false;
- }
+ ScopedDbConnection toconn(toShard->getConnString());
- const string oldPrimary = fromShard->getConnString().toString();
+ // TODO ERH - we need a clone command which replays operations from clone start to now
+ // can just use local.oplog.$main
+ BSONObj cloneRes;
+ bool worked = toconn->runCommand(
+ dbname.c_str(),
+ BSON("clone" << fromShard->getConnString().toString() << "collsToIgnore" << barr.arr()
+ << bypassDocumentValidationCommandOption() << true),
+ cloneRes);
+ toconn.done();
- ScopedDbConnection fromconn(fromShard->getConnString());
+ if (!worked) {
+ log() << "clone failed" << cloneRes;
+ errmsg = "clone failed";
+ return false;
+ }
- config->setPrimary(toShard->getConnString().toString());
+ const string oldPrimary = fromShard->getConnString().toString();
- if (shardedColls.empty()){
+ ScopedDbConnection fromconn(fromShard->getConnString());
- // 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;
+ config->setPrimary(toShard->getConnString().toString());
- try {
- fromconn->dropDatabase(dbname.c_str());
- }
- catch (DBException& e){
- e.addContext(str::stream() << "movePrimary could not drop the database "
- << dbname << " on " << oldPrimary);
- throw;
- }
+ 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 {
+ fromconn->dropDatabase(dbname.c_str());
+ } 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;
- fromconn->dropCollection(el.String());
- }
- catch (DBException& e){
- e.addContext(str::stream() << "movePrimary could not drop the cloned collection "
- << el.String() << " 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;
+ fromconn->dropCollection(el.String());
+ } 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
- BSONObj moveFinishDetails = _buildMoveEntry(dbname,
- oldPrimary,
- toShard->toString(),
- shardedColls);
-
- grid.catalogManager()->logChange(txn, "movePrimary", dbname, moveFinishDetails);
- return true;
}
- private:
- static BSONObj _buildMoveEntry(const string db,
- const string from,
- const string to,
- set<string> shardedColls) {
-
- BSONObjBuilder details;
- details.append("database", db);
- details.append("from", from);
- details.append("to", to);
-
- BSONArrayBuilder collB(details.subarrayStart("shardedCollections"));
- {
- set<string>::iterator it;
- for (it = shardedColls.begin(); it != shardedColls.end(); ++it) {
- collB.append(*it);
- }
+ fromconn.done();
+
+ result << "primary" << toShard->toString();
+
+ // Record finish in changelog
+ BSONObj moveFinishDetails =
+ _buildMoveEntry(dbname, oldPrimary, toShard->toString(), shardedColls);
+
+ grid.catalogManager()->logChange(txn, "movePrimary", dbname, moveFinishDetails);
+ return true;
+ }
+
+private:
+ static BSONObj _buildMoveEntry(const string db,
+ const string from,
+ const string to,
+ set<string> shardedColls) {
+ BSONObjBuilder details;
+ details.append("database", db);
+ details.append("from", from);
+ details.append("to", to);
+
+ BSONArrayBuilder collB(details.subarrayStart("shardedCollections"));
+ {
+ set<string>::iterator it;
+ for (it = shardedColls.begin(); it != shardedColls.end(); ++it) {
+ collB.append(*it);
}
- collB.done();
-
- return details.obj();
}
+ collB.done();
+
+ return details.obj();
+ }
- } movePrimary;
+} movePrimary;
-} // namespace
-} // namespace mongo
+} // namespace
+} // namespace mongo