summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron <aaron@10gen.com>2010-05-13 10:47:42 -0700
committerAaron <aaron@10gen.com>2010-05-13 10:47:42 -0700
commit052f894fd199cb99bac173d7f4156804113f5e15 (patch)
tree08272fc89a81f0f0bb4b94ca4c8f68251f703987
parentd2d668d31408dee1707a814fb932ef59e8dcdb24 (diff)
parent42f2ce74cfee0baefde3d5235e4089f86f89dae2 (diff)
downloadmongo-052f894fd199cb99bac173d7f4156804113f5e15.tar.gz
Merge branch 'master' of github.com:mongodb/mongo
-rw-r--r--db/oplog.h22
-rw-r--r--db/repl/health.cpp19
-rw-r--r--db/repl/health.h2
-rw-r--r--db/repl/replset.h2
-rw-r--r--db/repl/rs_config.cpp23
-rw-r--r--db/repl/rs_mod.cpp14
-rw-r--r--dbtests/querytests.cpp39
-rw-r--r--util/hostandport.h4
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 {