diff options
Diffstat (limited to 'src/mongo/db/repl/replset_commands.cpp')
-rw-r--r-- | src/mongo/db/repl/replset_commands.cpp | 1365 |
1 files changed, 674 insertions, 691 deletions
diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp index 600fbfe52a8..c26bed4775b 100644 --- a/src/mongo/db/repl/replset_commands.cpp +++ b/src/mongo/db/repl/replset_commands.cpp @@ -61,757 +61,740 @@ namespace mongo { namespace repl { - using std::string; - using std::stringstream; - - // Testing only, enabled via command-line. - class CmdReplSetTest : public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "Just for regression tests.\n"; - } - // No auth needed because it only works when enabled via command line. - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - return Status::OK(); - } - CmdReplSetTest() : ReplSetCommand("replSetTest") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - log() << "replSetTest command received: " << cmdObj.toString(); - - if( cmdObj.hasElement("forceInitialSyncFailure") ) { - replSetForceInitialSyncFailure = (unsigned) cmdObj["forceInitialSyncFailure"].Number(); - return true; - } - - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - - return false; - } - }; - MONGO_INITIALIZER(RegisterReplSetTestCmd)(InitializerContext* context) { - if (Command::testCommandsEnabled) { - // Leaked intentionally: a Command registers itself when constructed. - new CmdReplSetTest(); - } +using std::string; +using std::stringstream; + +// Testing only, enabled via command-line. +class CmdReplSetTest : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "Just for regression tests.\n"; + } + // No auth needed because it only works when enabled via command line. + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { return Status::OK(); } + CmdReplSetTest() : ReplSetCommand("replSetTest") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + log() << "replSetTest command received: " << cmdObj.toString(); + + if (cmdObj.hasElement("forceInitialSyncFailure")) { + replSetForceInitialSyncFailure = (unsigned)cmdObj["forceInitialSyncFailure"].Number(); + return true; + } - /** get rollback id. used to check if a rollback happened during some interval of time. - as consumed, the rollback id is not in any particular order, it simply changes on each rollback. - @see incRBID() - */ - class CmdReplSetGetRBID : public ReplSetCommand { - public: - CmdReplSetGetRBID() : ReplSetCommand("replSetGetRBID") {} - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - - status = getGlobalReplicationCoordinator()->processReplSetGetRBID(&result); + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) return appendCommandStatus(result, status); - } - } cmdReplSetRBID; - - class CmdReplSetGetStatus : public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "Report status of a replica set from the POV of this server\n"; - help << "{ replSetGetStatus : 1 }"; - help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetGetStatus); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetGetStatus() : ReplSetCommand("replSetGetStatus", true) { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - if ( cmdObj["forShell"].trueValue() ) - LastError::get(txn->getClient()).disable(); - - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - status = getGlobalReplicationCoordinator()->processReplSetGetStatus(&result); + return false; + } +}; +MONGO_INITIALIZER(RegisterReplSetTestCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new CmdReplSetTest(); + } + return Status::OK(); +} + +/** get rollback id. used to check if a rollback happened during some interval of time. + as consumed, the rollback id is not in any particular order, it simply changes on each rollback. + @see incRBID() +*/ +class CmdReplSetGetRBID : public ReplSetCommand { +public: + CmdReplSetGetRBID() : ReplSetCommand("replSetGetRBID") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) return appendCommandStatus(result, status); + + status = getGlobalReplicationCoordinator()->processReplSetGetRBID(&result); + return appendCommandStatus(result, status); + } +} cmdReplSetRBID; + +class CmdReplSetGetStatus : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "Report status of a replica set from the POV of this server\n"; + help << "{ replSetGetStatus : 1 }"; + help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetGetStatus); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - } cmdReplSetGetStatus; - - class CmdReplSetGetConfig : public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "Returns the current replica set configuration"; - help << "{ replSetGetConfig : 1 }"; - help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetGetConfig); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetGetConfig() : ReplSetCommand("replSetGetConfig", true) { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); + return Status::OK(); + } + CmdReplSetGetStatus() : ReplSetCommand("replSetGetStatus", true) {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + if (cmdObj["forShell"].trueValue()) + LastError::get(txn->getClient()).disable(); + + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); - getGlobalReplicationCoordinator()->processReplSetGetConfig(&result); - return true; + status = getGlobalReplicationCoordinator()->processReplSetGetStatus(&result); + return appendCommandStatus(result, status); + } +} cmdReplSetGetStatus; + +class CmdReplSetGetConfig : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "Returns the current replica set configuration"; + help << "{ replSetGetConfig : 1 }"; + help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetGetConfig); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - } cmdReplSetGetConfig; + return Status::OK(); + } + CmdReplSetGetConfig() : ReplSetCommand("replSetGetConfig", true) {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); + + getGlobalReplicationCoordinator()->processReplSetGetConfig(&result); + return true; + } +} cmdReplSetGetConfig; namespace { - HostAndPort someHostAndPortForMe() { - const char* ips = serverGlobalParams.bind_ip.c_str(); - while (*ips) { - std::string ip; - const char* comma = strchr(ips, ','); - if (comma) { - ip = std::string(ips, comma - ips); - ips = comma + 1; - } - else { - ip = std::string(ips); - ips = ""; - } - HostAndPort h = HostAndPort(ip, serverGlobalParams.port); - if (!h.isLocalHost()) { - return h; - } +HostAndPort someHostAndPortForMe() { + const char* ips = serverGlobalParams.bind_ip.c_str(); + while (*ips) { + std::string ip; + const char* comma = strchr(ips, ','); + if (comma) { + ip = std::string(ips, comma - ips); + ips = comma + 1; + } else { + ip = std::string(ips); + ips = ""; + } + HostAndPort h = HostAndPort(ip, serverGlobalParams.port); + if (!h.isLocalHost()) { + return h; } + } + + std::string h = getHostName(); + verify(!h.empty()); + verify(h != "localhost"); + return HostAndPort(h, serverGlobalParams.port); +} + +void parseReplSetSeedList(ReplicationCoordinatorExternalState* externalState, + const std::string& replSetString, + std::string* setname, + std::vector<HostAndPort>* seeds) { + const char* p = replSetString.c_str(); + const char* slash = strchr(p, '/'); + std::set<HostAndPort> seedSet; + if (slash) { + *setname = string(p, slash - p); + } else { + *setname = p; + } - std::string h = getHostName(); - verify(!h.empty()); - verify(h != "localhost"); - return HostAndPort(h, serverGlobalParams.port); + if (slash == 0) { + return; } - void parseReplSetSeedList(ReplicationCoordinatorExternalState* externalState, - const std::string& replSetString, - std::string* setname, - std::vector<HostAndPort>* seeds) { - const char *p = replSetString.c_str(); - const char *slash = strchr(p, '/'); - std::set<HostAndPort> seedSet; - if (slash) { - *setname = string(p, slash-p); + p = slash + 1; + while (1) { + const char* comma = strchr(p, ','); + if (comma == 0) { + comma = strchr(p, 0); + } + if (p == comma) { + break; + } + HostAndPort m; + try { + m = HostAndPort(string(p, comma - p)); + } catch (...) { + uassert(13114, "bad --replSet seed hostname", false); + } + uassert(13096, "bad --replSet command line config string - dups?", seedSet.count(m) == 0); + seedSet.insert(m); + // uassert(13101, "can't use localhost in replset host list", !m.isLocalHost()); + if (externalState->isSelf(m)) { + LOG(1) << "ignoring seed " << m.toString() << " (=self)"; + } else { + seeds->push_back(m); + } + if (*comma == 0) { + break; + } + p = comma + 1; + } +} +} // namespace + +class CmdReplSetInitiate : public ReplSetCommand { +public: + CmdReplSetInitiate() : ReplSetCommand("replSetInitiate") {} + virtual void help(stringstream& h) const { + h << "Initiate/christen a replica set."; + h << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetConfigure); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - else { - *setname = p; + return Status::OK(); + } + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + BSONObj configObj; + if (cmdObj["replSetInitiate"].type() == Object) { + configObj = cmdObj["replSetInitiate"].Obj(); + } + + std::string replSetString = getGlobalReplicationCoordinator()->getSettings().replSet; + if (replSetString.empty()) { + return appendCommandStatus(result, + Status(ErrorCodes::NoReplicationEnabled, + "This node was not started with the replSet " + "option")); + } + + if (configObj.isEmpty()) { + string noConfigMessage = + "no configuration specified. " + "Using a default configuration for the set"; + result.append("info2", noConfigMessage); + log() << "initiate : " << noConfigMessage; + + ReplicationCoordinatorExternalStateImpl externalState; + std::string name; + std::vector<HostAndPort> seeds; + parseReplSetSeedList(&externalState, replSetString, &name, &seeds); // may throw... + + BSONObjBuilder b; + b.append("_id", name); + b.append("version", 1); + BSONObjBuilder members; + HostAndPort me = someHostAndPortForMe(); + members.append("0", BSON("_id" << 0 << "host" << me.toString())); + result.append("me", me.toString()); + for (unsigned i = 0; i < seeds.size(); i++) { + members.append(BSONObjBuilder::numStr(i + 1), + BSON("_id" << i + 1 << "host" << seeds[i].toString())); + } + b.appendArray("members", members.obj()); + configObj = b.obj(); + log() << "created this configuration for initiation : " << configObj.toString(); + } + + if (configObj.getField("version").eoo()) { + // Missing version field defaults to version 1. + BSONObjBuilder builder; + builder.appendElements(configObj); + builder.append("version", 1); + configObj = builder.obj(); + } + + Status status = + getGlobalReplicationCoordinator()->processReplSetInitiate(txn, configObj, &result); + return appendCommandStatus(result, status); + } +} cmdReplSetInitiate; + +class CmdReplSetReconfig : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "Adjust configuration of a replica set\n"; + help << "{ replSetReconfig : config_object }"; + help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetConfigure); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - - if (slash == 0) { - return; + return Status::OK(); + } + CmdReplSetReconfig() : ReplSetCommand("replSetReconfig") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) { + return appendCommandStatus(result, status); } - p = slash + 1; - while (1) { - const char *comma = strchr(p, ','); - if (comma == 0) { - comma = strchr(p,0); - } - if (p == comma) { - break; - } - HostAndPort m; - try { - m = HostAndPort( string(p, comma-p) ); - } - catch (...) { - uassert(13114, "bad --replSet seed hostname", false); - } - uassert(13096, "bad --replSet command line config string - dups?", - seedSet.count(m) == 0); - seedSet.insert(m); - //uassert(13101, "can't use localhost in replset host list", !m.isLocalHost()); - if (externalState->isSelf(m)) { - LOG(1) << "ignoring seed " << m.toString() << " (=self)"; - } - else { - seeds->push_back(m); - } - if (*comma == 0) { - break; - } - p = comma + 1; - } - } -} // namespace - - class CmdReplSetInitiate : public ReplSetCommand { - public: - CmdReplSetInitiate() : ReplSetCommand("replSetInitiate") { } - virtual void help(stringstream& h) const { - h << "Initiate/christen a replica set."; - h << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetConfigure); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - virtual bool run(OperationContext* txn, - const string& , - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - - BSONObj configObj; - if( cmdObj["replSetInitiate"].type() == Object ) { - configObj = cmdObj["replSetInitiate"].Obj(); - } + if (cmdObj["replSetReconfig"].type() != Object) { + errmsg = "no configuration specified"; + return false; + } - std::string replSetString = getGlobalReplicationCoordinator()->getSettings().replSet; - if (replSetString.empty()) { - return appendCommandStatus(result, - Status(ErrorCodes::NoReplicationEnabled, - "This node was not started with the replSet " - "option")); - } + ReplicationCoordinator::ReplSetReconfigArgs parsedArgs; + parsedArgs.newConfigObj = cmdObj["replSetReconfig"].Obj(); + parsedArgs.force = cmdObj.hasField("force") && cmdObj["force"].trueValue(); + status = + getGlobalReplicationCoordinator()->processReplSetReconfig(txn, parsedArgs, &result); - if (configObj.isEmpty()) { - string noConfigMessage = "no configuration specified. " - "Using a default configuration for the set"; - result.append("info2", noConfigMessage); - log() << "initiate : " << noConfigMessage; - - ReplicationCoordinatorExternalStateImpl externalState; - std::string name; - std::vector<HostAndPort> seeds; - parseReplSetSeedList( - &externalState, - replSetString, - &name, - &seeds); // may throw... - - BSONObjBuilder b; - b.append("_id", name); - b.append("version", 1); - BSONObjBuilder members; - HostAndPort me = someHostAndPortForMe(); - members.append("0", BSON( "_id" << 0 << "host" << me.toString() )); - result.append("me", me.toString()); - for( unsigned i = 0; i < seeds.size(); i++ ) { - members.append(BSONObjBuilder::numStr(i+1), - BSON( "_id" << i+1 << "host" << seeds[i].toString())); - } - b.appendArray("members", members.obj()); - configObj = b.obj(); - log() << "created this configuration for initiation : " << - configObj.toString(); - } + ScopedTransaction scopedXact(txn, MODE_X); + Lock::GlobalWrite globalWrite(txn->lockState()); - if (configObj.getField("version").eoo()) { - // Missing version field defaults to version 1. - BSONObjBuilder builder; - builder.appendElements(configObj); - builder.append("version", 1); - configObj = builder.obj(); - } + WriteUnitOfWork wuow(txn); + if (status.isOK() && !parsedArgs.force) { + getGlobalServiceContext()->getOpObserver()->onOpMessage( + txn, + BSON("msg" + << "Reconfig set" + << "version" << parsedArgs.newConfigObj["version"])); + } + wuow.commit(); - Status status = getGlobalReplicationCoordinator()->processReplSetInitiate(txn, - configObj, - &result); - return appendCommandStatus(result, status); + return appendCommandStatus(result, status); + } +} cmdReplSetReconfig; + +class CmdReplSetFreeze : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "{ replSetFreeze : <seconds> }"; + help << "'freeze' state of member to the extent we can do that. What this really means is " + "that\n"; + help << "this node will not attempt to become primary until the time period specified " + "expires.\n"; + help << "You can call again with {replSetFreeze:0} to unfreeze sooner.\n"; + help << "A process restart unfreezes the member also.\n"; + help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetStateChange); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - } cmdReplSetInitiate; - - class CmdReplSetReconfig : public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "Adjust configuration of a replica set\n"; - help << "{ replSetReconfig : config_object }"; - help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetConfigure); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetReconfig() : ReplSetCommand("replSetReconfig") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) { - return appendCommandStatus(result, status); - } + return Status::OK(); + } + CmdReplSetFreeze() : ReplSetCommand("replSetFreeze") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); - if( cmdObj["replSetReconfig"].type() != Object ) { - errmsg = "no configuration specified"; - return false; - } + int secs = (int)cmdObj.firstElement().numberInt(); + return appendCommandStatus( + result, getGlobalReplicationCoordinator()->processReplSetFreeze(secs, &result)); + } +} cmdReplSetFreeze; + +class CmdReplSetStepDown : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "{ replSetStepDown : <seconds> }\n"; + help << "Step down as primary. Will not try to reelect self for the specified time period " + "(1 minute if no numeric secs value specified).\n"; + help << "(If another member with same priority takes over in the meantime, it will stay " + "primary.)\n"; + help << "http://dochub.mongodb.org/core/replicasetcommands"; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetStateChange); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + CmdReplSetStepDown() : ReplSetCommand("replSetStepDown") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); - ReplicationCoordinator::ReplSetReconfigArgs parsedArgs; - parsedArgs.newConfigObj = cmdObj["replSetReconfig"].Obj(); - parsedArgs.force = cmdObj.hasField("force") && cmdObj["force"].trueValue(); - status = getGlobalReplicationCoordinator()->processReplSetReconfig(txn, - parsedArgs, - &result); - - ScopedTransaction scopedXact(txn, MODE_X); - Lock::GlobalWrite globalWrite(txn->lockState()); - - WriteUnitOfWork wuow(txn); - if (status.isOK() && !parsedArgs.force) { - getGlobalServiceContext()->getOpObserver()->onOpMessage( - txn, - BSON("msg" << "Reconfig set" << - "version" << parsedArgs.newConfigObj["version"])); - } - wuow.commit(); + const bool force = cmdObj["force"].trueValue(); + long long stepDownForSecs = cmdObj.firstElement().numberLong(); + if (stepDownForSecs == 0) { + stepDownForSecs = 60; + } else if (stepDownForSecs < 0) { + status = Status(ErrorCodes::BadValue, "stepdown period must be a positive integer"); return appendCommandStatus(result, status); } - } cmdReplSetReconfig; - - class CmdReplSetFreeze : public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "{ replSetFreeze : <seconds> }"; - help << "'freeze' state of member to the extent we can do that. What this really means is that\n"; - help << "this node will not attempt to become primary until the time period specified expires.\n"; - help << "You can call again with {replSetFreeze:0} to unfreeze sooner.\n"; - help << "A process restart unfreezes the member also.\n"; - help << "\nhttp://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetStateChange); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetFreeze() : ReplSetCommand("replSetFreeze") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - - int secs = (int) cmdObj.firstElement().numberInt(); - return appendCommandStatus( - result, - getGlobalReplicationCoordinator()->processReplSetFreeze(secs, &result)); - } - } cmdReplSetFreeze; - - class CmdReplSetStepDown: public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "{ replSetStepDown : <seconds> }\n"; - help << "Step down as primary. Will not try to reelect self for the specified time period (1 minute if no numeric secs value specified).\n"; - help << "(If another member with same priority takes over in the meantime, it will stay primary.)\n"; - help << "http://dochub.mongodb.org/core/replicasetcommands"; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetStateChange); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetStepDown() : ReplSetCommand("replSetStepDown") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - - const bool force = cmdObj["force"].trueValue(); - long long stepDownForSecs = cmdObj.firstElement().numberLong(); - if (stepDownForSecs == 0) { - stepDownForSecs = 60; - } - else if (stepDownForSecs < 0) { - status = Status(ErrorCodes::BadValue, - "stepdown period must be a positive integer"); - return appendCommandStatus(result, status); - } - - long long secondaryCatchUpPeriodSecs; - status = bsonExtractIntegerField(cmdObj, - "secondaryCatchUpPeriodSecs", - &secondaryCatchUpPeriodSecs); - if (status.code() == ErrorCodes::NoSuchKey) { - // if field is absent, default values - if (force) { - secondaryCatchUpPeriodSecs = 0; - } - else { - secondaryCatchUpPeriodSecs = 10; - } - } - else if (!status.isOK()) { - return appendCommandStatus(result, status); - } - - if (secondaryCatchUpPeriodSecs < 0) { - status = Status(ErrorCodes::BadValue, - "secondaryCatchUpPeriodSecs period must be a positive or absent"); - return appendCommandStatus(result, status); - } - - if (stepDownForSecs < secondaryCatchUpPeriodSecs) { - status = Status(ErrorCodes::BadValue, - "stepdown period must be longer than secondaryCatchUpPeriodSecs"); - return appendCommandStatus(result, status); + long long secondaryCatchUpPeriodSecs; + status = bsonExtractIntegerField( + cmdObj, "secondaryCatchUpPeriodSecs", &secondaryCatchUpPeriodSecs); + if (status.code() == ErrorCodes::NoSuchKey) { + // if field is absent, default values + if (force) { + secondaryCatchUpPeriodSecs = 0; + } else { + secondaryCatchUpPeriodSecs = 10; } + } else if (!status.isOK()) { + return appendCommandStatus(result, status); + } - log() << "Attempting to step down in response to replSetStepDown command"; + if (secondaryCatchUpPeriodSecs < 0) { + status = Status(ErrorCodes::BadValue, + "secondaryCatchUpPeriodSecs period must be a positive or absent"); + return appendCommandStatus(result, status); + } - status = getGlobalReplicationCoordinator()->stepDown( - txn, - force, - Seconds(secondaryCatchUpPeriodSecs), - Seconds(stepDownForSecs)); + if (stepDownForSecs < secondaryCatchUpPeriodSecs) { + status = Status(ErrorCodes::BadValue, + "stepdown period must be longer than secondaryCatchUpPeriodSecs"); return appendCommandStatus(result, status); } - } cmdReplSetStepDown; - - class CmdReplSetMaintenance: public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "{ replSetMaintenance : bool }\n"; - help << "Enable or disable maintenance mode."; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetStateChange); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetMaintenance() : ReplSetCommand("replSetMaintenance") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - return appendCommandStatus( - result, - getGlobalReplicationCoordinator()->setMaintenanceMode( - cmdObj["replSetMaintenance"].trueValue())); - } - } cmdReplSetMaintenance; - - class CmdReplSetSyncFrom: public ReplSetCommand { - public: - virtual void help( stringstream &help ) const { - help << "{ replSetSyncFrom : \"host:port\" }\n"; - help << "Change who this member is syncing from."; - } - virtual Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { - ActionSet actions; - actions.addAction(ActionType::replSetStateChange); - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), actions)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - CmdReplSetSyncFrom() : ReplSetCommand("replSetSyncFrom") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); + log() << "Attempting to step down in response to replSetStepDown command"; - HostAndPort targetHostAndPort; - status = targetHostAndPort.initialize(cmdObj["replSetSyncFrom"].valuestrsafe()); - if (!status.isOK()) - return appendCommandStatus(result, status); + status = getGlobalReplicationCoordinator()->stepDown( + txn, force, Seconds(secondaryCatchUpPeriodSecs), Seconds(stepDownForSecs)); + return appendCommandStatus(result, status); + } +} cmdReplSetStepDown; - return appendCommandStatus( - result, - getGlobalReplicationCoordinator()->processReplSetSyncFrom(targetHostAndPort, - &result)); - } - } cmdReplSetSyncFrom; - - class CmdReplSetUpdatePosition: public ReplSetCommand { - public: - CmdReplSetUpdatePosition() : ReplSetCommand("replSetUpdatePosition") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); +class CmdReplSetMaintenance : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "{ replSetMaintenance : bool }\n"; + help << "Enable or disable maintenance mode."; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetStateChange); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + CmdReplSetMaintenance() : ReplSetCommand("replSetMaintenance") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); - // accept and ignore handshakes sent from old (3.0-series) nodes without erroring to - // enable mixed-version operation, since we no longer use the handshakes - if (cmdObj.hasField("handshake")) { - return true; - } - - UpdatePositionArgs args; - status = args.initialize(cmdObj); - if (!status.isOK()) - return appendCommandStatus(result, status); + return appendCommandStatus(result, + getGlobalReplicationCoordinator()->setMaintenanceMode( + cmdObj["replSetMaintenance"].trueValue())); + } +} cmdReplSetMaintenance; - // in the case of an update from a member with an invalid replica set config, - // we return our current config version - long long configVersion = -1; - status = getGlobalReplicationCoordinator()-> - processReplSetUpdatePosition(args, &configVersion); +class CmdReplSetSyncFrom : public ReplSetCommand { +public: + virtual void help(stringstream& help) const { + help << "{ replSetSyncFrom : \"host:port\" }\n"; + help << "Change who this member is syncing from."; + } + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetStateChange); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + CmdReplSetSyncFrom() : ReplSetCommand("replSetSyncFrom") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); - if (status == ErrorCodes::InvalidReplicaSetConfig) { - result.append("configVersion", configVersion); - } + HostAndPort targetHostAndPort; + status = targetHostAndPort.initialize(cmdObj["replSetSyncFrom"].valuestrsafe()); + if (!status.isOK()) return appendCommandStatus(result, status); - } - } cmdReplSetUpdatePosition; -namespace { - /** - * Returns true if there is no data on this server. Useful when starting replication. - * The "local" database does NOT count except for "rs.oplog" collection. - * Used to set the hasData field on replset heartbeat command response. - */ - bool replHasDatabases(OperationContext* txn) { - std::vector<string> names; - StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); - storageEngine->listDatabases(&names); - - if( names.size() >= 2 ) return true; - if( names.size() == 1 ) { - if( names[0] != "local" ) - return true; - - // we have a local database. return true if oplog isn't empty - BSONObj o; - if (Helpers::getSingleton(txn, repl::rsOplogName.c_str(), o)) { - return true; - } - } - return false; + return appendCommandStatus( + result, + getGlobalReplicationCoordinator()->processReplSetSyncFrom(targetHostAndPort, &result)); } +} cmdReplSetSyncFrom; + +class CmdReplSetUpdatePosition : public ReplSetCommand { +public: + CmdReplSetUpdatePosition() : ReplSetCommand("replSetUpdatePosition") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); -} // namespace + // accept and ignore handshakes sent from old (3.0-series) nodes without erroring to + // enable mixed-version operation, since we no longer use the handshakes + if (cmdObj.hasField("handshake")) { + return true; + } - MONGO_FP_DECLARE(rsDelayHeartbeatResponse); + UpdatePositionArgs args; + status = args.initialize(cmdObj); + if (!status.isOK()) + return appendCommandStatus(result, status); - /* { replSetHeartbeat : <setname> } */ - class CmdReplSetHeartbeat : public ReplSetCommand { - public: - CmdReplSetHeartbeat() : ReplSetCommand("replSetHeartbeat") { } - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { + // in the case of an update from a member with an invalid replica set config, + // we return our current config version + long long configVersion = -1; + status = + getGlobalReplicationCoordinator()->processReplSetUpdatePosition(args, &configVersion); - MONGO_FAIL_POINT_BLOCK(rsDelayHeartbeatResponse, delay) { - const BSONObj& data = delay.getData(); - sleepsecs(data["delay"].numberInt()); - } + if (status == ErrorCodes::InvalidReplicaSetConfig) { + result.append("configVersion", configVersion); + } + return appendCommandStatus(result, status); + } +} cmdReplSetUpdatePosition; - Status status = Status(ErrorCodes::InternalError, "status not set in heartbeat code"); - /* we don't call ReplSetCommand::check() here because heartbeat - checks many things that are pre-initialization. */ - if (!getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { - status = Status(ErrorCodes::NoReplicationEnabled, "not running with --replSet"); - return appendCommandStatus(result, status); - } +namespace { +/** + * Returns true if there is no data on this server. Useful when starting replication. + * The "local" database does NOT count except for "rs.oplog" collection. + * Used to set the hasData field on replset heartbeat command response. + */ +bool replHasDatabases(OperationContext* txn) { + std::vector<string> names; + StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); + storageEngine->listDatabases(&names); + + if (names.size() >= 2) + return true; + if (names.size() == 1) { + if (names[0] != "local") + return true; - /* we want to keep heartbeat connections open when relinquishing primary. - tag them here. */ - { - AbstractMessagingPort *mp = txn->getClient()->port(); - if( mp ) - mp->tag |= executor::NetworkInterface::kMessagingPortKeepOpen; - } + // we have a local database. return true if oplog isn't empty + BSONObj o; + if (Helpers::getSingleton(txn, repl::rsOplogName.c_str(), o)) { + return true; + } + } + return false; +} + +} // namespace + +MONGO_FP_DECLARE(rsDelayHeartbeatResponse); + +/* { replSetHeartbeat : <setname> } */ +class CmdReplSetHeartbeat : public ReplSetCommand { +public: + CmdReplSetHeartbeat() : ReplSetCommand("replSetHeartbeat") {} + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + MONGO_FAIL_POINT_BLOCK(rsDelayHeartbeatResponse, delay) { + const BSONObj& data = delay.getData(); + sleepsecs(data["delay"].numberInt()); + } + + Status status = Status(ErrorCodes::InternalError, "status not set in heartbeat code"); + /* we don't call ReplSetCommand::check() here because heartbeat + checks many things that are pre-initialization. */ + if (!getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { + status = Status(ErrorCodes::NoReplicationEnabled, "not running with --replSet"); + return appendCommandStatus(result, status); + } - if (getGlobalReplicationCoordinator()->isV1ElectionProtocol()) { - ReplSetHeartbeatArgsV1 args; - status = args.initialize(cmdObj); - if (status.isOK()) { - ReplSetHeartbeatResponse response; - status = getGlobalReplicationCoordinator()->processHeartbeatV1(args, &response); - if (status.isOK()) - response.addToBSON(&result, true); - return appendCommandStatus(result, status); - } - // else: fall through to old heartbeat protocol as it is likely that - // a new node just joined the set - } + /* we want to keep heartbeat connections open when relinquishing primary. + tag them here. */ + { + AbstractMessagingPort* mp = txn->getClient()->port(); + if (mp) + mp->tag |= executor::NetworkInterface::kMessagingPortKeepOpen; + } - ReplSetHeartbeatArgs args; + if (getGlobalReplicationCoordinator()->isV1ElectionProtocol()) { + ReplSetHeartbeatArgsV1 args; status = args.initialize(cmdObj); - if (!status.isOK()) { + if (status.isOK()) { + ReplSetHeartbeatResponse response; + status = getGlobalReplicationCoordinator()->processHeartbeatV1(args, &response); + if (status.isOK()) + response.addToBSON(&result, true); return appendCommandStatus(result, status); } + // else: fall through to old heartbeat protocol as it is likely that + // a new node just joined the set + } - // ugh. - if (args.getCheckEmpty()) { - result.append("hasData", replHasDatabases(txn)); - } - - ReplSetHeartbeatResponse response; - status = getGlobalReplicationCoordinator()->processHeartbeat(args, &response); - if (status.isOK()) - response.addToBSON(&result, false); + ReplSetHeartbeatArgs args; + status = args.initialize(cmdObj); + if (!status.isOK()) { return appendCommandStatus(result, status); } - } cmdReplSetHeartbeat; - - /** the first cmd called by a node seeking election and it's a basic sanity - test: do any of the nodes it can reach know that it can't be the primary? - */ - class CmdReplSetFresh : public ReplSetCommand { - public: - CmdReplSetFresh() : ReplSetCommand("replSetFresh") { } - - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - ReplicationCoordinator::ReplSetFreshArgs parsedArgs; - parsedArgs.id = cmdObj["id"].Int(); - parsedArgs.setName = cmdObj["set"].String(); - parsedArgs.who = HostAndPort(cmdObj["who"].String()); - BSONElement cfgverElement = cmdObj["cfgver"]; - uassert(28525, - str::stream() << "Expected cfgver argument to replSetFresh command to have " - "numeric type, but found " << typeName(cfgverElement.type()), - cfgverElement.isNumber()); - parsedArgs.cfgver = cfgverElement.safeNumberLong(); - parsedArgs.opTime = Timestamp(cmdObj["opTime"].Date()); - - status = getGlobalReplicationCoordinator()->processReplSetFresh(parsedArgs, &result); - return appendCommandStatus(result, status); + // ugh. + if (args.getCheckEmpty()) { + result.append("hasData", replHasDatabases(txn)); } - } cmdReplSetFresh; - - class CmdReplSetElect : public ReplSetCommand { - public: - CmdReplSetElect() : ReplSetCommand("replSetElect") { } - private: - virtual bool run(OperationContext* txn, - const string&, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - DEV log() << "received elect msg " << cmdObj.toString(); - else LOG(2) << "received elect msg " << cmdObj.toString(); - - Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); - if (!status.isOK()) - return appendCommandStatus(result, status); - ReplicationCoordinator::ReplSetElectArgs parsedArgs; - parsedArgs.set = cmdObj["set"].String(); - parsedArgs.whoid = cmdObj["whoid"].Int(); - BSONElement cfgverElement = cmdObj["cfgver"]; - uassert(28526, - str::stream() << "Expected cfgver argument to replSetElect command to have " - "numeric type, but found " << typeName(cfgverElement.type()), - cfgverElement.isNumber()); - parsedArgs.cfgver = cfgverElement.safeNumberLong(); - parsedArgs.round = cmdObj["round"].OID(); - - status = getGlobalReplicationCoordinator()->processReplSetElect(parsedArgs, &result); + ReplSetHeartbeatResponse response; + status = getGlobalReplicationCoordinator()->processHeartbeat(args, &response); + if (status.isOK()) + response.addToBSON(&result, false); + return appendCommandStatus(result, status); + } +} cmdReplSetHeartbeat; + +/** the first cmd called by a node seeking election and it's a basic sanity + test: do any of the nodes it can reach know that it can't be the primary? + */ +class CmdReplSetFresh : public ReplSetCommand { +public: + CmdReplSetFresh() : ReplSetCommand("replSetFresh") {} + + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) return appendCommandStatus(result, status); - } - } cmdReplSetElect; -} // namespace repl -} // namespace mongo + ReplicationCoordinator::ReplSetFreshArgs parsedArgs; + parsedArgs.id = cmdObj["id"].Int(); + parsedArgs.setName = cmdObj["set"].String(); + parsedArgs.who = HostAndPort(cmdObj["who"].String()); + BSONElement cfgverElement = cmdObj["cfgver"]; + uassert(28525, + str::stream() << "Expected cfgver argument to replSetFresh command to have " + "numeric type, but found " << typeName(cfgverElement.type()), + cfgverElement.isNumber()); + parsedArgs.cfgver = cfgverElement.safeNumberLong(); + parsedArgs.opTime = Timestamp(cmdObj["opTime"].Date()); + + status = getGlobalReplicationCoordinator()->processReplSetFresh(parsedArgs, &result); + return appendCommandStatus(result, status); + } +} cmdReplSetFresh; + +class CmdReplSetElect : public ReplSetCommand { +public: + CmdReplSetElect() : ReplSetCommand("replSetElect") {} + +private: + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + DEV log() << "received elect msg " << cmdObj.toString(); + else LOG(2) << "received elect msg " << cmdObj.toString(); + + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); + + ReplicationCoordinator::ReplSetElectArgs parsedArgs; + parsedArgs.set = cmdObj["set"].String(); + parsedArgs.whoid = cmdObj["whoid"].Int(); + BSONElement cfgverElement = cmdObj["cfgver"]; + uassert(28526, + str::stream() << "Expected cfgver argument to replSetElect command to have " + "numeric type, but found " << typeName(cfgverElement.type()), + cfgverElement.isNumber()); + parsedArgs.cfgver = cfgverElement.safeNumberLong(); + parsedArgs.round = cmdObj["round"].OID(); + + status = getGlobalReplicationCoordinator()->processReplSetElect(parsedArgs, &result); + return appendCommandStatus(result, status); + } +} cmdReplSetElect; + +} // namespace repl +} // namespace mongo |