0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
This commit is contained in:
Dwight 2010-05-13 17:18:17 -04:00
parent 42f2ce74cf
commit a2e86ec161
11 changed files with 155 additions and 95 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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);

View File

@ -96,6 +96,7 @@ namespace mongo {
}
log() << "replSet todo elect self as primary primary" << rsLog;
_rs->_self->_lastHeartbeatErrMsg.set("todo code #2");
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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;
}
}*/
}

View File

@ -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); }