DBClientBase* getVersionable( DBClientBase* conn ){ switch ( conn->type() ) { case ConnectionString::INVALID: massert( 15904, str::stream() << "cannot set version on invalid connection " << conn->toString(), false ); return NULL; case ConnectionString::MASTER: return conn; case ConnectionString::PAIR: massert( 15905, str::stream() << "cannot set version or shard on pair connection " << conn->toString(), false ); return NULL; case ConnectionString::SYNC: massert( 15906, str::stream() << "cannot set version or shard on sync connection " << conn->toString(), false ); return NULL; case ConnectionString::CUSTOM: massert( 16334, str::stream() << "cannot set version or shard on custom connection " << conn->toString(), false ); return NULL; case ConnectionString::SET: DBClientReplicaSet* set = (DBClientReplicaSet*) conn; return &( set->masterConn() ); } verify( false ); return NULL; }
DBClientBase& Tool::conn( bool slaveIfPaired ) { if ( slaveIfPaired && _conn->type() == ConnectionString::SET ) { if (!_slaveConn) { DBClientReplicaSet* rs = static_cast<DBClientReplicaSet*>(_conn); _slaveConn = &rs->slaveConn(); } return *_slaveConn; } return *_conn; }
/* * ok,err = replicaset:connect() */ static int replicaset_connect(lua_State *L) { DBClientReplicaSet *replicaset = userdata_to_replicaset(L, 1); try { replicaset->connect(); } catch (std::exception &e) { lua_pushnil(L); lua_pushfstring(L, LUAMONGO_ERR_CONNECT_FAILED, LUAMONGO_REPLICASET, e.what()); return 2; } lua_pushboolean(L, 1); return 1; }
int main( int argc , const char ** argv ) { unsigned nThreads = 1; bool print = false; for ( int i=1; i<argc; i++ ) { if ( mongoutils::str::equals( "--threads" , argv[i] ) ) { nThreads = atoi( argv[++i] ); } else if ( mongoutils::str::equals( "--print" , argv[1] ) ) { print = true; } else { cerr << "unknown option: " << argv[i] << endl; return 1; } } string errmsg; ConnectionString cs = ConnectionString::parse( "foo/127.0.0.1" , errmsg ); if ( ! cs.isValid() ) { cout << "error parsing url: " << errmsg << endl; return 1; } DBClientReplicaSet * conn = (DBClientReplicaSet*)cs.connect( errmsg ); if ( ! conn ) { cout << "error connecting: " << errmsg << endl; return 2; } string collName = "test.rs1"; conn->dropCollection( collName ); vector<boost::shared_ptr<boost::thread> > threads; for ( unsigned i=0; i<nThreads; i++ ) { string errmsg; threads.push_back( boost::shared_ptr<boost::thread>( new boost::thread( boost::bind( workerThread , collName , print , (DBClientReplicaSet*)cs.connect(errmsg) ) ) ) ); } for ( unsigned i=0; i<threads.size(); i++ ) { threads[i]->join(); } }
DBClientBase* ConnectionString::connect( string& errmsg, double socketTimeout ) const { switch ( _type ) { case MASTER: { DBClientConnection * c = new DBClientConnection(true); c->setSoTimeout( socketTimeout ); log(1) << "creating new connection to:" << _servers[0] << endl; if ( ! c->connect( _servers[0] , errmsg ) ) { delete c; return 0; } log(1) << "connected connection!" << endl; return c; } case PAIR: case SET: { DBClientReplicaSet * set = new DBClientReplicaSet( _setName , _servers , socketTimeout ); if( ! set->connect() ) { delete set; errmsg = "connect failed to set "; errmsg += toString(); return 0; } return set; } case SYNC: { // TODO , don't copy list<HostAndPort> l; for ( unsigned i=0; i<_servers.size(); i++ ) l.push_back( _servers[i] ); SyncClusterConnection* c = new SyncClusterConnection( l, socketTimeout ); return c; } case INVALID: throw UserException( 13421 , "trying to connect to invalid ConnectionString" ); break; } assert( 0 ); return 0; }
void ShardingConnectionHook::onCreate( DBClientBase * conn ) { if( !noauth ) { bool result; string err; LOG(2) << "calling onCreate auth for " << conn->toString() << endl; if ( conn->type() == ConnectionString::SET && !authOnPrimaryOnly ) { DBClientReplicaSet* setConn = dynamic_cast<DBClientReplicaSet*>(conn); verify(setConn); result = setConn->authAny( "local", internalSecurity.user, internalSecurity.pwd, err, false ); } else { result = conn->auth( "local", internalSecurity.user, internalSecurity.pwd, err, false ); } uassert( 15847, str::stream() << "can't authenticate to server " << conn->getServerAddress() << causedBy( err ), result ); } if ( _shardedConnections && versionManager.isVersionableCB( conn ) ) { // We must initialize sharding on all connections, so that we get exceptions if sharding is enabled on // the collection. BSONObj result; bool ok = versionManager.initShardVersionCB( conn, result ); // assert that we actually successfully setup sharding uassert( 15907, str::stream() << "could not initialize sharding on connection " << (*conn).toString() << ( result["errmsg"].type() == String ? causedBy( result["errmsg"].String() ) : causedBy( (string)"unknown failure : " + result.toString() ) ), ok ); } }
/** * @return true if had to do something */ bool checkShardVersion( DBClientBase& conn_in , const string& ns , bool authoritative , int tryNumber ) { // TODO: cache, optimize, etc... WriteBackListener::init( conn_in ); DBConfigPtr conf = grid.getDBConfig( ns ); if ( ! conf ) return false; DBClientBase* conn = 0; switch ( conn_in.type() ) { case ConnectionString::INVALID: assert(0); break; case ConnectionString::MASTER: // great conn = &conn_in; break; case ConnectionString::PAIR: assert( ! "pair not support for sharding" ); break; case ConnectionString::SYNC: // TODO: we should check later that we aren't actually sharded on this conn = &conn_in; break; case ConnectionString::SET: DBClientReplicaSet* set = (DBClientReplicaSet*)&conn_in; conn = &(set->masterConn()); break; } assert(conn); unsigned long long officialSequenceNumber = 0; ChunkManagerPtr manager; const bool isSharded = conf->isSharded( ns ); if ( isSharded ) { manager = conf->getChunkManagerIfExists( ns , authoritative ); // It's possible the chunk manager was reset since we checked whether sharded was true, // so must check this here. if( manager ) officialSequenceNumber = manager->getSequenceNumber(); } // has the ChunkManager been reloaded since the last time we updated the connection-level version? // (ie., last time we issued the setShardVersions below) unsigned long long sequenceNumber = connectionShardStatus.getSequence(conn,ns); if ( sequenceNumber == officialSequenceNumber ) { return false; } ShardChunkVersion version = 0; if ( isSharded && manager ) { version = manager->getVersion( Shard::make( conn->getServerAddress() ) ); } LOG(2) << " have to set shard version for conn: " << conn << " ns:" << ns << " my last seq: " << sequenceNumber << " current: " << officialSequenceNumber << " version: " << version << " manager: " << manager.get() << endl; BSONObj result; if ( setShardVersion( *conn , ns , version , authoritative , result ) ) { // success! LOG(1) << " setShardVersion success: " << result << endl; connectionShardStatus.setSequence( conn , ns , officialSequenceNumber ); return true; } LOG(1) << " setShardVersion failed!\n" << result << endl; if ( result["need_authoritative"].trueValue() ) massert( 10428 , "need_authoritative set but in authoritative mode already" , ! authoritative ); if ( ! authoritative ) { checkShardVersion( *conn , ns , 1 , tryNumber + 1 ); return true; } if ( result["reloadConfig"].trueValue() ) { if( result["version"].timestampTime() == 0 ){ // reload db conf->reload(); } else { // reload config conf->getChunkManager( ns , true ); } } const int maxNumTries = 7; if ( tryNumber < maxNumTries ) { LOG( tryNumber < ( maxNumTries / 2 ) ? 1 : 0 ) << "going to retry checkShardVersion host: " << conn->getServerAddress() << " " << result << endl; sleepmillis( 10 * tryNumber ); checkShardVersion( *conn , ns , true , tryNumber + 1 ); return true; } string errmsg = str::stream() << "setShardVersion failed host: " << conn->getServerAddress() << " " << result; log() << " " << errmsg << endl; massert( 10429 , errmsg , 0 ); return true; }
DBClientBase* ConnectionString::connect( std::string& errmsg, double socketTimeout ) const { switch ( _type ) { case MASTER: { DBClientConnection * c = new DBClientConnection(true); c->setSoTimeout( socketTimeout ); LOG(1) << "creating new connection to:" << _servers[0]; if ( ! c->connect( _servers[0] , errmsg ) ) { delete c; return 0; } LOG(1) << "connected connection!"; return c; } case PAIR: case SET: { DBClientReplicaSet * set = new DBClientReplicaSet( _setName , _servers , socketTimeout ); if( ! set->connect() ) { delete set; errmsg = "connect failed to replica set "; errmsg += toString(); return 0; } return set; } case SYNC: { // TODO , don't copy std::list<HostAndPort> l; for ( unsigned i=0; i<_servers.size(); i++ ) l.push_back( _servers[i] ); SyncClusterConnection* c = new SyncClusterConnection( l, socketTimeout ); return c; } case CUSTOM: { // Lock in case other things are modifying this at the same time boost::lock_guard<boost::mutex> lk( _connectHookMutex ); // Allow the replacement of connections with other connections - useful for testing. uassert( 16335, "custom connection to " + this->toString() + " specified with no connection hook", _connectHook ); // Double-checked lock, since this will never be active during normal operation DBClientBase* replacementConn = _connectHook->connect( *this, errmsg, socketTimeout ); log() << "replacing connection to " << this->toString() << " with " << ( replacementConn ? replacementConn->getServerAddress() : "(empty)" ); return replacementConn; } case INVALID: throw UserException( 13421 , "trying to connect to invalid ConnectionString" ); break; } verify( 0 ); return 0; }
/* * __tostring */ static int replicaset_tostring(lua_State *L) { DBClientReplicaSet *replicaset = userdata_to_replicaset(L, 1); lua_pushfstring(L, "%s: %s", LUAMONGO_REPLICASET, replicaset->toString().c_str()); return 1; }
int main( int argc , const char ** argv ) { unsigned nThreads = 1; bool print = false; bool testTimeout = false; for ( int i=1; i<argc; i++ ) { if ( mongoutils::str::equals( "--threads" , argv[i] ) ) { nThreads = atoi( argv[++i] ); } else if ( mongoutils::str::equals( "--print" , argv[i] ) ) { print = true; } // Run a special mode to demonstrate the DBClientReplicaSet so_timeout option. else if ( mongoutils::str::equals( "--testTimeout" , argv[i] ) ) { testTimeout = true; } else { cerr << "unknown option: " << argv[i] << endl; return EXIT_FAILURE; } } Status status = client::initialize(); if ( !status.isOK() ) { std::cout << "failed to initialize the client driver: " << status.toString() << endl; return EXIT_FAILURE; } string errmsg; ConnectionString cs = ConnectionString::parse( "foo/127.0.0.1" , errmsg ); if ( ! cs.isValid() ) { cout << "error parsing url: " << errmsg << endl; return EXIT_FAILURE; } DBClientReplicaSet * conn = static_cast<DBClientReplicaSet*>( cs.connect( errmsg, testTimeout ? 10 : 0 ) ); if ( ! conn ) { cout << "error connecting: " << errmsg << endl; return EXIT_FAILURE; } string collName = "test.rs1"; conn->dropCollection( collName ); if ( testTimeout ) { conn->insert( collName, BSONObj() ); try { conn->count( collName, BSON( "$where" << "sleep(40000)" ) ); } catch( DBException& ) { return EXIT_SUCCESS; } cout << "expected socket exception" << endl; return EXIT_FAILURE; } vector<boost::shared_ptr<boost::thread> > threads; for ( unsigned i=0; i<nThreads; i++ ) { string errmsg; threads.push_back( boost::shared_ptr<boost::thread>( new boost::thread( boost::bind( workerThread , collName , print , static_cast<DBClientReplicaSet*>( cs.connect(errmsg) ) ) ) ) ); } for ( unsigned i=0; i<threads.size(); i++ ) { threads[i]->join(); } return EXIT_SUCCESS; }