0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
mongodb/s/shard.cpp

261 lines
8.2 KiB
C++
Raw Normal View History

// 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 <http://www.gnu.org/licenses/>.
*/
2010-04-27 21:27:52 +02:00
#include "pch.h"
#include "shard.h"
#include "config.h"
#include "request.h"
#include <set>
namespace mongo {
2011-01-04 06:40:41 +01:00
class StaticShardInfo {
public:
2010-05-26 06:46:49 +02:00
StaticShardInfo() : _mutex("StaticShardInfo") { }
2011-01-04 06:40:41 +01:00
void reload() {
2010-05-03 17:18:27 +02:00
list<BSONObj> all;
{
2010-05-20 19:36:29 +02:00
ScopedDbConnection conn( configServer.getPrimary() );
auto_ptr<DBClientCursor> c = conn->query( ShardNS::shard , Query() );
2010-08-02 20:44:53 +02:00
assert( c.get() );
2011-01-04 06:40:41 +01:00
while ( c->more() ) {
all.push_back( c->next().getOwned() );
}
conn.done();
}
2011-01-04 06:40:41 +01:00
scoped_lock lk( _mutex );
2011-01-04 06:40:41 +01:00
// We use the _lookup table for all shards and for the primary config DB. The config DB info,
// however, does not come from the ShardNS::shard. So when cleaning the _lookup table we leave
// the config state intact. The rationale is that this way we could drop shards that
// were removed without reinitializing the config DB information.
map<string,Shard>::iterator i = _lookup.find( "config" );
2011-01-04 06:40:41 +01:00
if ( i != _lookup.end() ) {
Shard config = i->second;
_lookup.clear();
_lookup[ "config" ] = config;
2011-01-04 06:40:41 +01:00
}
else {
_lookup.clear();
}
2011-01-04 06:40:41 +01:00
for ( list<BSONObj>::iterator i=all.begin(); i!=all.end(); ++i ) {
BSONObj o = *i;
string name = o["_id"].String();
string host = o["host"].String();
long long maxSize = 0;
BSONElement maxSizeElem = o[ ShardFields::maxSize.name() ];
2011-01-04 06:40:41 +01:00
if ( ! maxSizeElem.eoo() ) {
maxSize = maxSizeElem.numberLong();
}
bool isDraining = false;
BSONElement isDrainingElem = o[ ShardFields::draining.name() ];
2011-01-04 06:40:41 +01:00
if ( ! isDrainingElem.eoo() ) {
isDraining = isDrainingElem.Bool();
}
Shard s( name , host , maxSize , isDraining );
_lookup[name] = s;
_lookup[host] = s;
// add rs name to lookup (if it exists)
size_t pos;
if ((pos = host.find('/', 0)) != string::npos) {
_lookup[host.substr(0, pos)] = s;
}
}
2010-05-03 17:18:27 +02:00
}
2011-01-04 06:40:41 +01:00
bool isMember( const string& addr ) {
scoped_lock lk( _mutex );
map<string,Shard>::iterator i = _lookup.find( addr );
return i != _lookup.end();
}
2011-01-04 06:40:41 +01:00
const Shard& find( const string& ident ) {
2010-12-21 05:02:56 +01:00
string mykey = ident;
2010-05-03 17:18:27 +02:00
{
2010-12-21 05:02:56 +01:00
// if its a replica set, just use set name
size_t pos = mykey.find( '/' );
if ( pos != string::npos )
mykey = mykey.substr(0,pos);
}
2010-12-21 05:02:56 +01:00
{
scoped_lock lk( _mutex );
map<string,Shard>::iterator i = _lookup.find( mykey );
2010-05-03 17:18:27 +02:00
if ( i != _lookup.end() )
return i->second;
}
2011-01-04 06:40:41 +01:00
2010-05-03 17:18:27 +02:00
// not in our maps, re-load all
reload();
scoped_lock lk( _mutex );
2010-12-21 05:02:56 +01:00
map<string,Shard>::iterator i = _lookup.find( mykey );
uassert( 13129 , (string)"can't find shard for: " + mykey , i != _lookup.end() );
2011-01-04 06:40:41 +01:00
return i->second;
}
2011-01-04 06:40:41 +01:00
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;
}
2011-01-04 06:40:41 +01:00
void remove( const string& name ) {
scoped_lock lk( _mutex );
2011-01-04 06:40:41 +01:00
for ( map<string,Shard>::iterator i = _lookup.begin(); i!=_lookup.end(); ) {
Shard s = i->second;
2011-01-04 06:40:41 +01:00
if ( s.getName() == name ) {
_lookup.erase(i++);
2011-01-04 06:40:41 +01:00
}
else {
++i;
}
}
}
2011-01-04 06:40:41 +01:00
void getAllShards( vector<Shard>& all ) {
scoped_lock lk( _mutex );
std::set<string> seen;
2011-01-04 06:40:41 +01:00
for ( map<string,Shard>::iterator i = _lookup.begin(); i!=_lookup.end(); ++i ) {
Shard s = i->second;
2010-04-29 02:56:40 +02:00
if ( s.getName() == "config" )
continue;
if ( seen.count( s.getName() ) )
continue;
seen.insert( s.getName() );
all.push_back( s );
}
}
private:
map<string,Shard> _lookup;
2011-01-04 06:40:41 +01:00
mongo::mutex _mutex;
} staticShardInfo;
2011-01-04 06:40:41 +01:00
void Shard::setAddress( const string& addr , bool authoritative ) {
assert( _name.size() );
_addr = addr;
if ( authoritative )
staticShardInfo.set( _name , _addr , true , false );
}
2011-01-04 06:40:41 +01:00
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;
_maxSize = s._maxSize;
_isDraining = s._isDraining;
}
2011-01-04 06:40:41 +01:00
void Shard::getAllShards( vector<Shard>& all ) {
staticShardInfo.getAllShards( all );
}
2011-01-04 06:40:41 +01:00
bool Shard::isAShard( const string& ident ) {
return staticShardInfo.isMember( ident );
}
2011-01-04 06:40:41 +01:00
void Shard::printShardInfo( ostream& out ) {
vector<Shard> all;
getAllShards( all );
for ( unsigned i=0; i<all.size(); i++ )
out << all[i].toString() << "\n";
out.flush();
}
2011-01-04 06:40:41 +01:00
BSONObj Shard::runCommand( const string& db , const BSONObj& cmd ) const {
2010-05-20 19:36:29 +02:00
ScopedDbConnection conn( this );
BSONObj res;
bool ok = conn->runCommand( db , cmd , res );
2011-01-04 06:40:41 +01:00
if ( ! ok ) {
stringstream ss;
ss << "runCommand (" << cmd << ") on shard (" << _name << ") failed : " << res;
throw UserException( 13136 , ss.str() );
}
res = res.getOwned();
conn.done();
return res;
}
2011-01-04 06:40:41 +01:00
ShardStatus Shard::getStatus() const {
return ShardStatus( *this , runCommand( "admin" , BSON( "serverStatus" << 1 ) ) );
}
2011-01-04 06:40:41 +01:00
void Shard::reloadShardInfo() {
2010-05-03 17:18:27 +02:00
staticShardInfo.reload();
}
2011-01-04 06:40:41 +01:00
bool Shard::isMember( const string& addr ) {
return staticShardInfo.isMember( addr );
}
2011-01-04 06:40:41 +01:00
void Shard::removeShard( const string& name ) {
staticShardInfo.remove( name );
}
2011-01-04 06:40:41 +01:00
Shard Shard::pick( const Shard& current ) {
2010-05-03 17:18:27 +02:00
vector<Shard> all;
staticShardInfo.getAllShards( all );
2011-01-04 06:40:41 +01:00
if ( all.size() == 0 ) {
2010-05-03 17:18:27 +02:00
staticShardInfo.reload();
staticShardInfo.getAllShards( all );
if ( all.size() == 0 )
return EMPTY;
}
2011-01-04 06:40:41 +01:00
// if current shard was provided, pick a different shard only if it is a better choice
ShardStatus best = all[0].getStatus();
2011-01-04 06:40:41 +01:00
if ( current != EMPTY ) {
best = current.getStatus();
}
2011-01-04 06:40:41 +01:00
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();
}
ShardStatus::ShardStatus( const Shard& shard , const BSONObj& obj )
: _shard( shard ) {
_mapped = obj.getFieldDotted( "mem.mapped" ).numberLong();
_hasOpsQueued = obj["writeBacksQueued"].Bool();
_writeLock = 0; // TODO
2010-05-03 17:18:27 +02:00
}
}