summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgregs <greg@10gen.com>2011-07-11 16:11:40 -0400
committergregs <greg@10gen.com>2011-07-11 16:11:40 -0400
commit3337ab497cd55e25fbdbe732e6c40c724add857d (patch)
treedd7f56009a73a88820ae69d03261ab4fd8d3df4e
parentb3224f5ae3cc3c6982b23e0cd64b1854fe97d03c (diff)
downloadmongo-3337ab497cd55e25fbdbe732e6c40c724add857d.tar.gz
backport of fix for SERVER-2481
-rw-r--r--client/dbclient_rs.cpp34
-rw-r--r--client/dbclient_rs.h6
-rw-r--r--client/dbclientcursor.h5
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