/** * Copyright (C) 2008 10gen 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, * as published by the Free Software Foundation. * * 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 * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 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 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::kCommand #include "mongo/platform/basic.h" #include "mongo/db/repl/repl_set_command.h" #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/bson/util/bson_extract.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/commands.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/lasterror.h" #include "mongo/db/service_context.h" #include "mongo/db/op_observer.h" #include "mongo/db/repl/initial_sync.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/repl_set_heartbeat_args.h" #include "mongo/db/repl/repl_set_heartbeat_args_v1.h" #include "mongo/db/repl/repl_set_heartbeat_response.h" #include "mongo/db/repl/replication_coordinator_global.h" #include "mongo/db/repl/replication_coordinator_external_state_impl.h" #include "mongo/db/repl/replication_executor.h" #include "mongo/db/repl/update_position_args.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/executor/network_interface.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/log.h" 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(); } 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"); } 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 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"); } 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; } } 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* seeds) { const char *p = replSetString.c_str(); const char *slash = strchr(p, '/'); std::set seedSet; if (slash) { *setname = string(p, slash-p); } else { *setname = p; } if (slash == 0) { return; } 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(); } 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 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"); } 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); } if( cmdObj["replSetReconfig"].type() != Object ) { errmsg = "no configuration specified"; return false; } 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(); return appendCommandStatus(result, status); } } cmdReplSetReconfig; class CmdReplSetFreeze : public ReplSetCommand { public: virtual void help( stringstream &help ) const { help << "{ replSetFreeze : }"; 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 : }\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); } log() << "Attempting to step down in response to replSetStepDown command"; status = getGlobalReplicationCoordinator()->stepDown( txn, force, Seconds(secondaryCatchUpPeriodSecs), Seconds(stepDownForSecs)); 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); HostAndPort targetHostAndPort; status = targetHostAndPort.initialize(cmdObj["replSetSyncFrom"].valuestrsafe()); if (!status.isOK()) return appendCommandStatus(result, status); 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); // 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); // 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); if (status == ErrorCodes::InvalidReplicaSetConfig) { result.append("configVersion", configVersion); } 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 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; } } // namespace MONGO_FP_DECLARE(rsDelayHeartbeatResponse); /* { replSetHeartbeat : } */ 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); } /* 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; } 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 } ReplSetHeartbeatArgs args; status = args.initialize(cmdObj); if (!status.isOK()) { return appendCommandStatus(result, status); } // ugh. if (args.getCheckEmpty()) { result.append("hasData", replHasDatabases(txn)); } 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); 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