Shard * Shard::split( const BSONObj& m ){ uassert( "can't split as shard that doesn't have a manager" , _manager ); log(1) << " before split on: " << m << "\n" << "\t self : " << toString() << endl; uassert( "locking namespace on server failed" , lockNamespaceOnServer( getServer() , _ns ) ); Shard * s = new Shard( _manager ); s->_ns = _ns; s->_server = _server; s->_min = m.getOwned(); s->_max = _max; s->_markModified(); _markModified(); _manager->_shards.push_back( s ); _max = m.getOwned(); log(1) << " after split:\n" << "\t left : " << toString() << "\n" << "\t right: "<< s->toString() << endl; _manager->save(); return s; }
bool CmdAuthenticate::getUserObj(const string& dbname, const string& user, BSONObj& userObj, string& pwd) { if (user == internalSecurity.user) { uassert(15890, "key file must be used to log in with internal user", !cmdLine.keyFile.empty()); pwd = internalSecurity.pwd; } else { string systemUsers = dbname + ".system.users"; DBConfigPtr config = grid.getDBConfig( systemUsers ); Shard s = config->getShard( systemUsers ); static BSONObj userPattern = BSON("user" << 1); scoped_ptr<ScopedDbConnection> conn( ScopedDbConnection::getInternalScopedDbConnection( s.getConnString(), 30.0 ) ); OCCASIONALLY conn->get()->ensureIndex(systemUsers, userPattern, false, "user_1"); { BSONObjBuilder b; b << "user" << user; BSONObj query = b.done(); userObj = conn->get()->findOne(systemUsers, query, 0, QueryOption_SlaveOk); if( userObj.isEmpty() ) { log() << "auth: couldn't find user " << user << ", " << systemUsers << endl; conn->done(); // return to pool return false; } } pwd = userObj.getStringField("pwd"); conn->done(); // return to pool } return true; }
Status DBClientShardResolver::chooseWriteHost( const string& shardName, ConnectionString* shardHost ) const { // Declare up here for parsing later string errMsg; // Special-case for config if (shardName == "config") { *shardHost = ConnectionString::parse( configServer.modelServer(), errMsg ); dassert( errMsg == "" ); return Status::OK(); } // // First get the information about the shard from the shard cache // // Internally uses our shard cache, does no reload Shard shard = Shard::findIfExists( shardName ); if ( shard.getName() == "" ) { return Status( ErrorCodes::ShardNotFound, string("unknown shard name ") + shardName ); } return findMaster(shard.getConnString().toString(), shardHost); }
ShardManager::ShardManager( DBConfig * config , string ns , ShardKeyPattern pattern ) : _config( config ) , _ns( ns ) , _key( pattern ){ Shard temp(0); ScopedDbConnection conn( temp.modelServer() ); auto_ptr<DBClientCursor> cursor = conn->query( temp.getNS() , BSON( "ns" << ns ) ); while ( cursor->more() ){ Shard * s = new Shard( this ); BSONObj d = cursor->next(); s->unserialize( d ); _shards.push_back( s ); s->_id = d["_id"].wrap().getOwned(); } conn.done(); if ( _shards.size() == 0 ){ Shard * s = new Shard( this ); s->_ns = ns; s->_min = _key.globalMin(); s->_max = _key.globalMax(); s->_server = config->getPrimary(); s->_markModified(); _shards.push_back( s ); log() << "no shards for:" << ns << " so creating first: " << s->toString() << endl; } _sequenceNumber = ++NextSequenceNumber; }
bool Shard::moveIfShould( Shard * newShard ){ Shard * toMove = 0; if ( newShard->countObjects() <= 1 ){ toMove = newShard; } else if ( this->countObjects() <= 1 ){ toMove = this; } else { log(1) << "don't know how to decide if i should move inner shard" << endl; } if ( ! toMove ) return false; string newLocation = grid.pickServerForNewDB(); if ( newLocation == getServer() ){ // if this is the best server, then we shouldn't do anything! log(1) << "not moving shard: " << toString() << " b/c would move to same place " << newLocation << " -> " << getServer() << endl; return 0; } log() << "moving shard (auto): " << toMove->toString() << " to: " << newLocation << " #objcets: " << toMove->countObjects() << endl; string errmsg; massert( (string)"moveAndCommit failed: " + errmsg , toMove->moveAndCommit( newLocation , errmsg ) ); return true; }
bool Balancer::_checkOIDs() { vector<Shard> all; Shard::getAllShards( all ); map<int,Shard> oids; for ( vector<Shard>::iterator i=all.begin(); i!=all.end(); ++i ) { Shard s = *i; BSONObj f = s.runCommand( "admin" , "features" , true ); if ( f["oidMachine"].isNumber() ) { int x = f["oidMachine"].numberInt(); if ( oids.count(x) == 0 ) { oids[x] = s; } else { log() << "error: 2 machines have " << x << " as oid machine piece " << s.toString() << " and " << oids[x].toString() << endl; s.runCommand( "admin" , BSON( "features" << 1 << "oidReset" << 1 ) , true ); oids[x].runCommand( "admin" , BSON( "features" << 1 << "oidReset" << 1 ) , true ); return false; } } else { log() << "warning: oidMachine not set on: " << s.toString() << endl; } } return true; }
void _delete( Request& r , DbMessage& d, ShardManager* manager ){ int flags = d.pullInt(); bool justOne = flags & 1; uassert( "bad delete message" , d.moreJSObjs() ); BSONObj pattern = d.nextJsObj(); if ( manager->hasShardKey( pattern ) ){ Shard& s = manager->findShard( pattern ); doWrite( dbDelete , r , s.getServer() ); return; } if ( ! justOne && ! pattern.hasField( "_id" ) ) throw UserException( "can only delete with a non-shard key pattern if can delete as many as we find" ); vector<Shard*> shards; manager->getShardsForQuery( shards , pattern ); set<string> seen; for ( vector<Shard*>::iterator i=shards.begin(); i!=shards.end(); i++){ Shard * s = *i; if ( seen.count( s->getServer() ) ) continue; seen.insert( s->getServer() ); doWrite( dbDelete , r , s->getServer() ); } }
bool setShardVersion(DBClientBase& conn, const string& ns, const string& configServerPrimary, ChunkVersion version, ChunkManager* manager, bool authoritative, BSONObj& result) { BSONObjBuilder cmdBuilder; cmdBuilder.append("setShardVersion", ns); cmdBuilder.append("configdb", configServerPrimary); Shard s = Shard::make(conn.getServerAddress()); cmdBuilder.append("shard", s.getName()); cmdBuilder.append("shardHost", s.getConnString()); if (ns.size() > 0) { version.addToBSON(cmdBuilder); } else { cmdBuilder.append("init", true); } if (authoritative) { cmdBuilder.appendBool("authoritative", 1); } BSONObj cmd = cmdBuilder.obj(); LOG(1) << " setShardVersion " << s.getName() << " " << conn.getServerAddress() << " " << ns << " " << cmd << (manager ? string(str::stream() << " " << manager->getSequenceNumber()) : ""); return conn.runCommand("admin", cmd, result, 0); }
Shard& ShardManager::findShard( const BSONObj & obj ){ for ( vector<Shard*>::iterator i=_shards.begin(); i != _shards.end(); i++ ){ Shard * s = *i; if ( s->contains( obj ) ) return *s; } throw UserException( "couldn't find a shard which should be impossible" ); }
bool Shard::isIdentical(Shard *other) { if (_type != other->_type) return false; if (count() != other->count()) return false; for (Shard *mine = _first, *yours = other->_first; mine; mine = mine->_next, yours = yours->_next) if (!mine->isIdentical(yours)) return false; return true; }
Shard* ShardManager::findShardOnServer( const string& server ) const { for ( vector<Shard*>::const_iterator i=_shards.begin(); i!=_shards.end(); i++ ){ Shard* s = *i; if ( s->getServer() == server ) return s; } return 0; }
Token *Command::arg(int idx) { for(Shard *it = first(); it; it = it->next()) { if(idx--) continue; it = it->first(); if(!it || it->type() != BLOCK) break; return (Token*) it->first(); } return 0; }
void ShardManager::ensureIndex(){ set<string> seen; for ( vector<Shard*>::const_iterator i=_shards.begin(); i!=_shards.end(); i++ ){ Shard* s = *i; if ( seen.count( s->getServer() ) ) continue; seen.insert( s->getServer() ); s->ensureIndex(); } }
// Deprecated, will move to the strategy itself Shard Request::primaryShard() const { assert( _didInit ); if ( _chunkManager ) { if ( _chunkManager->numChunks() > 1 ) throw UserException( 8060 , "can't call primaryShard on a sharded collection" ); return _chunkManager->findChunk( _chunkManager->getShardKey().globalMin() )->getShard(); } Shard s = _config->getShard( getns() ); uassert( 10194 , "can't call primaryShard on a sharded collection!" , s.ok() ); return s; }
void remove( const string& name ) { scoped_lock lk( _mutex ); for ( map<string,Shard>::iterator i = _lookup.begin(); i!=_lookup.end(); ) { Shard s = i->second; if ( s.getName() == name ) { _lookup.erase(i++); } else { ++i; } } }
void getAllShards( vector<Shard>& all ) { scoped_lock lk( _mutex ); std::set<string> seen; for ( map<string,Shard>::iterator i = _lookup.begin(); i!=_lookup.end(); ++i ) { Shard s = i->second; if ( s.getName() == "config" ) continue; if ( seen.count( s.getName() ) ) continue; seen.insert( s.getName() ); all.push_back( s ); } }
Status Strategy::commandOpUnsharded(const std::string& db, const BSONObj& command, int options, const std::string& versionedNS, CommandResult* cmdResult) { // Note that this implementation will not handle targeting retries and fails when the // sharding metadata is too stale auto status = grid.catalogCache()->getDatabase(db); if (!status.isOK()) { mongoutils::str::stream ss; ss << "Passthrough command failed: " << command.toString() << " on ns " << versionedNS << ". Caused by " << causedBy(status.getStatus()); return Status(ErrorCodes::IllegalOperation, ss); } shared_ptr<DBConfig> conf = status.getValue(); if (conf->isSharded(versionedNS)) { mongoutils::str::stream ss; ss << "Passthrough command failed: " << command.toString() << " on ns " << versionedNS << ". Cannot run on sharded namespace."; return Status(ErrorCodes::IllegalOperation, ss); } Shard primaryShard = conf->getPrimary(); BSONObj shardResult; try { ShardConnection conn(primaryShard.getConnString(), ""); // TODO: this can throw a stale config when mongos is not up-to-date -- fix. if (!conn->runCommand(db, command, shardResult, options)) { conn.done(); return Status(ErrorCodes::OperationFailed, str::stream() << "Passthrough command failed: " << command << " on ns " << versionedNS << "; result: " << shardResult); } conn.done(); } catch (const DBException& ex) { return ex.toStatus(); } // Fill out the command result. cmdResult->shardTarget = primaryShard; cmdResult->result = shardResult; cmdResult->target = primaryShard.getConnString(); return Status::OK(); }
Status ChunkManagerTargeter::targetShardKey(const BSONObj& doc, ShardEndpoint** endpoint) const { invariant(NULL != _manager); dassert(_manager->hasShardKey(doc)); ChunkPtr chunk = _manager->findChunkForDoc(doc); Shard shard = chunk->getShard(); *endpoint = new ShardEndpoint(shard.getName(), _manager->getVersion(StringData(shard.getName()))); return Status::OK(); }
bool Command::hasArg(const String& str) { for(Shard *it = first(); it; it = it->next()) { Block *block = (Block*) it->first(); if(!block || block->type() != BLOCK) continue; for(Shard *arg = block->first(); arg; arg = arg->next()) { // Blocks have only Tokens as children! if(((Token*)arg)->token() == str) return true; } } return false; }
void ShardManager::save(){ ServerShardVersion a = getVersion(); for ( vector<Shard*>::const_iterator i=_shards.begin(); i!=_shards.end(); i++ ){ Shard* s = *i; if ( ! s->_modified ) continue; s->save( true ); _sequenceNumber = ++NextSequenceNumber; } massert( "how did version get smalled" , getVersion() >= a ); ensureIndex(); // TODO: this is too aggressive - but not really sooo bad }
ShardStatus::ShardStatus( const Shard& shard , const BSONObj& obj , const BSONObj& dblistobj ) : _shard( shard ), _isDraining(shard.isDraining()) { _dataSize = dblistobj.getFieldDotted("totalUncompressedSize").numberLong(); _hasOpsQueued = obj["writeBacksQueued"].Bool(); _writeLock = 0; // TODO _mongoVersion = obj["version"].String(); }
Shard Shard::pick( const Shard& current ) { vector<Shard> all; staticShardInfo.getAllShards( all ); if ( all.size() == 0 ) { staticShardInfo.reload(); staticShardInfo.getAllShards( all ); if ( all.size() == 0 ) return EMPTY; } // if current shard was provided, pick a different shard only if it is a better choice ShardStatus best = all[0].getStatus(); if ( current != EMPTY ) { best = current.getStatus(); } for ( size_t i=0; i<all.size(); i++ ) { ShardStatus t = all[i].getStatus(); if ( t < best ) best = t; } LOG(1) << "best shard for new allocation is " << best << endl; return best.shard(); }
Macro::Macro(const String& n, Shard *macroShard, const String& args) : Linkable() { _name = n; _argTypes = args; if (macroShard) { // Steal macroShard's children. Shard *next; for (Shard *it = macroShard->first(); it; it = next) { next = it->next(); _shard.add(macroShard->remove(it)); } } }
ServerShardVersion ShardManager::getVersion( const string& server ) const{ // TODO: cache or something? ServerShardVersion max = 0; for ( vector<Shard*>::const_iterator i=_shards.begin(); i!=_shards.end(); i++ ){ Shard* s = *i; if ( s->getServer() != server ) continue; if ( s->_lastmod > max ) max = s->_lastmod; } return max; }
ShardConnection::ShardConnection(const Shard& s, const string& ns, ChunkManagerPtr manager) : _addr(s.getConnString()), _ns(ns), _manager( manager ) { _init(); }
void set( const string& name , const Shard& s , bool setName = true , bool setAddr = true ) { scoped_lock lk( _mutex ); ShardPtr ss( new Shard( s ) ); if ( setName ) _lookup[name] = ss; if ( setAddr ) _installHost( s.getConnString() , ss ); }
bool Chunk::moveAndCommit(const Shard& to, long long chunkSize /* bytes */, const WriteConcernOptions* writeConcern, bool waitForDelete, int maxTimeMS, BSONObj& res) const { uassert( 10167 , "can't move shard to its current location!" , getShard() != to ); log() << "moving chunk ns: " << _manager->getns() << " moving ( " << toString() << ") " << _shard.toString() << " -> " << to.toString(); Shard from = _shard; ScopedDbConnection fromconn(from.getConnString()); BSONObjBuilder builder; builder.append("moveChunk", _manager->getns()); builder.append("from", from.getAddress().toString()); builder.append("to", to.getAddress().toString()); // NEEDED FOR 2.0 COMPATIBILITY builder.append("fromShard", from.getName()); builder.append("toShard", to.getName()); /////////////////////////////// builder.append("min", _min); builder.append("max", _max); builder.append("maxChunkSizeBytes", chunkSize); builder.append("shardId", genID()); builder.append("configdb", configServer.modelServer()); // For legacy secondary throttle setting. bool secondaryThrottle = true; if (writeConcern && writeConcern->wNumNodes <= 1 && writeConcern->wMode.empty()) { secondaryThrottle = false; } builder.append("secondaryThrottle", secondaryThrottle); if (secondaryThrottle && writeConcern) { builder.append("writeConcern", writeConcern->toBSON()); } builder.append("waitForDelete", waitForDelete); builder.append(LiteParsedQuery::cmdOptionMaxTimeMS, maxTimeMS); builder.append("epoch", _manager->getVersion().epoch()); bool worked = fromconn->runCommand("admin", builder.done(), res); fromconn.done(); LOG( worked ? 1 : 0 ) << "moveChunk result: " << res; // if succeeded, needs to reload to pick up the new location // if failed, mongos may be stale // reload is excessive here as the failure could be simply because collection metadata is taken _manager->reload(); return worked; }
Slice::Slice(Shard& shard) : m_shard(shard), m_capacity(shard.GetSliceCapacity()), m_refCount(1), m_buffer(shard.AllocateSliceBuffer()), m_unallocatedCount(shard.GetSliceCapacity()), m_commitPendingCount(0), m_expiredCount(0) { Initialize(); // Perform start up initialization of the DocTable and RowTables after // the buffer has been allocated. GetDocTable().Initialize(m_buffer); for (Rank r = 0; r <= c_maxRankValue; ++r) { GetRowTable(r).Initialize(m_buffer, m_shard.GetTermTable()); } }
bool setShardVersion( DBClientBase & conn , const string& ns , ShardChunkVersion version , bool authoritative , BSONObj& result ){ BSONObjBuilder cmdBuilder; cmdBuilder.append( "setShardVersion" , ns.c_str() ); cmdBuilder.append( "configdb" , configServer.modelServer() ); cmdBuilder.appendTimestamp( "version" , version ); cmdBuilder.appendOID( "serverID" , &serverID ); if ( authoritative ) cmdBuilder.appendBool( "authoritative" , 1 ); Shard s = Shard::make( conn.getServerAddress() ); cmdBuilder.append( "shard" , s.getName() ); cmdBuilder.append( "shardHost" , s.getConnString() ); BSONObj cmd = cmdBuilder.obj(); log(1) << " setShardVersion " << s.getName() << " " << conn.getServerAddress() << " " << ns << " " << cmd << " " << &conn << endl; return conn.runCommand( "admin" , cmd , result ); }
/** * An exception will be thrown if there is an error. */ void RuleSet::generateRule(Command *command) { Rule *rule; Shard *it; GemTest *terms; // Create the rule object. if(command->isName("format")) { rule = new FormatRule(((Block*)command->last()->first())->collect()); } else { rule = new LengthRule; } terms = &rule->terms(); // Compile the terms (command -> shards -> blocks -> tokens). for(it = command->first(); it && it != command->last(); it = it->next()) { if(!it->first()) continue; terms->addBefore(new GemTest((Token*)it->first()->first())); } if(command->isName("format")) { // There must not be format rules with matching terms. removeMatching(*terms, Rule::FORMAT); add(rule); } else { add(rule); Length *len = &((LengthRule*)rule)->length(); // Set the lengths that were given. // Get last argument -> block -> first token. len->init((Token*)command->last()->first()->first()); // Was this all for naught? if(len->isClear()) delete remove(rule); } }