diff options
author | gregs <greg@10gen.com> | 2011-07-11 16:11:40 -0400 |
---|---|---|
committer | gregs <greg@10gen.com> | 2011-07-11 16:11:40 -0400 |
commit | 3337ab497cd55e25fbdbe732e6c40c724add857d (patch) | |
tree | dd7f56009a73a88820ae69d03261ab4fd8d3df4e | |
parent | b3224f5ae3cc3c6982b23e0cd64b1854fe97d03c (diff) | |
download | mongo-3337ab497cd55e25fbdbe732e6c40c724add857d.tar.gz |
backport of fix for SERVER-2481
-rw-r--r-- | client/dbclient_rs.cpp | 34 | ||||
-rw-r--r-- | client/dbclient_rs.h | 6 | ||||
-rw-r--r-- | client/dbclientcursor.h | 5 |
3 files changed, 44 insertions, 1 deletions
diff --git a/client/dbclient_rs.cpp b/client/dbclient_rs.cpp index ae01da3e5b3..3da036326aa 100644 --- a/client/dbclient_rs.cpp +++ b/client/dbclient_rs.cpp @@ -544,7 +544,7 @@ namespace mongo { // checkSlave will try a different slave automatically after a failure for ( int i=0; i<2; i++ ) { try { - return checkSlave()->query(ns,query,nToReturn,nToSkip,fieldsToReturn,queryOptions,batchSize); + return checkSlaveQueryResult( checkSlave()->query(ns,query,nToReturn,nToSkip,fieldsToReturn,queryOptions,batchSize) ); } catch ( DBException &e ) { log() << "can't query replica set slave " << i << " : " << _slaveHost << e.what() << endl; @@ -581,6 +581,38 @@ namespace mongo { assert(0); } + auto_ptr<DBClientCursor> DBClientReplicaSet::checkSlaveQueryResult( auto_ptr<DBClientCursor> result ){ + + bool isError = result->hasResultFlag( ResultFlag_ErrSet ); + if( ! isError ) return result; + + BSONObj error = result->peekOne(); + + BSONElement code = error["code"]; + if( code.eoo() || ! code.isNumber() ){ + warning() << "no code for error from secondary host " << _slaveHost << ", error was " << error << endl; + return result; + } + + // We only check for "not master or secondary" errors here + + // If the error code here ever changes, we need to change this code also + if( code.Int() == 13436 /* not master or secondary */ ){ + isntSecondary(); + throw DBException( str::stream() << "slave " << _slaveHost.toString() << " is no longer secondary", 14812 ); + } + + return result; + } + + void DBClientReplicaSet::isntSecondary() { + log() << "slave no longer has secondary status: " << _slaveHost << endl; + // Failover to next slave + _monitor->notifySlaveFailure( _slaveHost ); + _slave.reset(); + } + + void DBClientReplicaSet::isntMaster() { log() << "got not master for: " << _masterHost << endl; _monitor->notifyFailure( _masterHost ); diff --git a/client/dbclient_rs.h b/client/dbclient_rs.h index e942d7b5b2a..548b46a2176 100644 --- a/client/dbclient_rs.h +++ b/client/dbclient_rs.h @@ -215,6 +215,9 @@ namespace mongo { /* this is the callback from our underlying connections to notify us that we got a "not master" error. */ void isntMaster(); + /* this is used to indicate we got a "not master or secondary" error from a secondary. + */ + void isntSecondary(); // ----- status ------ @@ -240,6 +243,9 @@ namespace mongo { private: + // Used to simplify slave-handling logic on errors + auto_ptr<DBClientCursor> checkSlaveQueryResult( auto_ptr<DBClientCursor> result ); + DBClientConnection * checkMaster(); DBClientConnection * checkSlave(); diff --git a/client/dbclientcursor.h b/client/dbclientcursor.h index 5d795f4d6e1..d176b892d33 100644 --- a/client/dbclientcursor.h +++ b/client/dbclientcursor.h @@ -86,6 +86,11 @@ namespace mongo { WARNING: no support for _putBack yet! */ void peek(vector<BSONObj>&, int atMost); + BSONObj peekOne(){ + vector<BSONObj> v; + peek( v, 1 ); + return v.size() > 0 ? v[0] : BSONObj(); + } /** iterate the rest of the cursor and return the number if items |