diff options
Diffstat (limited to 's/grid.cpp')
-rw-r--r-- | s/grid.cpp | 153 |
1 files changed, 79 insertions, 74 deletions
diff --git a/s/grid.cpp b/s/grid.cpp index 969f4448f85..5d337d38ce4 100644 --- a/s/grid.cpp +++ b/s/grid.cpp @@ -27,38 +27,39 @@ #include "shard.h" namespace mongo { - - DBConfigPtr Grid::getDBConfig( string database , bool create , const string& shardNameHint ){ + + DBConfigPtr Grid::getDBConfig( string database , bool create , const string& shardNameHint ) { { string::size_type i = database.find( "." ); if ( i != string::npos ) database = database.substr( 0 , i ); } - + if ( database == "config" ) return configServerPtr; scoped_lock l( _lock ); DBConfigPtr& cc = _databases[database]; - if ( !cc ){ + if ( !cc ) { cc.reset(new DBConfig( database )); - if ( ! cc->load() ){ - if ( create ){ + if ( ! cc->load() ) { + if ( create ) { // note here that cc->primary == 0. log() << "couldn't find database [" << database << "] in config db" << endl; - - { // lets check case + + { + // lets check case ScopedDbConnection conn( configServer.modelServer() ); BSONObjBuilder b; b.appendRegex( "_id" , (string)"^" + database + "$" , "i" ); BSONObj d = conn->findOne( ShardNS::database , b.obj() ); conn.done(); - if ( ! d.isEmpty() ){ + if ( ! d.isEmpty() ) { cc.reset(); stringstream ss; - ss << "can't have 2 databases that just differ on case " + ss << "can't have 2 databases that just differ on case " << " have: " << d["_id"].String() << " want to add: " << database; @@ -67,20 +68,22 @@ namespace mongo { } Shard primary; - if ( database == "admin" ){ + if ( database == "admin" ) { primary = configServer.getPrimary(); - } else if ( shardNameHint.empty() ){ + } + else if ( shardNameHint.empty() ) { primary = Shard::pick(); - } else { + } + else { // use the shard name if provided Shard shard; shard.reset( shardNameHint ); primary = shard; } - if ( primary.ok() ){ + if ( primary.ok() ) { cc->setPrimary( primary.getName() ); // saves 'cc' to configDB log() << "\t put [" << database << "] on: " << primary << endl; } @@ -94,45 +97,45 @@ namespace mongo { cc.reset(); } } - + } - + return cc; } - void Grid::removeDB( string database ){ + void Grid::removeDB( string database ) { uassert( 10186 , "removeDB expects db name" , database.find( '.' ) == string::npos ); scoped_lock l( _lock ); _databases.erase( database ); - + } bool Grid::allowLocalHost() const { return _allowLocalShard; } - void Grid::setAllowLocalHost( bool allow ){ + void Grid::setAllowLocalHost( bool allow ) { _allowLocalShard = allow; } - bool Grid::addShard( string* name , const ConnectionString& servers , long long maxSize , string& errMsg ){ + bool Grid::addShard( string* name , const ConnectionString& servers , long long maxSize , string& errMsg ) { // name can be NULL, so privide a dummy one here to avoid testing it elsewhere string nameInternal; if ( ! name ) { name = &nameInternal; } - // Check whether the host (or set) exists and run several sanity checks on this request. + // Check whether the host (or set) exists and run several sanity checks on this request. // There are two set of sanity checks: making sure adding this particular shard is consistent - // with the replica set state (if it exists) and making sure this shards databases can be + // with the replica set state (if it exists) and making sure this shards databases can be // brought into the grid without conflict. vector<string> dbNames; try { ScopedDbConnection newShardConn( servers ); newShardConn->getLastError(); - - if ( newShardConn->type() == ConnectionString::SYNC ){ + + if ( newShardConn->type() == ConnectionString::SYNC ) { newShardConn.done(); errMsg = "can't use sync cluster as a shard. for replica set, have to use <setname>/<server1>,<server2>,..."; return false; @@ -147,10 +150,10 @@ namespace mongo { newShardConn.done(); return false; } - + BSONObj resIsMaster; ok = newShardConn->runCommand( "admin" , BSON( "isMaster" << 1 ) , resIsMaster ); - if ( !ok ){ + if ( !ok ) { ostringstream ss; ss << "failed running isMaster: " << resIsMaster; errMsg = ss.str(); @@ -161,7 +164,7 @@ namespace mongo { // if the shard has only one host, make sure it is not part of a replica set string setName = resIsMaster["setName"].str(); string commandSetName = servers.getSetName(); - if ( commandSetName.empty() && ! setName.empty() ){ + if ( commandSetName.empty() && ! setName.empty() ) { ostringstream ss; ss << "host is part of set: " << setName << " use replica set url format <setname>/<server1>,<server2>,...."; errMsg = ss.str(); @@ -170,7 +173,7 @@ namespace mongo { } // if the shard is part of replica set, make sure it is the right one - if ( ! commandSetName.empty() && ( commandSetName != setName ) ){ + if ( ! commandSetName.empty() && ( commandSetName != setName ) ) { ostringstream ss; ss << "host is part of a different set: " << setName; errMsg = ss.str(); @@ -178,34 +181,34 @@ namespace mongo { return false; } - // if the shard is part of a replica set, make sure all the hosts mentioned in 'servers' are part of + // if the shard is part of a replica set, make sure all the hosts mentioned in 'servers' are part of // the set. It is fine if not all members of the set are present in 'servers'. bool foundAll = true; string offendingHost; - if ( ! commandSetName.empty() ){ + if ( ! commandSetName.empty() ) { set<string> hostSet; BSONObjIterator iter( resIsMaster["hosts"].Obj() ); - while ( iter.more() ){ + while ( iter.more() ) { hostSet.insert( iter.next().String() ); // host:port } - if ( resIsMaster["passives"].isABSONObj() ){ + if ( resIsMaster["passives"].isABSONObj() ) { BSONObjIterator piter( resIsMaster["passives"].Obj() ); - while ( piter.more() ){ + while ( piter.more() ) { hostSet.insert( piter.next().String() ); // host:port } } vector<HostAndPort> hosts = servers.getServers(); - for ( size_t i = 0 ; i < hosts.size() ; i++ ){ + for ( size_t i = 0 ; i < hosts.size() ; i++ ) { string host = hosts[i].toString(); // host:port - if ( hostSet.find( host ) == hostSet.end() ){ + if ( hostSet.find( host ) == hostSet.end() ) { offendingHost = host; foundAll = false; break; } } } - if ( ! foundAll ){ + if ( ! foundAll ) { ostringstream ss; ss << "host " << offendingHost << " does not belong to replica set as a non-passive member" << setName;; errMsg = ss.str(); @@ -215,15 +218,15 @@ namespace mongo { // shard name defaults to the name of the replica set if ( name->empty() && ! setName.empty() ) - *name = setName; + *name = setName; - // In order to be accepted as a new shard, that mongod must not have any database name that exists already - // in any other shards. If that test passes, the new shard's databases are going to be entered as + // In order to be accepted as a new shard, that mongod must not have any database name that exists already + // in any other shards. If that test passes, the new shard's databases are going to be entered as // non-sharded db's whose primary is the newly added shard. BSONObj resListDB; ok = newShardConn->runCommand( "admin" , BSON( "listDatabases" << 1 ) , resListDB ); - if ( !ok ){ + if ( !ok ) { ostringstream ss; ss << "failed listing " << servers.toString() << "'s databases:" << resListDB; errMsg = ss.str(); @@ -232,20 +235,21 @@ namespace mongo { } BSONObjIterator i( resListDB["databases"].Obj() ); - while ( i.more() ){ + while ( i.more() ) { BSONObj dbEntry = i.next().Obj(); const string& dbName = dbEntry["name"].String(); - if ( _isSpecialLocalDB( dbName ) ){ + if ( _isSpecialLocalDB( dbName ) ) { // 'local', 'admin', and 'config' are system DBs and should be excluded here continue; - } else { + } + else { dbNames.push_back( dbName ); } } newShardConn.done(); } - catch ( DBException& e ){ + catch ( DBException& e ) { ostringstream ss; ss << "couldn't connect to new shard "; ss << e.what(); @@ -254,9 +258,9 @@ namespace mongo { } // check that none of the existing shard candidate's db's exist elsewhere - for ( vector<string>::const_iterator it = dbNames.begin(); it != dbNames.end(); ++it ){ + for ( vector<string>::const_iterator it = dbNames.begin(); it != dbNames.end(); ++it ) { DBConfigPtr config = getDBConfig( *it , false ); - if ( config.get() != NULL ){ + if ( config.get() != NULL ) { ostringstream ss; ss << "can't add shard " << servers.toString() << " because a local database '" << *it; ss << "' exists in another " << config->getPrimary().toString(); @@ -266,26 +270,26 @@ namespace mongo { } // if a name for a shard wasn't provided, pick one. - if ( name->empty() && ! _getNewShardName( name ) ){ + if ( name->empty() && ! _getNewShardName( name ) ) { errMsg = "error generating new shard name"; return false; } - + // build the ConfigDB shard document BSONObjBuilder b; b.append( "_id" , *name ); b.append( "host" , servers.toString() ); - if ( maxSize > 0 ){ + if ( maxSize > 0 ) { b.append( ShardFields::maxSize.name() , maxSize ); } BSONObj shardDoc = b.obj(); { ScopedDbConnection conn( configServer.getPrimary() ); - + // check whether the set of hosts (or single host) is not an already a known shard BSONObj old = conn->findOne( ShardNS::shard , BSON( "host" << servers.toString() ) ); - if ( ! old.isEmpty() ){ + if ( ! old.isEmpty() ) { errMsg = "host already used"; conn.done(); return false; @@ -295,7 +299,7 @@ namespace mongo { conn->insert( ShardNS::shard , shardDoc ); errMsg = conn->getLastError(); - if ( ! errMsg.empty() ){ + if ( ! errMsg.empty() ) { log() << "error adding shard: " << shardDoc << " err: " << errMsg << endl; conn.done(); return false; @@ -307,37 +311,37 @@ namespace mongo { Shard::reloadShardInfo(); // add all databases of the new shard - for ( vector<string>::const_iterator it = dbNames.begin(); it != dbNames.end(); ++it ){ + for ( vector<string>::const_iterator it = dbNames.begin(); it != dbNames.end(); ++it ) { DBConfigPtr config = getDBConfig( *it , true , *name ); - if ( ! config ){ - log() << "adding shard " << servers << " even though could not add database " << *it << endl; + if ( ! config ) { + log() << "adding shard " << servers << " even though could not add database " << *it << endl; } } return true; } - - bool Grid::knowAboutShard( const string& name ) const{ + + bool Grid::knowAboutShard( const string& name ) const { ShardConnection conn( configServer.getPrimary() , "" ); BSONObj shard = conn->findOne( ShardNS::shard , BSON( "host" << name ) ); conn.done(); return ! shard.isEmpty(); } - bool Grid::_getNewShardName( string* name ) const{ + bool Grid::_getNewShardName( string* name ) const { DEV assert( name ); bool ok = false; - int count = 0; + int count = 0; ShardConnection conn( configServer.getPrimary() , "" ); - BSONObj o = conn->findOne( ShardNS::shard , Query( fromjson ( "{_id: /^shard/}" ) ).sort( BSON( "_id" << -1 ) ) ); + BSONObj o = conn->findOne( ShardNS::shard , Query( fromjson ( "{_id: /^shard/}" ) ).sort( BSON( "_id" << -1 ) ) ); if ( ! o.isEmpty() ) { string last = o["_id"].String(); istringstream is( last.substr( 5 ) ); is >> count; count++; - } + } if (count < 9999) { stringstream ss; ss << "shard" << setfill('0') << setw(4) << count; @@ -364,7 +368,7 @@ namespace mongo { return true; } - bool Grid::_balancerStopped( const BSONObj& balancerDoc ) { + bool Grid::_balancerStopped( const BSONObj& balancerDoc ) { // check the 'stopped' marker maker // if present, it is a simple bool BSONElement stoppedElem = balancerDoc["stopped"]; @@ -374,10 +378,10 @@ namespace mongo { return false; } - bool Grid::_inBalancingWindow( const BSONObj& balancerDoc , const boost::posix_time::ptime& now ) { + bool Grid::_inBalancingWindow( const BSONObj& balancerDoc , const boost::posix_time::ptime& now ) { // check the 'activeWindow' marker // if present, it is an interval during the day when the balancer should be active - // { start: "08:00" , stop: "19:30" }, strftime format is %H:%M + // { start: "08:00" , stop: "19:30" }, strftime format is %H:%M BSONElement windowElem = balancerDoc["activeWindow"]; if ( windowElem.eoo() ) { return true; @@ -402,14 +406,15 @@ namespace mongo { log(1) << "cannot parse active window (use hh:mm 24hs format): " << intervalDoc << endl; return true; } - + // allow balancing if during the activeWindow // note that a window may be open during the night if ( stopTime > startTime ) { if ( ( now >= startTime ) && ( now <= stopTime ) ) { return true; } - } else if ( startTime > stopTime ) { + } + else if ( startTime > stopTime ) { if ( ( now >=startTime ) || ( now <= stopTime ) ) { return true; } @@ -420,7 +425,7 @@ namespace mongo { unsigned long long Grid::getNextOpTime() const { ScopedDbConnection conn( configServer.getPrimary() ); - + BSONObj result; massert( 10421 , "getoptime failed" , conn->simpleCommand( "admin" , &result , "getoptime" ) ); conn.done(); @@ -428,7 +433,7 @@ namespace mongo { return result["optime"]._numberLong(); } - bool Grid::_isSpecialLocalDB( const string& dbName ){ + bool Grid::_isSpecialLocalDB( const string& dbName ) { return ( dbName == "local" ) || ( dbName == "admin" ) || ( dbName == "config" ); } @@ -438,7 +443,7 @@ namespace mongo { class BalancingWindowUnitTest : public UnitTest { public: - void run(){ + void run() { // T0 < T1 < now < T2 < T3 and Error const string T0 = "9:00"; const string T1 = "11:00"; @@ -446,17 +451,17 @@ namespace mongo { const string T2 = "17:00"; const string T3 = "21:30"; const string E = "28:35"; - + BSONObj w1 = BSON( "activeWindow" << BSON( "start" << T0 << "stop" << T1 ) ); // closed in the past BSONObj w2 = BSON( "activeWindow" << BSON( "start" << T2 << "stop" << T3 ) ); // not opened until the future BSONObj w3 = BSON( "activeWindow" << BSON( "start" << T1 << "stop" << T2 ) ); // open now BSONObj w4 = BSON( "activeWindow" << BSON( "start" << T3 << "stop" << T2 ) ); // open since last day - + assert( ! Grid::_inBalancingWindow( w1 , now ) ); assert( ! Grid::_inBalancingWindow( w2 , now ) ); assert( Grid::_inBalancingWindow( w3 , now ) ); assert( Grid::_inBalancingWindow( w4 , now ) ); - + // bad input should not stop the balancer BSONObj w5; // empty window @@ -464,7 +469,7 @@ namespace mongo { BSONObj w7 = BSON( "activeWindow" << BSON( "stop" << 1 ) ); // missing start BSONObj w8 = BSON( "wrongMarker" << 1 << "start" << 1 << "stop" << 1 ); // active window marker missing BSONObj w9 = BSON( "activeWindow" << BSON( "start" << T3 << "stop" << E ) ); // garbage in window - + assert( Grid::_inBalancingWindow( w5 , now ) ); assert( Grid::_inBalancingWindow( w6 , now ) ); assert( Grid::_inBalancingWindow( w7 , now ) ); @@ -475,4 +480,4 @@ namespace mongo { } } BalancingWindowObjTest; -} +} |