diff options
Diffstat (limited to 's/commands_admin.cpp')
-rw-r--r-- | s/commands_admin.cpp | 568 |
1 files changed, 281 insertions, 287 deletions
diff --git a/s/commands_admin.cpp b/s/commands_admin.cpp index 551b8a9..532161a 100644 --- a/s/commands_admin.cpp +++ b/s/commands_admin.cpp @@ -29,6 +29,7 @@ #include "../util/message.h" #include "../util/processinfo.h" #include "../util/stringutils.h" +#include "../util/version.h" #include "../client/connpool.h" @@ -41,6 +42,8 @@ #include "grid.h" #include "strategy.h" #include "stats.h" +#include "writeback_listener.h" +#include "client.h" namespace mongo { @@ -48,7 +51,7 @@ namespace mongo { class GridAdminCmd : public Command { public: - GridAdminCmd( const char * n ) : Command( n , false, tolowerString(n).c_str() ){ + GridAdminCmd( const char * n ) : Command( n , false, tolowerString(n).c_str() ) { } virtual bool slaveOk() const { return true; @@ -58,7 +61,7 @@ namespace mongo { } // all grid commands are designed not to lock - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } }; // --------------- misc commands ---------------------- @@ -69,31 +72,34 @@ namespace mongo { virtual void help( stringstream& help ) const { help << " shows status/reachability of servers in the cluster"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { result.append("configserver", configServer.getPrimary().getConnString() ); result.append("isdbgrid", 1); return true; } } netstat; - + class ServerStatusCmd : public Command { public: - ServerStatusCmd() : Command( "serverStatus" , true ){ + ServerStatusCmd() : Command( "serverStatus" , true ) { _started = time(0); } - + virtual bool slaveOk() const { return true; } - virtual LockType locktype() const { return NONE; } - + virtual LockType locktype() const { return NONE; } + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + result.append( "host" , prettyHostName() ); + result.append("version", versionString); + result.append("process","mongos"); result.append("uptime",(double) (time(0)-_started)); result.appendDate( "localTime" , jsTime() ); { BSONObjBuilder t( result.subobjStart( "mem" ) ); - + ProcessInfo p; - if ( p.supported() ){ + if ( p.supported() ) { t.appendNumber( "resident" , p.getResidentSize() ); t.appendNumber( "virtual" , p.getVirtualMemorySize() ); t.appendBool( "supported" , true ); @@ -102,7 +108,7 @@ namespace mongo { result.append( "note" , "not all mem info support on this platform" ); t.appendBool( "supported" , false ); } - + t.done(); } @@ -112,7 +118,7 @@ namespace mongo { bb.append( "available" , connTicketHolder.available() ); bb.done(); } - + { BSONObjBuilder bb( result.subobjStart( "extra_info" ) ); bb.append("note", "fields vary by platform"); @@ -120,7 +126,7 @@ namespace mongo { p.getExtraInfo(bb); bb.done(); } - + result.append( "opcounters" , globalOpCounters.getObj() ); { BSONObjBuilder bb( result.subobjStart( "ops" ) ); @@ -130,7 +136,7 @@ namespace mongo { } result.append( "shardCursorType" , shardedCursorTypes.getObj() ); - + { BSONObjBuilder asserts( result.subobjStart( "asserts" ) ); asserts.append( "regular" , assertionCount.regular ); @@ -141,6 +147,13 @@ namespace mongo { asserts.done(); } + { + BSONObjBuilder bb( result.subobjStart( "network" ) ); + networkCounter.append( bb ); + bb.done(); + } + + return 1; } @@ -149,34 +162,34 @@ namespace mongo { class FsyncCommand : public GridAdminCmd { public: - FsyncCommand() : GridAdminCmd( "fsync" ){} - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ - if ( cmdObj["lock"].trueValue() ){ + FsyncCommand() : GridAdminCmd( "fsync" ) {} + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { + if ( cmdObj["lock"].trueValue() ) { errmsg = "can't do lock through mongos"; return false; } - + BSONObjBuilder sub; bool ok = true; int numFiles = 0; - + vector<Shard> shards; Shard::getAllShards( shards ); - for ( vector<Shard>::iterator i=shards.begin(); i!=shards.end(); i++ ){ + for ( vector<Shard>::iterator i=shards.begin(); i!=shards.end(); i++ ) { Shard s = *i; BSONObj x = s.runCommand( "admin" , "fsync" ); sub.append( s.getName() , x ); - if ( ! x["ok"].trueValue() ){ + if ( ! x["ok"].trueValue() ) { ok = false; errmsg = x["errmsg"].String(); } - + numFiles += x["numFiles"].numberInt(); } - + result.append( "numFiles" , numFiles ); result.append( "all" , sub.obj() ); return ok; @@ -192,43 +205,43 @@ namespace mongo { help << " example: { moveprimary : 'foo' , to : 'localhost:9999' }"; // TODO: locking? } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { string dbname = cmdObj.firstElement().valuestrsafe(); - if ( dbname.size() == 0 ){ + if ( dbname.size() == 0 ) { errmsg = "no db"; return false; } - if ( dbname == "config" ){ + if ( dbname == "config" ) { errmsg = "can't move config db"; return false; } DBConfigPtr config = grid.getDBConfig( dbname , false ); - if ( ! config ){ + if ( ! config ) { errmsg = "can't find db!"; return false; } string to = cmdObj["to"].valuestrsafe(); - if ( ! to.size() ){ + if ( ! to.size() ) { errmsg = "you have to specify where you want to move it"; return false; } Shard s = Shard::make( to ); - if ( config->getPrimary() == s.getConnString() ){ + if ( config->getPrimary() == s.getConnString() ) { errmsg = "thats already the primary"; return false; } - if ( ! grid.knowAboutShard( s.getConnString() ) ){ + if ( ! grid.knowAboutShard( s.getConnString() ) ) { errmsg = "that server isn't known to me"; return false; } - - log() << "movePrimary: moving " << dbname << " primary from: " << config->getPrimary().toString() + + log() << "movePrimary: moving " << dbname << " primary from: " << config->getPrimary().toString() << " to: " << s.toString() << endl; // TODO LOCKING: this is not safe with multiple mongos @@ -241,7 +254,7 @@ namespace mongo { bool worked = toconn->runCommand( dbname.c_str() , BSON( "clone" << config->getPrimary().getConnString() ) , cloneRes ); toconn.done(); - if ( ! worked ){ + if ( ! worked ) { log() << "clone failed" << cloneRes << endl; errmsg = "clone failed"; return false; @@ -264,25 +277,25 @@ namespace mongo { class EnableShardingCmd : public GridAdminCmd { public: - EnableShardingCmd() : GridAdminCmd( "enableSharding" ){} + EnableShardingCmd() : GridAdminCmd( "enableSharding" ) {} virtual void help( stringstream& help ) const { help - << "Enable sharding for a db. (Use 'shardcollection' command afterwards.)\n" - << " { enablesharding : \"<dbname>\" }\n"; + << "Enable sharding for a db. (Use 'shardcollection' command afterwards.)\n" + << " { enablesharding : \"<dbname>\" }\n"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { string dbname = cmdObj.firstElement().valuestrsafe(); - if ( dbname.size() == 0 ){ + if ( dbname.size() == 0 ) { errmsg = "no db"; return false; } DBConfigPtr config = grid.getDBConfig( dbname ); - if ( config->isShardingEnabled() ){ + if ( config->isShardingEnabled() ) { errmsg = "already enabled"; return false; } - + log() << "enabling sharding on: " << dbname << endl; config->enableSharding(); @@ -295,46 +308,46 @@ namespace mongo { class ShardCollectionCmd : public GridAdminCmd { public: - ShardCollectionCmd() : GridAdminCmd( "shardCollection" ){} + ShardCollectionCmd() : GridAdminCmd( "shardCollection" ) {} virtual void help( stringstream& help ) const { help - << "Shard a collection. Requires key. Optional unique. Sharding must already be enabled for the database.\n" - << " { enablesharding : \"<dbname>\" }\n"; + << "Shard a collection. Requires key. Optional unique. Sharding must already be enabled for the database.\n" + << " { enablesharding : \"<dbname>\" }\n"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { string ns = cmdObj.firstElement().valuestrsafe(); - if ( ns.size() == 0 ){ + if ( ns.size() == 0 ) { errmsg = "no ns"; return false; } DBConfigPtr config = grid.getDBConfig( ns ); - if ( ! config->isShardingEnabled() ){ + if ( ! config->isShardingEnabled() ) { errmsg = "sharding not enabled for db"; return false; } - if ( config->isSharded( ns ) ){ + if ( config->isSharded( ns ) ) { errmsg = "already sharded"; return false; } BSONObj key = cmdObj.getObjectField( "key" ); - if ( key.isEmpty() ){ + if ( key.isEmpty() ) { errmsg = "no shard key"; return false; } - BSONForEach(e, key){ - if (!e.isNumber() || e.number() != 1.0){ + BSONForEach(e, key) { + if (!e.isNumber() || e.number() != 1.0) { errmsg = "shard keys must all be ascending"; return false; } } - if ( ns.find( ".system." ) != string::npos ){ + if ( ns.find( ".system." ) != string::npos ) { errmsg = "can't shard system namespaces"; return false; } @@ -344,10 +357,10 @@ namespace mongo { // 1. A unique index must have the sharding key as its prefix. Otherwise maintainig uniqueness would // require coordinated access to all shards. Trying to shard a collection with such an index is not // allowed. - // + // // 2. Sharding a collection requires an index over the sharding key. That index must be create upfront. // The rationale is that sharding a non-empty collection would need to create the index and that could - // be slow. Requiring the index upfront allows the admin to plan before sharding and perhaps use + // be slow. Requiring the index upfront allows the admin to plan before sharding and perhaps use // background index construction. One exception to the rule: empty collections. It's fairly easy to // create the index as part of the sharding process. // @@ -358,20 +371,20 @@ namespace mongo { bool hasShardIndex = false; ScopedDbConnection conn( config->getPrimary() ); - BSONObjBuilder b; - b.append( "ns" , ns ); + BSONObjBuilder b; + b.append( "ns" , ns ); auto_ptr<DBClientCursor> cursor = conn->query( config->getName() + ".system.indexes" , b.obj() ); - while ( cursor->more() ){ + while ( cursor->more() ) { BSONObj idx = cursor->next(); // Is index key over the sharding key? Remember that. - if ( key.woCompare( idx["key"].embeddedObjectUserCheck() ) == 0 ){ + if ( key.woCompare( idx["key"].embeddedObjectUserCheck() ) == 0 ) { hasShardIndex = true; } // Not a unique index? Move on. - if ( idx["unique"].eoo() || ! idx["unique"].Bool() ) + if ( idx["unique"].eoo() || ! idx["unique"].trueValue() ) continue; // Shard key is prefix of unique index? Move on. @@ -384,17 +397,31 @@ namespace mongo { } BSONObj res = conn->findOne( config->getName() + ".system.namespaces" , BSON( "name" << ns ) ); - if ( res["options"].type() == Object && res["options"].embeddedObject()["capped"].trueValue() ){ + if ( res["options"].type() == Object && res["options"].embeddedObject()["capped"].trueValue() ) { errmsg = "can't shard capped collection"; conn.done(); return false; } - if ( ! hasShardIndex && ( conn->count( ns ) != 0 ) ){ + if ( hasShardIndex ) { + // make sure there are no null entries in the sharding index + BSONObjBuilder cmd; + cmd.append( "checkShardingIndex" , ns ); + cmd.append( "keyPattern" , key ); + BSONObj cmdObj = cmd.obj(); + if ( ! conn->runCommand( "admin" , cmdObj , res )) { + errmsg = res["errmsg"].str(); + conn.done(); + return false; + } + } + + if ( ! hasShardIndex && ( conn->count( ns ) != 0 ) ) { errmsg = "please create an index over the sharding key before sharding."; + conn.done(); return false; } - + conn.done(); } @@ -409,26 +436,26 @@ namespace mongo { class GetShardVersion : public GridAdminCmd { public: - GetShardVersion() : GridAdminCmd( "getShardVersion" ){} + GetShardVersion() : GridAdminCmd( "getShardVersion" ) {} virtual void help( stringstream& help ) const { help << " example: { getShardVersion : 'alleyinsider.foo' } "; } - - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { string ns = cmdObj.firstElement().valuestrsafe(); - if ( ns.size() == 0 ){ + if ( ns.size() == 0 ) { errmsg = "need to speciy fully namespace"; return false; } - + DBConfigPtr config = grid.getDBConfig( ns ); - if ( ! config->isSharded( ns ) ){ + if ( ! config->isSharded( ns ) ) { errmsg = "ns not sharded."; return false; } - + ChunkManagerPtr cm = config->getChunkManager( ns ); - if ( ! cm ){ + if ( ! cm ) { errmsg = "no chunk manager?"; return false; } @@ -439,144 +466,141 @@ namespace mongo { } } getShardVersionCmd; - class SplitCollectionHelper : public GridAdminCmd { + class SplitCollectionCmd : public GridAdminCmd { public: - SplitCollectionHelper( const char * name ) : GridAdminCmd( name ) , _name( name ){} + SplitCollectionCmd() : GridAdminCmd( "split" ) {} virtual void help( stringstream& help ) const { help - << " example: { split : 'alleyinsider.blog.posts' , find : { ts : 1 } } - split the shard that contains give key \n" - << " example: { split : 'alleyinsider.blog.posts' , middle : { ts : 1 } } - split the shard that contains the key with this as the middle \n" - << " NOTE: this does not move move the chunks, it merely creates a logical seperation \n" - ; + << " example: - split the shard that contains give key \n" + << " { split : 'alleyinsider.blog.posts' , find : { ts : 1 } }\n" + << " example: - split the shard that contains the key with this as the middle \n" + << " { split : 'alleyinsider.blog.posts' , middle : { ts : 1 } }\n" + << " NOTE: this does not move move the chunks, it merely creates a logical seperation \n" + ; } - virtual bool _split( BSONObjBuilder& result , string&errmsg , const string& ns , ChunkManagerPtr manager , ChunkPtr old , BSONObj middle ) = 0; - - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { ShardConnection::sync(); string ns = cmdObj.firstElement().valuestrsafe(); - if ( ns.size() == 0 ){ + if ( ns.size() == 0 ) { errmsg = "no ns"; return false; } DBConfigPtr config = grid.getDBConfig( ns ); - if ( ! config->isSharded( ns ) ){ + if ( ! config->isSharded( ns ) ) { errmsg = "ns not sharded. have to shard before can split"; return false; } BSONObj find = cmdObj.getObjectField( "find" ); - if ( find.isEmpty() ){ + if ( find.isEmpty() ) { find = cmdObj.getObjectField( "middle" ); - if ( find.isEmpty() ){ + if ( find.isEmpty() ) { errmsg = "need to specify find or middle"; return false; } } - - ChunkManagerPtr info = config->getChunkManager( ns ); - ChunkPtr old = info->findChunk( find ); - - return _split( result , errmsg , ns , info , old , cmdObj.getObjectField( "middle" ) ); - } - - protected: - string _name; - }; - - class SplitValueCommand : public SplitCollectionHelper { - public: - SplitValueCommand() : SplitCollectionHelper( "splitValue" ){} - virtual bool _split( BSONObjBuilder& result , string& errmsg , const string& ns , ChunkManagerPtr manager , ChunkPtr old , BSONObj middle ){ - - result << "shardinfo" << old->toString(); - - result.appendBool( "auto" , middle.isEmpty() ); - - if ( middle.isEmpty() ) - middle = old->pickSplitPoint(); - result.append( "middle" , middle ); - - return true; - } + ChunkManagerPtr info = config->getChunkManager( ns ); + ChunkPtr chunk = info->findChunk( find ); + BSONObj middle = cmdObj.getObjectField( "middle" ); - } splitValueCmd; + assert( chunk.get() ); + log() << "splitting: " << ns << " shard: " << chunk << endl; + BSONObj res; + ChunkPtr p; + if ( middle.isEmpty() ) { + p = chunk->singleSplit( true /* force a split even if not enough data */ , res ); - class SplitCollection : public SplitCollectionHelper { - public: - SplitCollection() : SplitCollectionHelper( "split" ){} - virtual bool _split( BSONObjBuilder& result , string& errmsg , const string& ns , ChunkManagerPtr manager , ChunkPtr old , BSONObj middle ){ - assert( old.get() ); - log() << "splitting: " << ns << " shard: " << old << endl; - - if ( middle.isEmpty() ) - old->split(); + } else { + // sanity check if the key provided is a valid split point + if ( ( middle == chunk->getMin() ) || ( middle == chunk->getMax() ) ) { + errmsg = "cannot split on initial or final chunk's key"; + return false; + } + vector<BSONObj> splitPoints; splitPoints.push_back( middle ); - old->multiSplit( splitPoints ); + p = chunk->multiSplit( splitPoints , res ); } + if ( p.get() == NULL ) { + errmsg = "split failed"; + result.append( "cause" , res ); + return false; + } + config->getChunkManager( ns , true ); return true; } - - } splitCollectionCmd; class MoveChunkCmd : public GridAdminCmd { public: - MoveChunkCmd() : GridAdminCmd( "moveChunk" ){} + MoveChunkCmd() : GridAdminCmd( "moveChunk" ) {} virtual void help( stringstream& help ) const { help << "{ movechunk : 'test.foo' , find : { num : 1 } , to : 'localhost:30001' }"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { ShardConnection::sync(); Timer t; string ns = cmdObj.firstElement().valuestrsafe(); - if ( ns.size() == 0 ){ + if ( ns.size() == 0 ) { errmsg = "no ns"; return false; } DBConfigPtr config = grid.getDBConfig( ns ); - if ( ! config->isSharded( ns ) ){ + if ( ! config->isSharded( ns ) ) { errmsg = "ns not sharded. have to shard before can move a chunk"; return false; } BSONObj find = cmdObj.getObjectField( "find" ); - if ( find.isEmpty() ){ + if ( find.isEmpty() ) { errmsg = "need to specify find. see help"; return false; } string toString = cmdObj["to"].valuestrsafe(); - if ( ! toString.size() ){ + if ( ! toString.size() ) { errmsg = "you have to specify where you want to move the chunk"; return false; } - + Shard to = Shard::make( toString ); + // so far, chunk size serves test purposes; it may or may not become a supported parameter + long long maxChunkSizeBytes = cmdObj["maxChunkSizeBytes"].numberLong(); + if ( maxChunkSizeBytes == 0 ) { + maxChunkSizeBytes = Chunk::MaxChunkSize; + } + tlog() << "CMD: movechunk: " << cmdObj << endl; ChunkManagerPtr info = config->getChunkManager( ns ); ChunkPtr c = info->findChunk( find ); const Shard& from = c->getShard(); - if ( from == to ){ + if ( from == to ) { errmsg = "that chunk is already on that shard"; return false; } - - if ( ! c->moveAndCommit( to , errmsg ) ) + + BSONObj res; + if ( ! c->moveAndCommit( to , maxChunkSizeBytes , res ) ) { + errmsg = "move failed"; + result.append( "cause" , res ); return false; + } + + // pre-emptively reload the config to get new version info + config->getChunkManager( ns , true ); result.append( "millis" , t.millis() ); return true; @@ -591,12 +615,12 @@ namespace mongo { virtual void help( stringstream& help ) const { help << "list all shards of the system"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { ScopedDbConnection conn( configServer.getPrimary() ); vector<BSONObj> all; auto_ptr<DBClientCursor> cursor = conn->query( "config.shards" , BSONObj() ); - while ( cursor->more() ){ + while ( cursor->more() ) { BSONObj o = cursor->next(); all.push_back( o ); } @@ -608,27 +632,27 @@ namespace mongo { } } listShardsCmd; - /* a shard is a single mongod server or a replica pair. add it (them) to the cluster as a storage partition. */ + /* a shard is a single mongod server or a replica pair. add it (them) to the cluster as a storage partition. */ class AddShard : public GridAdminCmd { public: AddShard() : GridAdminCmd("addShard") { } virtual void help( stringstream& help ) const { help << "add a new shard to the system"; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { errmsg.clear(); // get replica set component hosts ConnectionString servers = ConnectionString::parse( cmdObj.firstElement().valuestrsafe() , errmsg ); - if ( ! errmsg.empty() ){ + if ( ! errmsg.empty() ) { log() << "addshard request " << cmdObj << " failed:" << errmsg << endl; return false; } // using localhost in server names implies every other process must use locahost addresses too vector<HostAndPort> serverAddrs = servers.getServers(); - for ( size_t i = 0 ; i < serverAddrs.size() ; i++ ){ - if ( serverAddrs[i].isLocalHost() != grid.allowLocalHost() ){ + for ( size_t i = 0 ; i < serverAddrs.size() ; i++ ) { + if ( serverAddrs[i].isLocalHost() != grid.allowLocalHost() ) { errmsg = "can't use localhost as a shard since all shards need to communicate. " "either use all shards and configdbs in localhost or all in actual IPs " ; log() << "addshard request " << cmdObj << " failed: attempt to mix localhosts and IPs" << endl; @@ -636,7 +660,7 @@ namespace mongo { } // it's fine if mongods of a set all use default port - if ( ! serverAddrs[i].hasPort() ){ + if ( ! serverAddrs[i].hasPort() ) { serverAddrs[i].setPort( CmdLine::ShardServerPort ); } } @@ -645,15 +669,15 @@ namespace mongo { string name = ""; if ( cmdObj["name"].type() == String ) { name = cmdObj["name"].valuestrsafe(); - } + } // maxSize is the space usage cap in a shard in MBs long long maxSize = 0; - if ( cmdObj[ ShardFields::maxSize.name() ].isNumber() ){ + if ( cmdObj[ ShardFields::maxSize.name() ].isNumber() ) { maxSize = cmdObj[ ShardFields::maxSize.name() ].numberLong(); } - - if ( ! grid.addShard( &name , servers , maxSize , errmsg ) ){ + + if ( ! grid.addShard( &name , servers , maxSize , errmsg ) ) { log() << "addshard request " << cmdObj << " failed: " << errmsg << endl; return false; } @@ -673,10 +697,10 @@ namespace mongo { virtual void help( stringstream& help ) const { help << "remove a shard to the system."; } - bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){ + bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { string target = cmdObj.firstElement().valuestrsafe(); Shard s = Shard::make( target ); - if ( ! grid.knowAboutShard( s.getConnString() ) ){ + if ( ! grid.knowAboutShard( s.getConnString() ) ) { errmsg = "unknown shard"; return false; } @@ -687,7 +711,7 @@ namespace mongo { BSONObj searchDoc = BSON( "_id" << s.getName() ); BSONObj drainingDoc = BSON( "_id" << s.getName() << ShardFields::draining(true) ); BSONObj shardDoc = conn->findOne( "config.shards", drainingDoc ); - if ( shardDoc.isEmpty() ){ + if ( shardDoc.isEmpty() ) { // TODO prevent move chunks to this shard. @@ -696,7 +720,7 @@ namespace mongo { conn->update( "config.shards" , searchDoc , newStatus, false /* do no upsert */); errmsg = conn->getLastError(); - if ( errmsg.size() ){ + if ( errmsg.size() ) { log() << "error starting remove shard: " << s.getName() << " err: " << errmsg << endl; return false; } @@ -704,7 +728,7 @@ namespace mongo { Shard::reloadShardInfo(); result.append( "msg" , "draining started successfully" ); - result.append( "state" , "started" ); + result.append( "state" , "started" ); result.append( "shard" , s.getName() ); conn.done(); return true; @@ -716,12 +740,12 @@ namespace mongo { long long chunkCount = conn->count( "config.chunks" , shardIDDoc ); BSONObj primaryDoc = BSON( "primary" << shardDoc[ "_id" ].str() ); long long dbCount = conn->count( "config.databases" , primaryDoc ); - if ( ( chunkCount == 0 ) && ( dbCount == 0 ) ){ - log() << "going to remove shard: " << s.getName() << endl; + if ( ( chunkCount == 0 ) && ( dbCount == 0 ) ) { + log() << "going to remove shard: " << s.getName() << endl; conn->remove( "config.shards" , searchDoc ); errmsg = conn->getLastError(); - if ( errmsg.size() ){ + if ( errmsg.size() ) { log() << "error concluding remove shard: " << s.getName() << " err: " << errmsg << endl; return false; } @@ -755,7 +779,7 @@ namespace mongo { class IsDbGridCmd : public Command { public: - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual bool slaveOk() const { return true; } @@ -769,7 +793,7 @@ namespace mongo { class CmdIsMaster : public Command { public: - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual bool requiresAuth() { return false; } virtual bool slaveOk() const { return true; @@ -777,10 +801,11 @@ namespace mongo { virtual void help( stringstream& help ) const { help << "test if this is master half of a replica pair"; } - CmdIsMaster() : Command("ismaster") { } + CmdIsMaster() : Command("isMaster" , false , "ismaster") { } virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { - result.append("ismaster", 1.0 ); + result.appendBool("ismaster", true ); result.append("msg", "isdbgrid"); + result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); return true; } } ismaster; @@ -794,23 +819,23 @@ namespace mongo { virtual bool slaveOk() const { return true; } - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual bool requiresAuth() { return false; } virtual void help( stringstream &help ) const { help << "{whatsmyuri:1}"; - } + } virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { result << "you" << ClientInfo::get()->getRemote(); return true; } } cmdWhatsMyUri; - + class CmdShardingGetPrevError : public Command { public: - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual bool requiresAuth() { return false; } virtual bool slaveOk() const { return true; @@ -827,7 +852,7 @@ namespace mongo { class CmdShardingGetLastError : public Command { public: - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual bool requiresAuth() { return false; } virtual bool slaveOk() const { return true; @@ -836,196 +861,147 @@ namespace mongo { help << "check for an error on the last command executed"; } CmdShardingGetLastError() : Command("getLastError" , false , "getlasterror") { } - - void addWriteBack( vector<OID>& all , const BSONObj& o ){ - BSONElement e = o["writeback"]; - if ( e.type() == jstOID ) - all.push_back( e.OID() ); - } - - void handleWriteBacks( vector<OID>& all ){ - if ( all.size() == 0 ) - return; - - for ( unsigned i=0; i<all.size(); i++ ){ - waitForWriteback( all[i] ); - } - } - virtual bool run(const string& dbName, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { LastError *le = lastError.disableForCommand(); { assert( le ); - if ( le->msg.size() && le->nPrev == 1 ){ + if ( le->msg.size() && le->nPrev == 1 ) { le->appendSelf( result ); return true; } } - + ClientInfo * client = ClientInfo::get(); - set<string> * shards = client->getPrev(); - - if ( shards->size() == 0 ){ - result.appendNull( "err" ); - return true; - } + return client->getLastError( cmdObj , result ); + } + } cmdGetLastError; - //log() << "getlasterror enter: " << shards->size() << endl; + } + class CmdShardingResetError : public Command { + public: + CmdShardingResetError() : Command( "resetError" , false , "reseterror" ) {} - vector<OID> writebacks; - - // handle single server - if ( shards->size() == 1 ){ - string theShard = *(shards->begin() ); - result.append( "theshard" , theShard.c_str() ); - ShardConnection conn( theShard , "" ); - BSONObj res; - bool ok = conn->runCommand( dbName , cmdObj , res ); - //log() << "\t" << res << endl; - result.appendElements( res ); - conn.done(); - result.append( "singleShard" , theShard ); - addWriteBack( writebacks , res ); - - // hit other machines just to block - for ( set<string>::const_iterator i=client->sinceLastGetError().begin(); i!=client->sinceLastGetError().end(); ++i ){ - string temp = *i; - if ( temp == theShard ) - continue; - - ShardConnection conn( temp , "" ); - addWriteBack( writebacks , conn->getLastErrorDetailed() ); - conn.done(); - } - client->clearSinceLastGetError(); - handleWriteBacks( writebacks ); - return ok; - } - - BSONArrayBuilder bbb( result.subarrayStart( "shards" ) ); - - long long n = 0; - - // hit each shard - vector<string> errors; - for ( set<string>::iterator i = shards->begin(); i != shards->end(); i++ ){ - string theShard = *i; - bbb.append( theShard ); - ShardConnection conn( theShard , "" ); - BSONObj res; - bool ok = conn->runCommand( dbName , cmdObj , res ); - addWriteBack( writebacks, res ); - string temp = DBClientWithCommands::getLastErrorString( res ); - if ( ok == false || temp.size() ) - errors.push_back( temp ); - n += res["n"].numberLong(); - conn.done(); - } - - bbb.done(); - - result.appendNumber( "n" , n ); - - // hit other machines just to block - for ( set<string>::const_iterator i=client->sinceLastGetError().begin(); i!=client->sinceLastGetError().end(); ++i ){ - string temp = *i; - if ( shards->count( temp ) ) - continue; - - ShardConnection conn( temp , "" ); - addWriteBack( writebacks, conn->getLastErrorDetailed() ); - conn.done(); - } - client->clearSinceLastGetError(); + virtual LockType locktype() const { return NONE; } + virtual bool requiresAuth() { return false; } + virtual bool slaveOk() const { + return true; + } - if ( errors.size() == 0 ){ - result.appendNull( "err" ); - handleWriteBacks( writebacks ); - return true; - } - - result.append( "err" , errors[0].c_str() ); - - BSONObjBuilder all; - for ( unsigned i=0; i<errors.size(); i++ ){ - all.append( all.numStr( i ) , errors[i].c_str() ); - } - result.appendArray( "errs" , all.obj() ); - handleWriteBacks( writebacks ); - return true; + bool run(const string& dbName , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) { + LastError *le = lastError.get(); + if ( le ) + le->reset(); + + ClientInfo * client = ClientInfo::get(); + set<string> * shards = client->getPrev(); + + for ( set<string>::iterator i = shards->begin(); i != shards->end(); i++ ) { + string theShard = *i; + ShardConnection conn( theShard , "" ); + BSONObj res; + conn->runCommand( dbName , cmdObj , res ); + conn.done(); } - } cmdGetLastError; - - } - + + return true; + } + } cmdShardingResetError; + class CmdListDatabases : public Command { public: - CmdListDatabases() : Command("listDatabases", false , "listdatabases" ) {} + CmdListDatabases() : Command("listDatabases", true , "listdatabases" ) {} virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return true; } virtual bool slaveOverrideOk() { return true; } virtual bool adminOnly() const { return true; } - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual void help( stringstream& help ) const { help << "list databases on cluster"; } - + bool run(const string& , BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) { vector<Shard> shards; Shard::getAllShards( shards ); - + map<string,long long> sizes; map< string,shared_ptr<BSONObjBuilder> > dbShardInfo; - for ( vector<Shard>::iterator i=shards.begin(); i!=shards.end(); i++ ){ + for ( vector<Shard>::iterator i=shards.begin(); i!=shards.end(); i++ ) { Shard s = *i; BSONObj x = s.runCommand( "admin" , "listDatabases" ); BSONObjIterator j( x["databases"].Obj() ); - while ( j.more() ){ + while ( j.more() ) { BSONObj theDB = j.next().Obj(); - + string name = theDB["name"].String(); long long size = theDB["sizeOnDisk"].numberLong(); long long& totalSize = sizes[name]; - if ( size == 1 ){ + if ( size == 1 ) { if ( totalSize <= 1 ) totalSize = 1; } else totalSize += size; - + shared_ptr<BSONObjBuilder>& bb = dbShardInfo[name]; if ( ! bb.get() ) bb.reset( new BSONObjBuilder() ); bb->appendNumber( s.getName() , size ); } - + } - + long long totalSize = 0; BSONArrayBuilder bb( result.subarrayStart( "databases" ) ); - for ( map<string,long long>::iterator i=sizes.begin(); i!=sizes.end(); ++i ){ + for ( map<string,long long>::iterator i=sizes.begin(); i!=sizes.end(); ++i ) { string name = i->first; + + if ( name == "local" ) { + // we don't return local + // since all shards have their own independant local + continue; + } + long long size = i->second; totalSize += size; - + BSONObjBuilder temp; temp.append( "name" , name ); - temp.appendNumber( "size" , size ); + temp.appendNumber( "sizeOnDisk" , size ); temp.appendBool( "empty" , size == 1 ); temp.append( "shards" , dbShardInfo[name]->obj() ); - + bb.append( temp.obj() ); } + + if ( sizes.find( "config" ) == sizes.end() ){ + ScopedDbConnection conn( configServer.getPrimary() ); + BSONObj x; + if ( conn->simpleCommand( "config" , &x , "dbstats" ) ){ + BSONObjBuilder b; + b.append( "name" , "config" ); + b.appendBool( "empty" , false ); + if ( x["fileSize"].type() ) + b.appendAs( x["fileSize"] , "sizeOnDisk" ); + else + b.append( "sizeOnDisk" , 1 ); + bb.append( b.obj() ); + } + else { + bb.append( BSON( "name" << "config" ) ); + } + conn.done(); + } + bb.done(); result.appendNumber( "totalSize" , totalSize ); result.appendNumber( "totalSizeMb" , totalSize / ( 1024 * 1024 ) ); - + return 1; } @@ -1038,9 +1014,9 @@ namespace mongo { virtual bool slaveOk() const { return true; } virtual bool slaveOverrideOk() { return true; } virtual bool adminOnly() const { return true; } - virtual LockType locktype() const { return NONE; } + virtual LockType locktype() const { return NONE; } virtual void help( stringstream& help ) const { help << "Not supported sharded"; } - + bool run(const string& , BSONObj& jsobj, string& errmsg, BSONObjBuilder& /*result*/, bool /*fromRepl*/) { errmsg = "closeAllDatabases isn't supported through mongos"; return false; @@ -1048,4 +1024,22 @@ namespace mongo { } cmdCloseAllDatabases; + class CmdReplSetGetStatus : public Command { + public: + CmdReplSetGetStatus() : Command("replSetGetStatus"){} + virtual bool logTheOp() { return false; } + virtual bool slaveOk() const { return true; } + virtual bool adminOnly() const { return true; } + virtual LockType locktype() const { return NONE; } + virtual void help( stringstream& help ) const { help << "Not supported through mongos"; } + + bool run(const string& , BSONObj& jsobj, string& errmsg, BSONObjBuilder& /*result*/, bool /*fromRepl*/) { + if ( jsobj["forShell"].trueValue() ) + lastError.disableForCommand(); + + errmsg = "replSetGetStatus is not supported through mongos"; + return false; + } + } cmdReplSetGetStatus; + } // namespace mongo |