// shard.cpp /** * Copyright (C) 2008 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "pch.h" #include "shard.h" #include "config.h" #include "request.h" #include namespace mongo { class StaticShardInfo { public: StaticShardInfo() : _mutex("StaticShardInfo") { } void reload(){ list all; { ScopedDbConnection conn( configServer.getPrimary() ); auto_ptr c = conn->query( ShardNS::shard , Query() ); while ( c->more() ){ all.push_back( c->next().getOwned() ); } conn.done(); } scoped_lock lk( _mutex ); for ( list::iterator i=all.begin(); i!=all.end(); ++i ){ BSONObj o = *i; string name = o["_id"].String(); string host = o["host"].String(); Shard s( name , host ); _lookup[name] = s; _lookup[host] = s; } } const Shard& find( const string& ident ){ { scoped_lock lk( _mutex ); map::iterator i = _lookup.find( ident ); if ( i != _lookup.end() ) return i->second; } // not in our maps, re-load all reload(); scoped_lock lk( _mutex ); map::iterator i = _lookup.find( ident ); uassert( 13129 , (string)"can't find shard for: " + ident , i != _lookup.end() ); return i->second; } void set( const string& name , const string& addr , bool setName = true , bool setAddr = true ){ Shard s(name,addr); scoped_lock lk( _mutex ); if ( setName ) _lookup[name] = s; if ( setAddr ) _lookup[addr] = s; } void getAllShards( vector& all ){ scoped_lock lk( _mutex ); std::set seen; for ( map::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 ); } } private: map _lookup; mongo::mutex _mutex; } staticShardInfo; void Shard::setAddress( const string& addr , bool authoritative ){ assert( _name.size() ); _addr = addr; if ( authoritative ) staticShardInfo.set( _name , _addr , true , false ); } void Shard::reset( const string& ident ){ const Shard& s = staticShardInfo.find( ident ); uassert( 13128 , (string)"can't find shard for: " + ident , s.ok() ); _name = s._name; _addr = s._addr; } void Shard::getAllShards( vector& all ){ staticShardInfo.getAllShards( all ); } BSONObj Shard::runCommand( const string& db , const BSONObj& cmd ) const { ScopedDbConnection conn( this ); BSONObj res; bool ok = conn->runCommand( db , cmd , res ); if ( ! ok ){ stringstream ss; ss << "runCommand (" << cmd << ") on shard (" << _name << ") failed : " << res; throw UserException( 13136 , ss.str() ); } res = res.getOwned(); conn.done(); return res; } ShardStatus Shard::getStatus() const { return ShardStatus( *this , runCommand( "admin" , BSON( "serverStatus" << 1 ) ) ); } void Shard::reloadShardInfo(){ staticShardInfo.reload(); } Shard Shard::pick(){ vector all; staticShardInfo.getAllShards( all ); if ( all.size() == 0 ){ staticShardInfo.reload(); staticShardInfo.getAllShards( all ); if ( all.size() == 0 ) return EMPTY; } ShardStatus best = all[0].getStatus(); for ( size_t i=1; i