summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/dbclient_rs.cpp41
-rw-r--r--client/dbclient_rs.h6
-rw-r--r--client/dbclientcursor.h5
3 files changed, 49 insertions, 3 deletions
diff --git a/client/dbclient_rs.cpp b/client/dbclient_rs.cpp
index ae01da3..37f6225 100644
--- a/client/dbclient_rs.cpp
+++ b/client/dbclient_rs.cpp
@@ -463,9 +463,12 @@ namespace mongo {
if ( ! _slave->isFailed() )
return _slave.get();
_monitor->notifySlaveFailure( _slaveHost );
+ _slaveHost = _monitor->getSlave();
}
-
- _slaveHost = _monitor->getSlave();
+ else {
+ _slaveHost = h;
+ }
+
_slave.reset( new DBClientConnection( true , this ) );
_slave->connect( _slaveHost );
_auth( _slave.get() );
@@ -544,7 +547,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 +584,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 e942d7b..548b46a 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 5d795f4..d176b89 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