diff options
author | Eliot Horowitz <eliot@10gen.com> | 2011-02-02 10:47:02 -0500 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2011-02-02 10:47:02 -0500 |
commit | 1227dfe359d312389a7aaa4302f4be61e05444dc (patch) | |
tree | a75548c8ed99d85c15b032ba295fcfa0e597833e /client/dbclient_rs.cpp | |
parent | 9297201b7f10690812917a60bc6f283e67972625 (diff) | |
download | mongo-1227dfe359d312389a7aaa4302f4be61e05444dc.tar.gz |
fix concurrency issues with DBClientReplicaSet SERVER-2466
Diffstat (limited to 'client/dbclient_rs.cpp')
-rw-r--r-- | client/dbclient_rs.cpp | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/client/dbclient_rs.cpp b/client/dbclient_rs.cpp index 07f5d8145b0..748a1f3f52a 100644 --- a/client/dbclient_rs.cpp +++ b/client/dbclient_rs.cpp @@ -50,7 +50,7 @@ namespace mongo { ReplicaSetMonitor::ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers ) - : _lock( "ReplicaSetMonitor instance" ) , _name( name ) , _master(-1) { + : _lock( "ReplicaSetMonitor instance" ) , _checkConnectionLock( "ReplicaSetMonitor check connection lock" ), _name( name ) , _master(-1) { string errmsg; @@ -148,7 +148,13 @@ namespace mongo { HostAndPort ReplicaSetMonitor::getMaster() { - if ( _master < 0 || !_nodes[_master].ok ) + bool good = false; + { + scoped_lock lk( _lock ); + good = _master >= 0 && _nodes[_master].ok; + } + + if ( ! good ) _check(); uassert( 10009 , str::stream() << "ReplicaSetMonitor no master found for set: " << _name , _master >= 0 ); @@ -156,6 +162,23 @@ namespace mongo { scoped_lock lk( _lock ); return _nodes[_master].addr; } + + HostAndPort ReplicaSetMonitor::getSlave( const HostAndPort& prev ) { + // make sure its valid + if ( prev.port() > 0 ) { + scoped_lock lk( _lock ); + for ( unsigned i=0; i<_nodes.size(); i++ ) { + if ( prev != _nodes[i].addr ) + continue; + + if ( _nodes[i].ok ) + return prev; + break; + } + } + + return getSlave(); + } HostAndPort ReplicaSetMonitor::getSlave() { int x = rand() % _nodes.size(); @@ -235,8 +258,11 @@ namespace mongo { changed = true; } } + + bool ReplicaSetMonitor::_checkConnection( DBClientConnection * c , string& maybePrimary , bool verbose ) { + scoped_lock lk( _checkConnectionLock ); bool isMaster = false; bool changed = false; try { @@ -369,20 +395,24 @@ namespace mongo { _masterHost = _monitor->getMaster(); _master.reset( new DBClientConnection( true ) ); - _master->connect( _masterHost ); + string errmsg; + if ( ! _master->connect( _masterHost , errmsg ) ) { + _monitor->notifyFailure( _masterHost ); + uasserted( 13639 , str::stream() << "can't connect to new replica set master [" << _masterHost.toString() << "] err: " << errmsg ); + } _auth( _master.get() ); return _master.get(); } DBClientConnection * DBClientReplicaSet::checkSlave() { - HostAndPort h = _monitor->getSlave(); + HostAndPort h = _monitor->getSlave( _slaveHost ); if ( h == _slaveHost ) { if ( ! _slave->isFailed() ) return _slave.get(); _monitor->notifySlaveFailure( _slaveHost ); } - + _slaveHost = _monitor->getSlave(); _slave.reset( new DBClientConnection( true ) ); _slave->connect( _slaveHost ); |