mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
rs
This commit is contained in:
parent
42f2ce74cf
commit
a2e86ec161
18
db/client.h
18
db/client.h
@ -172,24 +172,18 @@ namespace mongo {
|
||||
|
||||
AuthenticationInfo * getAuthenticationInfo(){ return &_ai; }
|
||||
bool isAdmin() { return _ai.isAuthorized( "admin" ); }
|
||||
|
||||
CurOp* curop() { return _curOp; }
|
||||
|
||||
CurOp* curop() { return _curOp; }
|
||||
Context* getContext(){ return _context; }
|
||||
Database* database() { return _context ? _context->db() : 0; }
|
||||
const char *ns() { return _context->ns(); }
|
||||
const char *ns() const { return _context->ns(); }
|
||||
const char *desc() const { return _desc; }
|
||||
|
||||
Client(const char *desc);
|
||||
~Client();
|
||||
|
||||
const char *desc() const { return _desc; }
|
||||
|
||||
void addTempCollection( const string& ns ){
|
||||
_tempCollections.push_back( ns );
|
||||
}
|
||||
|
||||
void dropTempCollectionsInDB(const string db);
|
||||
void dropAllTempCollectionsInDB(const string db);
|
||||
void addTempCollection( const string& ns ) { _tempCollections.push_back( ns ); }
|
||||
void dropTempCollectionsInDB(const string db);
|
||||
void dropAllTempCollectionsInDB(const string db);
|
||||
|
||||
void setLastOp( const OpTime& op ){
|
||||
_lastOp = op;
|
||||
|
@ -269,8 +269,10 @@ namespace mongo {
|
||||
if( theReplSet == 0 ) {
|
||||
if( cmdLine.replSet.empty() )
|
||||
s << p("Not using --replSet");
|
||||
else
|
||||
s << p("Still starting up, or else set is not yet " + a("http://www.mongodb.org/display/DOCS/Replica+Set+Configuration#InitialSetup", "", "initialized") + '.');
|
||||
else {
|
||||
s << p("Still starting up, or else set is not yet " + a("http://www.mongodb.org/display/DOCS/Replica+Set+Configuration#InitialSetup", "", "initiated")
|
||||
+ ".<br>" + ReplSet::startupStatusMsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
|
@ -70,7 +70,7 @@ namespace mongo {
|
||||
ReplSet::Member& me = *rs._self;
|
||||
electCmd = BSON(
|
||||
"replSetElect" << 1 <<
|
||||
"set" << rs.getName() <<
|
||||
"set" << rs.name() <<
|
||||
"who" << me.fullName() <<
|
||||
"whoid" << me._id <<
|
||||
"cfgver" << rs._cfg->version
|
||||
|
@ -36,6 +36,7 @@ namespace mongo {
|
||||
namespace mongo {
|
||||
|
||||
using namespace mongoutils::html;
|
||||
using namespace bson;
|
||||
|
||||
static RamLog _rsLog;
|
||||
Tee *rsLog = &_rsLog;
|
||||
@ -58,7 +59,6 @@ namespace mongo {
|
||||
errmsg = "incompatible replset protocol version";
|
||||
return false;
|
||||
}
|
||||
result.append("rs", true);
|
||||
string s = string(cmdObj.getStringField("replSetHeartbeat"))+'/';
|
||||
if( !startsWith(cmdLine.replSet, s ) ) {
|
||||
errmsg = "repl set names do not match";
|
||||
@ -67,18 +67,23 @@ namespace mongo {
|
||||
result.append("mismatch", true);
|
||||
return false;
|
||||
}
|
||||
result.append("rs", true);
|
||||
if( theReplSet == 0 ) {
|
||||
errmsg = "still initializing";
|
||||
return false;
|
||||
}
|
||||
if( theReplSet->getName() != cmdObj.getStringField("replSetHeartbeat") ) {
|
||||
|
||||
if( theReplSet->name() != cmdObj.getStringField("replSetHeartbeat") ) {
|
||||
errmsg = "repl set names do not match (2)";
|
||||
result.append("mismatch", true);
|
||||
return false;
|
||||
}
|
||||
/* todo: send our state*/
|
||||
result.append("set", theReplSet->getName());
|
||||
result.append("v", theReplSet->config().version);
|
||||
result.append("set", theReplSet->name());
|
||||
result.append("state", theReplSet->state());
|
||||
int v = theReplSet->config().version;
|
||||
result.append("v", v);
|
||||
// if( v > cmdObj["v"].Int() )
|
||||
// result << "config" << theReplSet->config().asBson();
|
||||
return true;
|
||||
}
|
||||
} cmdReplSetHeartbeat;
|
||||
@ -111,8 +116,13 @@ namespace mongo {
|
||||
try {
|
||||
BSONObj info;
|
||||
int theirConfigVersion = -10000;
|
||||
bool ok = requestHeartbeat(theReplSet->getName(), m->fullName(), info, theReplSet->config().version, theirConfigVersion);
|
||||
bool ok = requestHeartbeat(theReplSet->name(), m->fullName(), info, theReplSet->config().version, theirConfigVersion);
|
||||
m->_lastHeartbeat = time(0); // we set this on any response - we don't get this far if couldn't connect because exception is thrown
|
||||
{
|
||||
be state = info["state"];
|
||||
if( state.ok() )
|
||||
m->_state = (ReplSet::State) state.Int();
|
||||
}
|
||||
if( ok ) {
|
||||
if( m->_upSince == 0 ) {
|
||||
log() << "replSet " << m->fullName() << " is now up" << rsLog;
|
||||
@ -120,6 +130,11 @@ namespace mongo {
|
||||
}
|
||||
m->_health = 1.0;
|
||||
m->_lastHeartbeatErrMsg.set("");
|
||||
|
||||
be cfg = info["config"];
|
||||
if( cfg.ok() ) {
|
||||
//theReplSet->receivedNewConfig(cfg.Obj());
|
||||
}
|
||||
}
|
||||
else {
|
||||
down();
|
||||
@ -136,6 +151,26 @@ namespace mongo {
|
||||
}
|
||||
};
|
||||
|
||||
string ago(time_t t) {
|
||||
if( t == 0 ) return "";
|
||||
|
||||
time_t x = time(0) - t;
|
||||
stringstream s;
|
||||
if( x < 180 ) {
|
||||
s << x << " sec";
|
||||
if( x != 1 ) s << 's';
|
||||
}
|
||||
else if( x < 3600 ) {
|
||||
s.precision(2);
|
||||
s << x / 60.0 << " mins";
|
||||
}
|
||||
else {
|
||||
s.precision(2);
|
||||
s << x / 3600.0 << " hrs";
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void ReplSet::Member::summarizeAsHtml(stringstream& s) const {
|
||||
s << tr();
|
||||
{
|
||||
@ -146,20 +181,13 @@ namespace mongo {
|
||||
double h = health();
|
||||
bool ok = h > 0;
|
||||
s << td(h);
|
||||
s << td(upSince());
|
||||
s << td(ago(upSince()));
|
||||
{
|
||||
stringstream h;
|
||||
string h;
|
||||
time_t hb = lastHeartbeat();
|
||||
time_t now = time(0);
|
||||
if( hb == 0 ) h << "never";
|
||||
else {
|
||||
time_t diff = now-hb;
|
||||
if( now > hb ) h << diff;
|
||||
else h << 0;
|
||||
if( diff == 1 ) h << "sec ago";
|
||||
else h << "secs ago";
|
||||
}
|
||||
s << td(h.str());
|
||||
if( hb == 0 ) h = "never";
|
||||
else h = ago(hb) + " ago";
|
||||
s << td(h);
|
||||
}
|
||||
s << td(config().votes);
|
||||
s << td(ReplSet::stateAsStr(state()));
|
||||
@ -187,13 +215,16 @@ namespace mongo {
|
||||
return "";
|
||||
}
|
||||
|
||||
extern time_t started;
|
||||
|
||||
void ReplSet::summarizeAsHtml(stringstream& s) const {
|
||||
s << table(0, false);
|
||||
s << tr("Set name:", _name);
|
||||
s << tr("Majority up:", elect.aMajoritySeemsToBeUp()?"yes":"no" );
|
||||
s << _table();
|
||||
|
||||
const char *h[] = {"Member", "Up", "Uptime",
|
||||
const char *h[] = {"Member", "Up",
|
||||
"<a title=\"length of time we have been continuously connected to the other member with no reconnects\">cctime</a>",
|
||||
"<a title=\"when this server last received a heartbeat response - includes error code responses\">Last heartbeat</a>",
|
||||
"Votes", "State", "Status", 0};
|
||||
s << table(h);
|
||||
@ -201,8 +232,8 @@ namespace mongo {
|
||||
/* self row */
|
||||
s << tr() << td(_self->fullName()) <<
|
||||
td("1") <<
|
||||
td("self") <<
|
||||
td("") <<
|
||||
td(ago(started)) <<
|
||||
td("(self)") <<
|
||||
td(ToString(_self->config().votes)) <<
|
||||
td(stateAsHtml(_myState));
|
||||
s << td( _self->_lastHeartbeatErrMsg.get() );
|
||||
@ -297,7 +328,7 @@ namespace mongo {
|
||||
v.push_back(bb.obj());
|
||||
m = m->next();
|
||||
}
|
||||
b.append("set", getName());
|
||||
b.append("set", name());
|
||||
b.appendDate("date", time(0));
|
||||
b.append("myState", _myState);
|
||||
b.append("members", v);
|
||||
|
@ -96,6 +96,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
log() << "replSet todo elect self as primary primary" << rsLog;
|
||||
_rs->_self->_lastHeartbeatErrMsg.set("todo code #2");
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "../cmdline.h"
|
||||
#include "../../util/sock.h"
|
||||
#include "replset.h"
|
||||
#include "../db/client.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
@ -96,8 +97,8 @@ namespace mongo {
|
||||
ReplSet::StartupStatus ReplSet::startupStatus = PRESTART;
|
||||
string ReplSet::startupStatusMsg;
|
||||
|
||||
void ReplSet::setFrom(ReplSetConfig& c) {
|
||||
_cfg.reset( new ReplSetConfig(c) );
|
||||
void ReplSet::setFrom(ReplSetConfig& c, bool save) {
|
||||
_cfg = new ReplSetConfig(c);
|
||||
assert( _cfg->ok() );
|
||||
assert( _name.empty() || _name == _cfg->_id );
|
||||
_name = _cfg->_id;
|
||||
@ -117,20 +118,27 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
assert( me == 1 );
|
||||
|
||||
if( save ) {
|
||||
_cfg->save();
|
||||
}
|
||||
}
|
||||
|
||||
void ReplSet::finishLoadingConfig(vector<ReplSetConfig>& cfgs) {
|
||||
int v = -1;
|
||||
ReplSetConfig *highest = 0;
|
||||
int myVersion = -2000;
|
||||
int n = 0;
|
||||
for( vector<ReplSetConfig>::iterator i = cfgs.begin(); i != cfgs.end(); i++ ) {
|
||||
ReplSetConfig& cfg = *i;
|
||||
if( ++n == 1 ) myVersion = cfg.version;
|
||||
if( cfg.ok() && cfg.version > v ) {
|
||||
highest = &cfg;
|
||||
v = cfg.version;
|
||||
}
|
||||
}
|
||||
assert( highest );
|
||||
setFrom(*highest);
|
||||
setFrom(*highest, highest->version > myVersion && highest->version >= 0);
|
||||
}
|
||||
|
||||
void ReplSet::loadConfig() {
|
||||
@ -155,7 +163,7 @@ namespace mongo {
|
||||
|
||||
if( nempty == (int) configs.size() ) {
|
||||
startupStatus = EMPTYCONFIG;
|
||||
startupStatusMsg = "can't get " + rsConfigNs + " config from self or any seed (uninitialized?)";
|
||||
startupStatusMsg = "can't get " + rsConfigNs + " config from self or any seed (EMPTYCONFIG)";
|
||||
log() << "replSet can't get " << rsConfigNs << " config from self or any seed (EMPTYCONFIG)" << rsLog;
|
||||
log() << "replSet have you ran replSetInitiate yet?" << rsLog;
|
||||
log() << "replSet sleeping 1 minute and will try again." << rsLog;
|
||||
@ -186,8 +194,9 @@ namespace mongo {
|
||||
startupStatus = STARTED;
|
||||
}
|
||||
|
||||
/* called at startup */
|
||||
/* forked as a thread during startup */
|
||||
void startReplSets() {
|
||||
Client::initThread("startReplSets");
|
||||
mongo::lastError.reset( new LastError() );
|
||||
try {
|
||||
assert( theReplSet == 0 );
|
||||
@ -202,6 +211,7 @@ namespace mongo {
|
||||
if( theReplSet )
|
||||
theReplSet->fatal();
|
||||
}
|
||||
cc().shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,15 +37,30 @@ namespace mongo {
|
||||
*/
|
||||
class ReplSet {
|
||||
public:
|
||||
static enum StartupStatus { PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3, EMPTYUNREACHABLE=4, STARTED=5 } startupStatus;
|
||||
static enum StartupStatus { PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3, EMPTYUNREACHABLE=4, STARTED=5, SOON=6 } startupStatus;
|
||||
static string startupStatusMsg;
|
||||
|
||||
enum State {
|
||||
STARTUP,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
RECOVERING,
|
||||
FATAL,
|
||||
STARTUP2,
|
||||
UNKNOWN /* remote node not yet reached */
|
||||
};
|
||||
|
||||
private:
|
||||
State _myState;
|
||||
|
||||
public:
|
||||
|
||||
void fatal();
|
||||
bool isMaster(const char *client);
|
||||
void fillIsMaster(BSONObjBuilder&);
|
||||
bool ok() const { return _myState != FATAL; }
|
||||
|
||||
string getName() const { return _name; } /* @return replica set's logical name */
|
||||
State state() const { return _myState; }
|
||||
string name() const { return _name; } /* @return replica set's logical name */
|
||||
|
||||
/* cfgString format is
|
||||
replsetname/host1,host2:port,...
|
||||
@ -61,19 +76,20 @@ namespace mongo {
|
||||
// for replSetGetStatus command
|
||||
void summarizeStatus(BSONObjBuilder&) const;
|
||||
void summarizeAsHtml(stringstream&) const;
|
||||
const ReplSetConfig& config() { return *_cfg.get(); }
|
||||
const ReplSetConfig& config() { return *_cfg; }
|
||||
void receivedNewConfig(BSONObj);
|
||||
|
||||
private:
|
||||
string _name;
|
||||
const vector<HostAndPort> *_seeds;
|
||||
auto_ptr<ReplSetConfig> _cfg;
|
||||
ReplSetConfig *_cfg;
|
||||
|
||||
/** load our configuration from admin.replset. try seed machines too.
|
||||
throws exception if a problem.
|
||||
*/
|
||||
void loadConfig();
|
||||
void finishLoadingConfig(vector<ReplSetConfig>& v);
|
||||
void setFrom(ReplSetConfig& c);
|
||||
void setFrom(ReplSetConfig& c, bool save);
|
||||
|
||||
struct Consensus {
|
||||
ReplSet &rs;
|
||||
@ -83,17 +99,6 @@ namespace mongo {
|
||||
bool electSelf();
|
||||
} elect;
|
||||
|
||||
private:
|
||||
enum State {
|
||||
STARTUP,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
RECOVERING,
|
||||
FATAL,
|
||||
STARTUP2,
|
||||
UNKNOWN /* remote node not yet reached */
|
||||
} _myState;
|
||||
|
||||
public:
|
||||
struct Member : public List1<Member>::Base {
|
||||
Member(HostAndPort h, int ord, const ReplSetConfig::MemberCfg *c);
|
||||
|
@ -29,8 +29,14 @@ namespace mongo {
|
||||
|
||||
void ReplSetConfig::save() {
|
||||
check();
|
||||
BSONObj o = asBson();
|
||||
Helpers::putSingletonGod(rsConfigNs.c_str(), o, false/*logOp=false; local db so would work regardless...*/);
|
||||
log() << "replSet info saving a newer config version to local.system.replset" << rsLog;
|
||||
MemoryMappedFile::flushAll(true);
|
||||
{
|
||||
writelock lk("admin.");
|
||||
BSONObj o = asBson();
|
||||
Helpers::putSingletonGod(rsConfigNs.c_str(), o, false/*logOp=false; local db so would work regardless...*/);
|
||||
MemoryMappedFile::flushAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
bo ReplSetConfig::MemberCfg::asBson() const {
|
||||
@ -177,9 +183,8 @@ namespace mongo {
|
||||
//log(0) << "replSet load config from: " << h.toString() << rsLog;
|
||||
|
||||
auto_ptr<DBClientCursor> c;
|
||||
int v = -5;
|
||||
try {
|
||||
version = -5;
|
||||
|
||||
if( h.isSelf() ) {
|
||||
;
|
||||
}
|
||||
@ -192,33 +197,40 @@ namespace mongo {
|
||||
int theirVersion;
|
||||
BSONObj info;
|
||||
bool ok = requestHeartbeat(setname, h.toString(), info, -2, theirVersion);
|
||||
if( !ok ) {
|
||||
log() << "replSet TEMP !ok heartbeating " << h.toString() << " on cfg load" << rsLog;
|
||||
if( !info.isEmpty() ) log() << "replSet TEMP response was: " << info.toString() << rsLog;
|
||||
return;
|
||||
if( info["rs"].trueValue() ) {
|
||||
// yes, it is a replicate set, although perhaps not yet initialized
|
||||
}
|
||||
if( !info["rs"].trueValue() ) {
|
||||
stringstream ss;
|
||||
ss << "replSet error: member " << h.toString() << " is not in --replSet mode";
|
||||
cout << "TEMP " << info.toString() << endl;
|
||||
msgassertedNoTrace(13260, ss.str().c_str()); // not caught as not a user exception - we want it not caught
|
||||
//for python: uassert(13260, "", false);
|
||||
else {
|
||||
if( !ok ) {
|
||||
log() << "replSet TEMP !ok heartbeating " << h.toString() << " on cfg load" << rsLog;
|
||||
if( !info.isEmpty() ) log() << "replSet TEMP response was: " << info.toString() << rsLog;
|
||||
return;
|
||||
}
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "replSet error: member " << h.toString() << " is not in --replSet mode";
|
||||
cout << "TEMP " << info.toString() << endl;
|
||||
msgassertedNoTrace(13260, ss.str().c_str()); // not caught as not a user exception - we want it not caught
|
||||
//for python err# checker: uassert(13260, "", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version = -4;
|
||||
v = -4;
|
||||
ScopedConn conn(h.toString());
|
||||
version = -3;
|
||||
v = -3;
|
||||
c = conn->query(rsConfigNs);
|
||||
if( c.get() == 0 )
|
||||
return;
|
||||
if( c.get() == 0 ) {
|
||||
version = v; return;
|
||||
}
|
||||
if( !c->more() ) {
|
||||
version = -2; /* -2 is a sentinel - see ReplSetConfig::empty() */
|
||||
version = EMPTYCONFIG;
|
||||
return;
|
||||
}
|
||||
version = -1;
|
||||
}
|
||||
catch( DBException& e) {
|
||||
version = v;
|
||||
log(level) << "replSet load config couldn't load " << h.toString() << ' ' << e.what() << rsLog;
|
||||
return;
|
||||
}
|
||||
|
@ -25,17 +25,10 @@
|
||||
|
||||
namespace mongo {
|
||||
|
||||
/**
|
||||
" + rsConfigNs + "
|
||||
|
||||
This collection has one object per server in the set.
|
||||
|
||||
See "Replical Sets Configuration" on mongodb.org wiki for details on the format.
|
||||
*/
|
||||
|
||||
const string rsConfigNs = "local.system.replset";
|
||||
|
||||
class ReplSetConfig {
|
||||
enum { EMPTYCONFIG = -2 };
|
||||
public:
|
||||
/* if something is misconfigured, throws an exception.
|
||||
if couldn't be queried or is just blank, ok() will be false.
|
||||
@ -63,8 +56,8 @@ namespace mongo {
|
||||
string md5;
|
||||
BSONObj getLastErrorDefaults;
|
||||
|
||||
// true if could connect, and there is no cfg object there at all
|
||||
bool empty() const { return version == -2; }
|
||||
/** @return true if could connect, and there is no cfg object there at all */
|
||||
bool empty() const { return version == EMPTYCONFIG; }
|
||||
|
||||
string toString() const { return asBson().toString(); }
|
||||
|
||||
@ -72,12 +65,12 @@ namespace mongo {
|
||||
void check() const;
|
||||
|
||||
void save(); // to local db
|
||||
BSONObj asBson() const;
|
||||
|
||||
private:
|
||||
bool _ok;
|
||||
void from(BSONObj);
|
||||
void clear();
|
||||
BSONObj asBson() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
catch(...) { }
|
||||
if( !ok ) {
|
||||
if( !ok && !res["rs"].trueValue() ) {
|
||||
if( !res.isEmpty() )
|
||||
log() << "replSet warning " << i->h.toString() << " replied: " << res.toString() << rsLog;
|
||||
uasserted(13144, "need all members up to initiate, not ok: " + i->h.toString());
|
||||
@ -89,6 +89,7 @@ namespace mongo {
|
||||
}
|
||||
if( ReplSet::startupStatus != ReplSet::EMPTYCONFIG ) {
|
||||
result.append("startupStatus", ReplSet::startupStatus);
|
||||
result.append("startupStatusMsg", ReplSet::startupStatusMsg);
|
||||
errmsg = "all members and seeds must be reachable to initiate set";
|
||||
result.append("info", cmdLine.replSet);
|
||||
return false;
|
||||
@ -108,11 +109,9 @@ namespace mongo {
|
||||
|
||||
log() << "replSet replSetInitiate all members seem up" << rsLog;
|
||||
|
||||
log() << newConfig.toString() << rsLog;
|
||||
//log() << newConfig.toString() << rsLog;
|
||||
|
||||
MemoryMappedFile::flushAll(true);
|
||||
newConfig.save();
|
||||
MemoryMappedFile::flushAll(true);
|
||||
}
|
||||
catch( DBException& e ) {
|
||||
log() << "replSet replSetInitiate exception: " << e.what() << rsLog;
|
||||
@ -121,9 +120,20 @@ namespace mongo {
|
||||
|
||||
log() << "replSet replSetInitiate Config now saved locally. Should come online in about a minute." << rsLog;
|
||||
result.append("info", "Config now saved locally. Should come online in about a minute.");
|
||||
ReplSet::startupStatus = ReplSet::SOON;
|
||||
ReplSet::startupStatusMsg = "Received replSetInitiate - should come online shortly.";
|
||||
|
||||
return true;
|
||||
}
|
||||
} cmdReplSetInitiate;
|
||||
|
||||
/*void ReplSet::receivedNewConfig(BSONObj cfg) {
|
||||
writelock lk("admin.");
|
||||
ReplSetConfig c(cfg);
|
||||
if( c.version <= config().version ) {
|
||||
log() << "replSet info received new config v" << c.version << " but our v" << config().version << " is already newer" << rsLog;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// helpers for testing repl sets
|
||||
// run
|
||||
// mongo --shell testing.js
|
||||
// mongo --shell <host:port> testing.js
|
||||
|
||||
cfg = {
|
||||
_id: 'asdf',
|
||||
@ -13,6 +13,8 @@ cfg = {
|
||||
db = db.getSisterDB("admin");
|
||||
local = db.getSisterDB("local");
|
||||
|
||||
print("\nswitched to admin db\n");
|
||||
print("\nswitched to admin db");
|
||||
print("cfg = samp replset config");
|
||||
print("rc = runCommand\n");
|
||||
|
||||
function rc(c) { return db.runCommand(c); }
|
||||
|
Loading…
Reference in New Issue
Block a user