diff --git a/db/db.cpp b/db/db.cpp index e6dd292f4c5..0499fab14ec 100644 --- a/db/db.cpp +++ b/db/db.cpp @@ -70,6 +70,7 @@ namespace mongo { void setupSignals(); void closeAllSockets(); + void startReplSets(); void startReplication(); void pairWith(const char *remoteEnd, const char *arb); void setRecCacheSize(unsigned MB); @@ -553,6 +554,10 @@ namespace mongo { snapshotThread.go(); clientCursorMonitor.go(); + + if( !cmdLine.replSet.empty() ) + boost::thread t(startReplSets); + listen(listenPort); // listen() will return when exit code closes its socket. @@ -1151,4 +1156,3 @@ BOOL CtrlHandler( DWORD fdwCtrlType ) #include "recstore.h" #include "reccache.h" - diff --git a/db/repl.cpp b/db/repl.cpp index 17b69cf6a40..c1dc3484488 100644 --- a/db/repl.cpp +++ b/db/repl.cpp @@ -1708,9 +1708,9 @@ namespace mongo { } } - bool startReplSets(); void startReplication() { - if( startReplSets() ) + /* if we are going to be a replica set, we aren't doing other forms of replication. */ + if( !cmdLine.replSet.empty() ) return; /* this was just to see if anything locks for longer than it should -- we need to be careful diff --git a/db/repl/replset.cpp b/db/repl/replset.cpp index 83bc1b559b1..5d1a98b94ca 100644 --- a/db/repl/replset.cpp +++ b/db/repl/replset.cpp @@ -16,15 +16,16 @@ #include "stdafx.h" #include "../cmdline.h" -#include "replset.h" #include "../../util/sock.h" +#include "replset.h" +#include "rs_config.h" namespace mongo { ReplSet *theReplSet = 0; /** @param cfgString /, */ - ReplSet::ReplSet(string cfgString) { + ReplSet::ReplSet(string cfgString) : fatal(false) { const char *p = cfgString.c_str(); const char *slash = strchr(p, '/'); uassert(13093, "bad --replSet config string format is: /,[,...]", slash != 0 && p != slash); @@ -60,13 +61,30 @@ namespace mongo { } _seeds = seeds; - for( vector::iterator i = seeds->begin(); i != seeds->end(); i++ ) - addMemberIfMissing(*i); + //for( vector::iterator i = seeds->begin(); i != seeds->end(); i++ ) + // addMemberIfMissing(*i); + + loadConfig(); startHealthThreads(); } - void ReplSet::addMemberIfMissing(const HostAndPort& h) { + void ReplSet::loadConfig() { + try { + vector configs; + configs.push_back( ReplSetConfig(HostAndPort::me()) ); + for( vector::const_iterator i = _seeds->begin(); i != _seeds->end(); i++ ) + configs.push_back( ReplSetConfig(*i) ); + } + catch(AssertionException&) { + log() << "replSet: error loading configurations. admin.replset may be misconfigured\n"; + log() << "replSet: replication will not start" << endl; + fatal = true; + throw; + } + } + + /*void ReplSet::addMemberIfMissing(const HostAndPort& h) { MemberInfo *m = _members.head(); while( m ) { if( h.host() == m->host && h.port() == m->port ) @@ -75,15 +93,22 @@ namespace mongo { } MemberInfo *nm = new MemberInfo(h.host(), h.port()); _members.push(nm); - } + }*/ /* called at initialization */ - bool startReplSets() { - assert( theReplSet == 0 ); - if( cmdLine.replSet.empty() ) - return false; - theReplSet = new ReplSet(cmdLine.replSet); - return false; + void startReplSets() { + mongo::lastError.reset( new LastError() ); + try { + assert( theReplSet == 0 ); + if( cmdLine.replSet.empty() ) + return; + theReplSet = new ReplSet(cmdLine.replSet); + } + catch(...) { + log() << "Caught exception in repl set management thread" << endl; + if( theReplSet ) + theReplSet->fatal = true; + } } } diff --git a/db/repl/replset.h b/db/repl/replset.h index 417a849f48d..1f7e56a2082 100644 --- a/db/repl/replset.h +++ b/db/repl/replset.h @@ -32,21 +32,34 @@ namespace mongo { */ class ReplSet { public: + bool fatal; + + bool ok() const { return !fatal; } + + /* @return replica set's logical name */ string getName() const { return _name; } /* cfgString format is replsetname/host1,host2:port,... - where :port is optional, and - */ + where :port is optional. + + throws exception if a problem initializing. + */ ReplSet(string cfgString); + // for replSetGetStatus command void summarizeStatus(BSONObjBuilder&) const; private: string _name; const vector *_seeds; - void addMemberIfMissing(const HostAndPort& p); + /** load our configuration from admin.replset. try seed machines too. + throws exception if a problem. + */ + void loadConfig(); + +// void addMemberIfMissing(const HostAndPort& p); struct MemberInfo : public List1::Base { MemberInfo(string h, int p) : port(p), host(h) { diff --git a/db/repl/rs_config.cpp b/db/repl/rs_config.cpp index 33f088ae3a6..a0dd9ffca44 100644 --- a/db/repl/rs_config.cpp +++ b/db/repl/rs_config.cpp @@ -24,6 +24,7 @@ namespace mongo { void ReplSetConfig::from(BSONObj o) { + md5 = o.md5(); _id = o["_id"].String(); version = o["version"].numberInt(); uassert(13115, "bad admin.replset config: version", version > 0); @@ -60,12 +61,19 @@ namespace mongo { uassert(13117, "bad admin.replset config", !_id.empty()); } + static inline void configAssert(bool expr) { + uassert(13122, "bad admin.replset config", expr); + } + ReplSetConfig::ReplSetConfig(const HostAndPort& h) { + log(2) << "load ReplSetConfig " << h.toString() << endl; + DBClientConnection conn(false, 0, 20); conn._logLevel = 2; string err; conn.connect(h.toString()); auto_ptr c = conn.query("admin.replset"); + configAssert(c->more()); BSONObj o = c->nextSafe(); uassert(13109, "multiple rows in admin.replset not supported", !c->more()); from(o); diff --git a/db/repl/rs_config.h b/db/repl/rs_config.h index 3c9fa81ab48..9d530bd7aa8 100644 --- a/db/repl/rs_config.h +++ b/db/repl/rs_config.h @@ -50,10 +50,12 @@ Additionally an object in this collection holds global configuration settings fo class ReplSetConfig { public: - /* can throw exception */ + /* if something is misconfigured, throws an exception. + if couldn't be queried or is just blank, ok() will be false. + */ ReplSetConfig(const HostAndPort& h); - bool ok() const { return !_id.empty(); } + bool ok() const { return _ok; } struct Member { HostAndPort h; @@ -64,10 +66,12 @@ public: string _id; int version; HealthOptions healthOptions; + string md5; - /* TODO: adde getLastErrorDefaults */ + /* TODO: add getLastErrorDefaults */ private: + bool _ok; void from(BSONObj); }; diff --git a/dbtests/test.vcproj b/dbtests/test.vcproj index 1146ec00035..c797517ca36 100644 --- a/dbtests/test.vcproj +++ b/dbtests/test.vcproj @@ -1960,6 +1960,14 @@ RelativePath="..\db\repl\replset.cpp" > + + + + diff --git a/util/hostandport.h b/util/hostandport.h index 21527ee224f..03473ca300f 100644 --- a/util/hostandport.h +++ b/util/hostandport.h @@ -29,6 +29,10 @@ namespace mongo { HostAndPort(string h, int p = -1) : _host(h), _port(p) { } + static HostAndPort me() { + return HostAndPort("localhost", cmdLine.port); + } + static HostAndPort fromString(string s) { const char *p = s.c_str(); uassert(13110, "HostAndPort: bad config string", *p);