Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:mongodb/mongo

  • Loading branch information...
commit bae82cf7a9fb003585169f314405f619ff5f3b88 2 parents d008ee9 + 24d9585
Kristina Chodorow authored
317 client/dbclient.cpp
View
@@ -35,7 +35,7 @@ namespace mongo {
switch ( _type ){
case MASTER: {
DBClientConnection * c = new DBClientConnection(true);
- log(2) << "creating new connection to:" << _servers[0] << endl;
+ log(1) << "creating new connection to:" << _servers[0] << endl;
if ( ! c->connect( _servers[0] , errmsg ) ) {
delete c;
return 0;
@@ -43,14 +43,15 @@ namespace mongo {
return c;
}
- case PAIR: {
- DBClientPaired *p = new DBClientPaired();
- if( !p->connect( _servers[0] , _servers[1] ) ){
- delete p;
- errmsg = "connect failed to pair";
+ case PAIR:
+ case SET: {
+ DBClientReplicaSet * set = new DBClientReplicaSet( _setName , _servers );
+ if( ! set->connect() ){
+ delete set;
+ errmsg = "connect failed to set";
return 0;
}
- return p;
+ return set;
}
case SYNC: {
@@ -60,7 +61,7 @@ namespace mongo {
l.push_back( _servers[i] );
return new SyncClusterConnection( l );
}
-
+
case INVALID:
throw UserException( 13421 , "trying to connect to invalid ConnectionString" );
break;
@@ -71,6 +72,13 @@ namespace mongo {
}
ConnectionString ConnectionString::parse( const string& host , string& errmsg ){
+
+ string::size_type i = host.find( '/' );
+ if ( i != string::npos ){
+ // replica set
+ return ConnectionString( SET , host.substr( i + 1 ) , host.substr( 0 , i ) );
+ }
+
int numCommas = DBClientBase::countCommas( host );
if( numCommas == 0 )
@@ -313,9 +321,10 @@ namespace mongo {
bool DBClientWithCommands::isMaster(bool& isMaster, BSONObj *info) {
BSONObj o;
- if ( info == 0 ) info = &o;
+ if ( info == 0 )
+ info = &o;
bool ok = runCommand("admin", ismastercmdobj, *info);
- isMaster = (info->getIntField("ismaster") == 1);
+ isMaster = info->getField("ismaster").trueValue();
return ok;
}
@@ -439,61 +448,6 @@ namespace mongo {
return count( db.c_str() , q ) != 0;
}
-
- void testSort() {
- DBClientConnection c;
- string err;
- if ( !c.connect("localhost", err) ) {
- out() << "can't connect to server " << err << endl;
- return;
- }
-
- cout << "findOne returns:" << endl;
- cout << c.findOne("test.foo", QUERY( "x" << 3 ) ).toString() << endl;
- cout << c.findOne("test.foo", QUERY( "x" << 3 ).sort("name") ).toString() << endl;
-
- }
-
- /* TODO: unit tests should run this? */
- void testDbEval() {
- DBClientConnection c;
- string err;
- if ( !c.connect("localhost", err) ) {
- out() << "can't connect to server " << err << endl;
- return;
- }
-
- if( !c.auth("dwight", "u", "p", err) ) {
- out() << "can't authenticate " << err << endl;
- return;
- }
-
- BSONObj info;
- BSONElement retValue;
- BSONObjBuilder b;
- b.append("0", 99);
- BSONObj args = b.done();
- bool ok = c.eval("dwight", "function() { return args[0]; }", info, retValue, &args);
- out() << "eval ok=" << ok << endl;
- out() << "retvalue=" << retValue.toString() << endl;
- out() << "info=" << info.toString() << endl;
-
- out() << endl;
-
- int x = 3;
- assert( c.eval("dwight", "function() { return 3; }", x) );
-
- out() << "***\n";
-
- BSONObj foo = fromjson("{\"x\":7}");
- out() << foo.toString() << endl;
- int res=0;
- ok = c.eval("dwight", "function(parm1) { return parm1.x; }", foo, res);
- out() << ok << " retval:" << res << endl;
- }
-
- void testPaired();
-
/* --- dbclientconnection --- */
bool DBClientConnection::auth(const string &dbname, const string &username, const string &password_text, string& errmsg, bool digestPassword) {
@@ -527,23 +481,17 @@ namespace mongo {
return c->nextSafe().copy();
}
- bool DBClientConnection::connect(const string &_serverAddress, string& errmsg) {
- serverAddress = _serverAddress;
-
- string ip;
- int port;
- size_t idx = serverAddress.rfind( ":" );
- if ( idx != string::npos ) {
- port = strtol( serverAddress.substr( idx + 1 ).c_str(), 0, 10 );
- ip = serverAddress.substr( 0 , idx );
- } else {
- port = CmdLine::DefaultDBPort;
- ip = serverAddress;
- }
+ bool DBClientConnection::connect(const HostAndPort& server, string& errmsg){
+ _server = server;
+ _serverString = _server.toString();
+ return _connect( errmsg );
+ }
+ bool DBClientConnection::_connect( string& errmsg ){
+ _serverString = _server.toString();
// we keep around SockAddr for connection life -- maybe MessagingPort
// requires that?
- server.reset(new SockAddr(ip.c_str(), port));
+ server.reset(new SockAddr(_server.host().c_str(), _server.port()));
p.reset(new MessagingPort( _timeout, _logLevel ));
if (server->getAddr() == "0.0.0.0"){
@@ -553,7 +501,7 @@ namespace mongo {
if ( !p->connect(*server) ) {
stringstream ss;
- ss << "couldn't connect to server {ip: \"" << ip << "\", port: " << port << '}';
+ ss << "couldn't connect to server " << _serverString << '}';
errmsg = ss.str();
failed = true;
return false;
@@ -570,16 +518,15 @@ namespace mongo {
return;
lastReconnectTry = time(0);
- log(_logLevel) << "trying reconnect to " << serverAddress << endl;
+ log(_logLevel) << "trying reconnect to " << _serverString << endl;
string errmsg;
- string tmp = serverAddress;
failed = false;
- if ( !connect(tmp.c_str(), errmsg) ) {
- log(_logLevel) << "reconnect " << serverAddress << " failed " << errmsg << endl;
+ if ( ! _connect(errmsg) ) {
+ log(_logLevel) << "reconnect " << _serverString << " failed " << errmsg << endl;
return;
}
- log(_logLevel) << "reconnect " << serverAddress << " ok" << endl;
+ log(_logLevel) << "reconnect " << _serverString << " ok" << endl;
for( map< string, pair<string,string> >::iterator i = authCache.begin(); i != authCache.end(); i++ ) {
const char *dbname = i->first.c_str();
const char *username = i->second.first.c_str();
@@ -899,13 +846,13 @@ namespace mongo {
void DBClientConnection::checkResponse( const char *data, int nReturned ) {
/* check for errors. the only one we really care about at
this stage is "not master" */
- if ( clientPaired && nReturned ) {
+ if ( clientSet && nReturned ) {
assert(data);
BSONObj o(data);
BSONElement e = o.firstElement();
if ( strcmp(e.fieldName(), "$err") == 0 &&
e.type() == String && strncmp(e.valuestr(), "not master", 10) == 0 ) {
- clientPaired->isntMaster();
+ clientSet->isntMaster();
}
}
}
@@ -924,44 +871,59 @@ namespace mongo {
/* --- class dbclientpaired --- */
- string DBClientPaired::toString() {
- stringstream ss;
- ss << "state: " << master << '\n';
- ss << "left: " << left.toStringLong() << '\n';
- ss << "right: " << right.toStringLong() << '\n';
- return ss.str();
+ string DBClientReplicaSet::toString() {
+ return getServerAddress();
}
-#pragma warning(disable: 4355)
- DBClientPaired::DBClientPaired() :
- left(true, this), right(true, this)
- {
- master = NotSetL;
+ DBClientReplicaSet::DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers )
+ : _name( name ) , _currentMaster( 0 ), _servers( servers ){
+
+ for ( unsigned i=0; i<_servers.size(); i++ )
+ _conns.push_back( new DBClientConnection( true , this ) );
+ }
+
+ DBClientReplicaSet::~DBClientReplicaSet(){
+ for ( unsigned i=0; i<_conns.size(); i++ )
+ delete _conns[i];
+ _conns.clear();
+ }
+
+ string DBClientReplicaSet::getServerAddress() const {
+ StringBuilder ss;
+ if ( _name.size() )
+ ss << _name << "/";
+
+ for ( unsigned i=0; i<_servers.size(); i++ ){
+ if ( i > 0 )
+ ss << ",";
+ ss << _servers[i].toString();
+ }
+ return ss.str();
}
-#pragma warning(default: 4355)
/* find which server, the left or right, is currently master mode */
- void DBClientPaired::_checkMaster() {
+ void DBClientReplicaSet::_checkMaster() {
+ log( _logLevel ) << "_checkMaster on: " << toString() << endl;
for ( int retry = 0; retry < 2; retry++ ) {
- int x = master;
- for ( int pass = 0; pass < 2; pass++ ) {
- DBClientConnection& c = x == 0 ? left : right;
+ for ( unsigned i=0; i<_conns.size(); i++ ){
+ DBClientConnection * c = _conns[i];
try {
bool im;
BSONObj o;
- c.isMaster(im, &o);
- if ( retry )
- log(_logLevel) << "checkmaster: " << c.toString() << ' ' << o.toString() << '\n';
+ c->isMaster(im, &o);
+
+ //if ( retry )
+ log(_logLevel) << "checkmaster: " << c->toString() << ' ' << o << '\n';
+
if ( im ) {
- master = (State) (x + 2);
+ _currentMaster = c;
return;
}
}
- catch (AssertionException&) {
- if ( retry )
- log(_logLevel) << "checkmaster: caught exception " << c.toString() << '\n';
+ catch ( std::exception& e ) {
+ //if ( retry )
+ log(_logLevel) << "checkmaster: caught exception " << c->toString() << ' ' << e.what() << endl;
}
- x = x^1;
}
sleepsecs(1);
}
@@ -969,40 +931,54 @@ namespace mongo {
uassert( 10009 , "checkmaster: no master found", false);
}
- DBClientConnection& DBClientPaired::checkMaster() {
- if ( master > NotSetR ) {
+ DBClientConnection * DBClientReplicaSet::checkMaster() {
+ if ( _currentMaster ){
// a master is selected. let's just make sure connection didn't die
- DBClientConnection& c = master == Left ? left : right;
- if ( !c.isFailed() )
- return c;
- // after a failure, on the next checkMaster, start with the other
- // server -- presumably it took over. (not critical which we check first,
- // just will make the failover slightly faster if we guess right)
- master = master == Left ? NotSetR : NotSetL;
+ if ( ! _currentMaster->isFailed() )
+ return _currentMaster;
+ _currentMaster = 0;
}
_checkMaster();
- assert( master > NotSetR );
- return master == Left ? left : right;
+ assert( _currentMaster );
+ return _currentMaster;
}
- DBClientConnection& DBClientPaired::masterConn(){
- return checkMaster();
+ DBClientConnection& DBClientReplicaSet::masterConn(){
+ return *checkMaster();
}
- DBClientConnection& DBClientPaired::slaveConn(){
- DBClientConnection& m = checkMaster();
- assert( ! m.isFailed() );
- return master == Left ? right : left;
+ DBClientConnection& DBClientReplicaSet::slaveConn(){
+ DBClientConnection * m = checkMaster();
+ assert( ! m->isFailed() );
+
+ DBClientConnection * failedSlave = 0;
+
+ for ( unsigned i=0; i<_conns.size(); i++ ){
+ if ( m == _conns[i] )
+ continue;
+ failedSlave = _conns[i];
+ if ( _conns[i]->isFailed() )
+ continue;
+ return *_conns[i];
+ }
+
+ assert(failedSlave);
+ return *failedSlave;
}
- bool DBClientPaired::connect(const string &serverHostname1, const string &serverHostname2) {
+ bool DBClientReplicaSet::connect(){
string errmsg;
- bool l = left.connect(serverHostname1, errmsg);
- bool r = right.connect(serverHostname2, errmsg);
- master = l ? NotSetL : NotSetR;
- if ( !l && !r ) // it would be ok to fall through, but checkMaster will then try an immediate reconnect which is slow
+
+ bool anyGood = false;
+ for ( unsigned i=0; i<_conns.size(); i++ ){
+ if ( _conns[i]->connect( _servers[i] , errmsg ) )
+ anyGood = true;
+ }
+
+ if ( ! anyGood )
return false;
+
try {
checkMaster();
}
@@ -1012,62 +988,35 @@ namespace mongo {
return true;
}
- bool DBClientPaired::connect(string hostpairstring) {
- size_t comma = hostpairstring.find( "," );
- uassert( 10010 , "bad hostpairstring", comma != string::npos);
- return connect( hostpairstring.substr( 0 , comma ) , hostpairstring.substr( comma + 1 ) );
- }
-
- bool DBClientPaired::auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword ) {
- DBClientConnection& m = checkMaster();
- if( !m.auth(dbname, username, pwd, errmsg, digestPassword ) )
+ bool DBClientReplicaSet::auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword ) {
+ DBClientConnection * m = checkMaster();
+ if( !m->auth(dbname, username, pwd, errmsg, digestPassword ) )
return false;
+
/* we try to authentiate with the other half of the pair -- even if down, that way the authInfo is cached. */
- string e;
- try {
- if( &m == &left )
- right.auth(dbname, username, pwd, e, digestPassword );
- else
- left.auth(dbname, username, pwd, e, digestPassword );
- }
- catch( AssertionException&) {
- }
+ for ( unsigned i=0; i<_conns.size(); i++ ){
+ if ( _conns[i] == m )
+ continue;
+ try {
+ string e;
+ _conns[i]->auth( dbname , username , pwd , e , digestPassword );
+ }
+ catch ( AssertionException& e ){
+ }
+ }
+
return true;
}
- auto_ptr<DBClientCursor> DBClientPaired::query(const string &a, Query b, int c, int d,
- const BSONObj *e, int f, int g)
- {
- return checkMaster().query(a,b,c,d,e,f,g);
- }
-
- BSONObj DBClientPaired::findOne(const string &a, const Query& b, const BSONObj *c, int d) {
- return checkMaster().findOne(a,b,c,d);
- }
-
- void testPaired() {
- DBClientPaired p;
- log() << "connect returns " << p.connect("localhost:27017", "localhost:27018") << endl;
-
- //DBClientConnection p(true);
- string errmsg;
- // log() << "connect " << p.connect("localhost", errmsg) << endl;
- log() << "auth " << p.auth("dwight", "u", "p", errmsg) << endl;
-
- while( 1 ) {
- sleepsecs(3);
- try {
- log() << "findone returns " << p.findOne("dwight.foo", BSONObj()).toString() << endl;
- sleepsecs(3);
- BSONObj info;
- bool im;
- log() << "ismaster returns " << p.isMaster(im,&info) << " info: " << info.toString() << endl;
- }
- catch(...) {
- cout << "caught exception" << endl;
- }
- }
- }
+ auto_ptr<DBClientCursor> DBClientReplicaSet::query(const string &a, Query b, int c, int d,
+ const BSONObj *e, int f, int g){
+ // TODO: if slave ok is set go to a slave
+ return checkMaster()->query(a,b,c,d,e,f,g);
+ }
+
+ BSONObj DBClientReplicaSet::findOne(const string &a, const Query& b, const BSONObj *c, int d) {
+ return checkMaster()->findOne(a,b,c,d);
+ }
bool serverAlive( const string &uri ) {
DBClientConnection c( false, 0, 20 ); // potentially the connection to server could fail while we're checking if it's alive - so use timeouts
147 client/dbclient.h
View
@@ -98,7 +98,7 @@ namespace mongo {
class ConnectionString {
public:
- enum ConnectionType { INVALID , MASTER , PAIR , SYNC };
+ enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC };
ConnectionString( const HostAndPort& server ){
_type = MASTER;
@@ -111,14 +111,22 @@ namespace mongo {
_finishInit();
}
- ConnectionString( ConnectionType type , const string& s ){
+ ConnectionString( ConnectionType type , const string& s , const string& setName = "" ){
_type = type;
+ _setName = setName;
_fillServers( s );
switch ( _type ){
case MASTER:
assert( _servers.size() == 1 );
break;
+ case SET:
+ assert( _setName.size() );
+ assert( _servers.size() > 1 );
+ break;
+ case PAIR:
+ assert( _servers.size() == 2 );
+ break;
default:
assert( _servers.size() > 0 );
}
@@ -144,10 +152,6 @@ namespace mongo {
return _string;
}
- operator string() const {
- return toString();
- }
-
DBClientBase* connect( string& errmsg ) const;
static ConnectionString parse( const string& url , string& errmsg );
@@ -180,8 +184,9 @@ namespace mongo {
ConnectionType _type;
vector<HostAndPort> _servers;
string _string;
+ string _setName;
};
-
+
/**
* controls how much a clients cares about writes
* default is NORMAL
@@ -749,10 +754,11 @@ namespace mongo {
virtual bool callRead( Message& toSend , Message& response ) = 0;
// virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed
virtual void say( Message& toSend ) = 0;
-
+
+ virtual ConnectionString::ConnectionType type() const = 0;
}; // DBClientBase
- class DBClientPaired;
+ class DBClientReplicaSet;
class ConnectException : public UserException {
public:
@@ -764,27 +770,31 @@ namespace mongo {
This is the main entry point for talking to a simple Mongo setup
*/
class DBClientConnection : public DBClientBase {
- DBClientPaired *clientPaired;
+ DBClientReplicaSet *clientSet;
boost::scoped_ptr<MessagingPort> p;
boost::scoped_ptr<SockAddr> server;
bool failed; // true if some sort of fatal error has ever happened
bool autoReconnect;
time_t lastReconnectTry;
- string serverAddress; // remember for reconnects
+ HostAndPort _server; // remember for reconnects
+ string _serverString;
+ int _port;
void _checkConnection();
void checkConnection() { if( failed ) _checkConnection(); }
map< string, pair<string,string> > authCache;
int _timeout;
+
+ bool _connect( string& errmsg );
public:
/**
@param _autoReconnect if true, automatically reconnect on a connection failure
- @param cp used by DBClientPaired. You do not need to specify this parameter
+ @param cp used by DBClientReplicaSet. You do not need to specify this parameter
@param timeout tcp timeout in seconds - this is for read/write, not connect.
Connect timeout is fixed, but short, at 5 seconds.
*/
- DBClientConnection(bool _autoReconnect=false, DBClientPaired* cp=0, int timeout=0) :
- clientPaired(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0), _timeout(timeout) { }
+ DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* cp=0, int timeout=0) :
+ clientSet(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0), _timeout(timeout) { }
/** Connect to a Mongo database server.
@@ -794,9 +804,25 @@ namespace mongo {
@param serverHostname host to connect to. can include port number ( 127.0.0.1 , 127.0.0.1:5555 )
If you use IPv6 you must add a port number ( ::1:27017 )
@param errmsg any relevant error message will appended to the string
+ @deprecated please use HostAndPort
+ @return false if fails to connect.
+ */
+ virtual bool connect(const char * hostname, string& errmsg){
+ // TODO: remove this method
+ HostAndPort t( hostname );
+ return connect( t , errmsg );
+ }
+
+ /** Connect to a Mongo database server.
+
+ If autoReconnect is true, you can try to use the DBClientConnection even when
+ false was returned -- it will try to connect again.
+
+ @param server server to connect to.
+ @param errmsg any relevant error message will appended to the string
@return false if fails to connect.
*/
- virtual bool connect(const string &serverHostname, string& errmsg);
+ virtual bool connect(const HostAndPort& server, string& errmsg);
/** Connect to a Mongo database server. Exception throwing version.
Throws a UserException if cannot connect.
@@ -806,9 +832,9 @@ namespace mongo {
@param serverHostname host to connect to. can include port number ( 127.0.0.1 , 127.0.0.1:5555 )
*/
- void connect(string serverHostname) {
+ void connect(const string& serverHostname) {
string errmsg;
- if( !connect(serverHostname.c_str(), errmsg) )
+ if( !connect(HostAndPort(serverHostname), errmsg) )
throw ConnectException(string("can't connect ") + errmsg);
}
@@ -839,18 +865,18 @@ namespace mongo {
string toStringLong() const {
stringstream ss;
- ss << serverAddress;
+ ss << _serverString;
if ( failed ) ss << " failed";
return ss.str();
}
/** Returns the address of the server */
string toString() {
- return serverAddress;
+ return _serverString;
}
string getServerAddress() const {
- return serverAddress;
+ return _serverString;
}
virtual void killCursor( long long cursorID );
@@ -860,49 +886,47 @@ namespace mongo {
}
virtual void say( Message &toSend );
-
+ virtual bool call( Message &toSend, Message &response, bool assertOk = true );
+
+ virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
protected:
friend class SyncClusterConnection;
virtual void recv( Message& m );
- virtual bool call( Message &toSend, Message &response, bool assertOk = true );
virtual void sayPiggyBack( Message &toSend );
virtual void checkResponse( const char *data, int nReturned );
};
- /** Use this class to connect to a replica pair of servers. The class will manage
- checking for which server in a replica pair is master, and do failover automatically.
-
+ /** Use this class to connect to a replica set of servers. The class will manage
+ checking for which server in a replica set is master, and do failover automatically.
+
+ This can also be used to connect to replica pairs since pairs are a subset of sets
+
On a failover situation, expect at least one operation to return an error (throw
an exception) before the failover is complete. Operations are not retried.
*/
- class DBClientPaired : public DBClientBase {
- DBClientConnection left,right;
- enum State {
- NotSetL=0,
- NotSetR=1,
- Left, Right
- } master;
+ class DBClientReplicaSet : public DBClientBase {
+ string _name;
+ DBClientConnection * _currentMaster;
+ vector<HostAndPort> _servers;
+ vector<DBClientConnection*> _conns;
+
void _checkMaster();
- DBClientConnection& checkMaster();
+ DBClientConnection * checkMaster();
public:
- /** Call connect() after constructing. autoReconnect is always on for DBClientPaired connections. */
- DBClientPaired();
+ /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet connections. */
+ DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers );
+ virtual ~DBClientReplicaSet();
- /** Returns false is neither member of the pair were reachable, or neither is
+ /** Returns false if nomember of the set were reachable, or neither is
master, although,
when false returned, you can still try to use this connection object, it will
try reconnects.
*/
- bool connect(const string &serverHostname1, const string &serverHostname2);
-
- /** Connect to a server pair using a host pair string of the form
- hostname[:port],hostname[:port]
- */
- bool connect(string hostpairstring);
+ bool connect();
- /** Authorize. Authorizes both sides of the pair as needed.
+ /** Authorize. Authorizes all nodes as needed
*/
virtual bool auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword = true );
@@ -917,27 +941,27 @@ namespace mongo {
/** insert */
virtual void insert( const string &ns , BSONObj obj ) {
- checkMaster().insert(ns, obj);
+ checkMaster()->insert(ns, obj);
}
/** insert multiple objects. Note that single object insert is asynchronous, so this version
is only nominally faster and not worth a special effort to try to use. */
virtual void insert( const string &ns, const vector< BSONObj >& v ) {
- checkMaster().insert(ns, v);
+ checkMaster()->insert(ns, v);
}
/** remove */
virtual void remove( const string &ns , Query obj , bool justOne = 0 ) {
- checkMaster().remove(ns, obj, justOne);
+ checkMaster()->remove(ns, obj, justOne);
}
/** update */
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) {
- return checkMaster().update(ns, query, obj, upsert,multi);
+ return checkMaster()->update(ns, query, obj, upsert,multi);
}
virtual void killCursor( long long cursorID ){
- checkMaster().killCursor( cursorID );
+ checkMaster()->killCursor( cursorID );
}
string toString();
@@ -945,30 +969,27 @@ namespace mongo {
/* this is the callback from our underlying connections to notify us that we got a "not master" error.
*/
void isntMaster() {
- master = ( ( master == Left ) ? NotSetR : NotSetL );
- }
-
- string getServerAddress() const {
- return left.getServerAddress() + "," + right.getServerAddress();
+ _currentMaster = 0;
}
+ string getServerAddress() const;
DBClientConnection& masterConn();
DBClientConnection& slaveConn();
-
- /* TODO - not yet implemented. mongos may need these. */
- virtual bool call( Message &toSend, Message &response, bool assertOk=true ) { assert(false); return false; }
- virtual void say( Message &toSend ) { assert(false); }
+
+
+ virtual bool call( Message &toSend, Message &response, bool assertOk=true ) { return checkMaster()->call( toSend , response , assertOk ); }
+ virtual void say( Message &toSend ) { checkMaster()->say( toSend ); }
+ virtual bool callRead( Message& toSend , Message& response ){ return checkMaster()->callRead( toSend , response ); }
+
+ virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; }
+
+ protected:
virtual void sayPiggyBack( Message &toSend ) { assert(false); }
virtual void checkResponse( const char *data, int nReturned ) { assert(false); }
- virtual bool callRead( Message& toSend , Message& response ){
- return call( toSend , response );
- }
-
bool isFailed() const {
- // TODO: this really should check isFailed on current master as well
- return master < Left;
+ return _currentMaster == 0 || _currentMaster->isFailed();
}
};
2  client/syncclusterconnection.h
View
@@ -88,6 +88,8 @@ namespace mongo {
virtual bool callRead( Message& toSend , Message& response );
+ virtual ConnectionString::ConnectionType type() const { return ConnectionString::SYNC; }
+
private:
SyncClusterConnection( SyncClusterConnection& prev );
string _toString() const;
2  db/instance.h
View
@@ -141,6 +141,8 @@ namespace mongo {
virtual bool callRead( Message& toSend , Message& response ){
return call( toSend , response );
}
+
+ virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
};
extern int lockFile;
15 jstests/replsets/replset1.js
View
@@ -34,6 +34,10 @@ doTest = function( signal ) {
// and slaves in the set and wait until the change has replicated.
replTest.awaitReplication();
+
+ cppconn = new Mongo( replTest.getURL() ).getDB( "foo" );
+ assert.eq( 1000 , cppconn.foo.findOne().a , "cppconn 1" );
+
// Here's how to stop the master node
var master_id = replTest.getNodeId( master );
replTest.stop( master_id );
@@ -46,6 +50,17 @@ doTest = function( signal ) {
assert( master_id != new_master_id, "Old master shouldn't be equal to new master." );
+
+ {
+ // this may fail since it has to reconnect
+ try {
+ cppconn.foo.findOne()
+ }
+ catch ( e ){
+ }
+ assert.eq( 1000 , cppconn.foo.findOne().a , "cppconn 2" );
+ }
+
// Here's how to restart a node:
replTest.restart( master_id );
45 jstests/replsets/replsetarb2.js
View
@@ -0,0 +1,45 @@
+// Election when master fails and remaining nodes are an arbiter and a slave.
+// Note that in this scenario, the arbiter needs two votes.
+
+doTest = function( signal ) {
+
+ var replTest = new ReplSetTest( {name: 'unicomplex', nodes: 3} );
+ var nodes = replTest.nodeList();
+
+ print(tojson(nodes));
+
+ var conns = replTest.startSet();
+ var r = replTest.initiate({"_id" : "unicomplex",
+ "members" : [
+ {"_id" : 0, "host" : nodes[0] },
+ {"_id" : 1, "host" : nodes[1], "arbiterOnly" : true, "votes": 2},
+ {"_id" : 2, "host" : nodes[2] }]});
+
+ // Make sure we have a master
+ var master = replTest.getMaster();
+
+ // Make sure we have an arbiter
+ assert.soon(function() {
+ res = conns[1].getDB("admin").runCommand({replSetGetStatus: 1});
+ printjson(res);
+ return res.myState == 7;
+ }, "Aribiter failed to initialize.");
+
+ // Wait for initial replication
+ master.getDB("foo").foo.insert({a: "foo"});
+ replTest.awaitReplication();
+
+ // Now kill the original master
+ mId = replTest.getNodeId( master );
+ replTest.stop( mId );
+
+ // And make sure that the slave is promoted
+ new_master = replTest.getMaster();
+
+ newMasterId = replTest.getNodeId( new_master );
+ assert( newMasterId == 2, "Slave wasn't promoted to new master");
+
+ replTest.stopSet( signal );
+}
+
+doTest( 15 );
8 shell/servers.js
View
@@ -1146,6 +1146,14 @@ ReplSetTest.prototype.awaitReplication = function() {
var synced = true;
for(var i=0; i<this.liveNodes.slaves.length; i++) {
var slave = this.liveNodes.slaves[i];
+
+ // Continue if we're connected to an arbiter
+ if(res = slave.getDB("admin").runCommand({replSetGetStatus: 1})) {
+ if(res.myState == 7) {
+ continue;
+ }
+ }
+
slave.getDB("admin").getMongo().setSlaveOk();
var log = slave.getDB("local")['replset.minvalid'];
if(log.find().hasNext()) {
5 tools/tool.cpp
View
@@ -229,8 +229,9 @@ namespace mongo {
}
DBClientBase& Tool::conn( bool slaveIfPaired ){
- if ( _paired && slaveIfPaired )
- return ((DBClientPaired*)_conn)->slaveConn();
+ // TODO: _paired is deprecated
+ if ( slaveIfPaired && _conn->type() == ConnectionString::SET )
+ return ((DBClientReplicaSet*)_conn)->slaveConn();
return *_conn;
}
Please sign in to comment.
Something went wrong with that request. Please try again.