diff options
author | Aaron <aaron@10gen.com> | 2010-05-13 10:47:42 -0700 |
---|---|---|
committer | Aaron <aaron@10gen.com> | 2010-05-13 10:47:42 -0700 |
commit | 052f894fd199cb99bac173d7f4156804113f5e15 (patch) | |
tree | 08272fc89a81f0f0bb4b94ca4c8f68251f703987 | |
parent | d2d668d31408dee1707a814fb932ef59e8dcdb24 (diff) | |
parent | 42f2ce74cfee0baefde3d5235e4089f86f89dae2 (diff) | |
download | mongo-052f894fd199cb99bac173d7f4156804113f5e15.tar.gz |
Merge branch 'master' of github.com:mongodb/mongo
-rw-r--r-- | db/oplog.h | 22 | ||||
-rw-r--r-- | db/repl/health.cpp | 19 | ||||
-rw-r--r-- | db/repl/health.h | 2 | ||||
-rw-r--r-- | db/repl/replset.h | 2 | ||||
-rw-r--r-- | db/repl/rs_config.cpp | 23 | ||||
-rw-r--r-- | db/repl/rs_mod.cpp | 14 | ||||
-rw-r--r-- | dbtests/querytests.cpp | 39 | ||||
-rw-r--r-- | util/hostandport.h | 4 |
8 files changed, 99 insertions, 26 deletions
diff --git a/db/oplog.h b/db/oplog.h index b9d6b533e38..83b00f3a5ac 100644 --- a/db/oplog.h +++ b/db/oplog.h @@ -133,7 +133,7 @@ namespace mongo { shared_ptr<Cursor> _c; DiskLoc startLoc( const DiskLoc &rec ) { Extent *e = rec.rec()->myExtent( rec ); - if ( e->myLoc != _qp.nsd()->capExtent ) + if ( !_qp.nsd()->capLooped() || ( e->myLoc != _qp.nsd()->capExtent ) ) return e->firstRecord; // Likely we are on the fresh side of capExtent, so return first fresh record. // If we are on the stale side of capExtent, then the collection is small and it @@ -141,14 +141,22 @@ namespace mongo { return _qp.nsd()->capFirstNewRecord; } + // should never have an empty extent in the oplog, so don't worry about that case DiskLoc prevLoc( const DiskLoc &rec ) { Extent *e = rec.rec()->myExtent( rec ); - if ( e->xprev.isNull() ) - e = _qp.nsd()->lastExtent.ext(); - else - e = e->xprev.ext(); - if ( e->myLoc != _qp.nsd()->capExtent ) - return e->firstRecord; + if ( _qp.nsd()->capLooped() ) { + if ( e->xprev.isNull() ) + e = _qp.nsd()->lastExtent.ext(); + else + e = e->xprev.ext(); + if ( e->myLoc != _qp.nsd()->capExtent ) + return e->firstRecord; + } else { + if ( !e->xprev.isNull() ) { + e = e->xprev.ext(); + return e->firstRecord; + } + } return DiskLoc(); // reached beginning of collection } void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { diff --git a/db/repl/health.cpp b/db/repl/health.cpp index 0c19dea8cec..eebb16ab65d 100644 --- a/db/repl/health.cpp +++ b/db/repl/health.cpp @@ -54,11 +54,16 @@ namespace mongo { errmsg = "not a replset member"; return false; } + if( cmdObj["pv"].Int() != 1 ) { + errmsg = "incompatible replset protocol version"; + return false; + } result.append("rs", true); - if( !startsWith(cmdLine.replSet, cmdObj.getStringField("replSetHeartbeat")+'/' ) ) { + string s = string(cmdObj.getStringField("replSetHeartbeat"))+'/'; + if( !startsWith(cmdLine.replSet, s ) ) { errmsg = "repl set names do not match"; - cout << cmdLine.replSet << endl; - cout << cmdObj.getStringField("replSetHeartbeat") << endl; + cout << "cmdline: " << cmdLine.replSet << endl; + cout << "s: " << s << endl; result.append("mismatch", true); return false; } @@ -73,13 +78,14 @@ namespace mongo { } /* todo: send our state*/ result.append("set", theReplSet->getName()); + result.append("v", theReplSet->config().version); return true; } } cmdReplSetHeartbeat; /* throws dbexception */ - bool requestHeartbeat(string setName, string memberFullName, BSONObj& result) { - BSONObj cmd = BSON( "replSetHeartbeat" << setName ); + bool requestHeartbeat(string setName, string memberFullName, BSONObj& result, int myCfgVersion, int& theirCfgVersion) { + BSONObj cmd = BSON( "replSetHeartbeat" << setName << "v" << myCfgVersion << "pv" << 1 ); ScopedConn conn(memberFullName); return conn->runCommand("admin", cmd, result); } @@ -104,7 +110,8 @@ namespace mongo { while( 1 ) { try { BSONObj info; - bool ok = requestHeartbeat(theReplSet->getName(), m->fullName(), info); + int theirConfigVersion = -10000; + bool ok = requestHeartbeat(theReplSet->getName(), 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 if( ok ) { if( m->_upSince == 0 ) { diff --git a/db/repl/health.h b/db/repl/health.h index 6180f7a8e64..f7174efe7fb 100644 --- a/db/repl/health.h +++ b/db/repl/health.h @@ -21,7 +21,7 @@ namespace mongo { /* throws */ - bool requestHeartbeat(string setname, string memberFullName, BSONObj& result); + bool requestHeartbeat(string setname, string memberFullName, BSONObj& result, int myConfigVersion, int& theirConfigVersion); struct HealthOptions { HealthOptions() { diff --git a/db/repl/replset.h b/db/repl/replset.h index 4520221b978..cd757fd1d52 100644 --- a/db/repl/replset.h +++ b/db/repl/replset.h @@ -61,6 +61,7 @@ namespace mongo { // for replSetGetStatus command void summarizeStatus(BSONObjBuilder&) const; void summarizeAsHtml(stringstream&) const; + const ReplSetConfig& config() { return *_cfg.get(); } private: string _name; @@ -119,6 +120,7 @@ namespace mongo { }; const Member* currentPrimary() const { return _currentPrimary; } + const ReplSetConfig::MemberCfg& myConfig() const { return _self->config(); } private: const Member *_currentPrimary; diff --git a/db/repl/rs_config.cpp b/db/repl/rs_config.cpp index 6905770e0b4..4f4ad679c97 100644 --- a/db/repl/rs_config.cpp +++ b/db/repl/rs_config.cpp @@ -178,26 +178,37 @@ namespace mongo { auto_ptr<DBClientCursor> c; try { - ScopedConn conn(h.toString()); - version = -4; + version = -5; - { + if( h.isSelf() ) { + ; + } + else { /* first, make sure other node is configured to be a replset. just to be safe. */ size_t sl = cmdLine.replSet.find('/'); assert( sl != string::npos ); string setname = cmdLine.replSet.substr(0, sl); BSONObj cmd = BSON( "replSetHeartbeat" << setname ); + int theirVersion; BSONObj info; - bool ok = conn->runCommand("admin", cmd, 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() ) { stringstream ss; ss << "replSet error: member " << h.toString() << " is not in --replSet mode"; - msgassertedNoTrace(10000, ss.str().c_str()); // not caught as not a user exception - we want it not caught + 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); } } + version = -4; + ScopedConn conn(h.toString()); version = -3; - c = conn->query(rsConfigNs); if( c.get() == 0 ) return; diff --git a/db/repl/rs_mod.cpp b/db/repl/rs_mod.cpp index 4ea65f85c9a..80b4695bda9 100644 --- a/db/repl/rs_mod.cpp +++ b/db/repl/rs_mod.cpp @@ -31,12 +31,20 @@ using namespace bson; namespace mongo { /* throws */ - static void checkAllMembersUpAndPreInit(const ReplSetConfig& cfg) { + static void checkAllMembersUpForConfigChange(const ReplSetConfig& cfg) { for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) { BSONObj res; { bool ok = false; - try { ok = requestHeartbeat(cfg._id, i->h.toString(), res); } + try { + int theirVersion = -1000; + ok = requestHeartbeat(cfg._id, i->h.toString(), res, -1, theirVersion); + if( theirVersion >= cfg.version ) { + stringstream ss; + ss << "replSet member " << i->h.toString() << " has too new a config version (" << theirVersion << ") to reconfigure"; + uasserted(13259, ss.str()); + } + } catch(...) { } if( !ok ) { if( !res.isEmpty() ) @@ -96,7 +104,7 @@ namespace mongo { log() << "replSet replSetInitiate config object parses ok, " << newConfig.members.size() << " members specified" << rsLog; - checkAllMembersUpAndPreInit(newConfig); + checkAllMembersUpForConfigChange(newConfig); log() << "replSet replSetInitiate all members seem up" << rsLog; diff --git a/dbtests/querytests.cpp b/dbtests/querytests.cpp index 88a6bbfbc70..dc48d89ec77 100644 --- a/dbtests/querytests.cpp +++ b/dbtests/querytests.cpp @@ -1005,7 +1005,9 @@ namespace QueryTests { for( int j = -1; j < i; ++j ) { auto_ptr< DBClientCursor > c = client().query( ns(), QUERY( "ts" << GTE << j ), 0, 0, 0, QueryOption_OplogReplay ); ASSERT( c->more() ); - ASSERT_EQUALS( ( j > min ? j : min ), c->next()[ "ts" ].numberInt() ); + BSONObj next = c->next(); + ASSERT( !next[ "ts" ].eoo() ); + ASSERT_EQUALS( ( j > min ? j : min ), next[ "ts" ].numberInt() ); } } } @@ -1014,6 +1016,40 @@ namespace QueryTests { int _old; }; + class FindingStartPartiallyFull : public CollectionBase { + public: + FindingStartPartiallyFull() : CollectionBase( "findingstart" ), _old( __findingStartInitialTimeout ) { + __findingStartInitialTimeout = 0; + } + ~FindingStartPartiallyFull() { + __findingStartInitialTimeout = _old; + } + + void run() { + BSONObj info; + ASSERT( client().runCommand( "unittests", BSON( "create" << "querytests.findingstart" << "capped" << true << "size" << 10000 << "$nExtents" << 5 << "autoIndexId" << false ), info ) ); + + int i = 0; + for( ; i < 150; client().insert( ns(), BSON( "ts" << i++ ) ) ); + + for( int k = 0; k < 5; ++k ) { + client().insert( ns(), BSON( "ts" << i++ ) ); + int min = client().query( ns(), Query().sort( BSON( "$natural" << 1 ) ) )->next()[ "ts" ].numberInt(); + for( int j = -1; j < i; ++j ) { + auto_ptr< DBClientCursor > c = client().query( ns(), QUERY( "ts" << GTE << j ), 0, 0, 0, QueryOption_OplogReplay ); + ASSERT( c->more() ); + BSONObj next = c->next(); + ASSERT( !next[ "ts" ].eoo() ); + ASSERT_EQUALS( ( j > min ? j : min ), next[ "ts" ].numberInt() ); + } + } + } + + private: + int _old; + }; + + class WhatsMyUri : public CollectionBase { public: WhatsMyUri() : CollectionBase( "whatsmyuri" ) {} @@ -1137,6 +1173,7 @@ namespace QueryTests { add< HelperTest >(); add< HelperByIdTest >(); add< FindingStart >(); + add< FindingStartPartiallyFull >(); add< WhatsMyUri >(); add< parsedtests::basic1 >(); diff --git a/util/hostandport.h b/util/hostandport.h index 918bf8ad2a9..2db8c375ea3 100644 --- a/util/hostandport.h +++ b/util/hostandport.h @@ -86,8 +86,8 @@ namespace mongo { int p = _port == -1 ? CmdLine::DefaultDBPort : _port; if( p != cmdLine.port ) return false; - assert( _host != "localhost" && _host != "127.0.0.1" ); - return sameStart(getHostName().c_str(), _host.c_str()); + + return sameStart(getHostName().c_str(), _host.c_str()) || isLocalHost(); } inline string HostAndPort::toString() const { |