diff options
| author | Antonin Kral <a.kral@bobek.cz> | 2012-08-29 20:54:51 +0200 |
|---|---|---|
| committer | Antonin Kral <a.kral@bobek.cz> | 2012-08-29 20:54:51 +0200 |
| commit | 83957b73f9177f6e38bd5375bd93ca1f6a47188c (patch) | |
| tree | f20b7d6ac9a9c64ff5bb6b5910a24abbb356b1d5 /src/mongo/shell/utils_sh.js | |
| parent | 5071d203970edd4c995493d810abe20987e76fe9 (diff) | |
Imported Upstream version 2.2.0upstream/2.2.0
Diffstat (limited to 'src/mongo/shell/utils_sh.js')
| -rw-r--r-- | src/mongo/shell/utils_sh.js | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/mongo/shell/utils_sh.js b/src/mongo/shell/utils_sh.js new file mode 100644 index 00000000000..3aa2102b2f4 --- /dev/null +++ b/src/mongo/shell/utils_sh.js @@ -0,0 +1,348 @@ +sh = function() { return "try sh.help();" } + +sh._checkMongos = function() { + var x = db.runCommand( "ismaster" ); + if ( x.msg != "isdbgrid" ) + throw "not connected to a mongos" +} + +sh._checkFullName = function( fullName ) { + assert( fullName , "neeed a full name" ) + assert( fullName.indexOf( "." ) > 0 , "name needs to be fully qualified <db>.<collection>'" ) +} + +sh._adminCommand = function( cmd , skipCheck ) { + if ( ! skipCheck ) sh._checkMongos(); + return db.getSisterDB( "admin" ).runCommand( cmd ); +} + +sh._dataFormat = function( bytes ){ + if( bytes < 1024 ) return Math.floor( bytes ) + "b" + if( bytes < 1024 * 1024 ) return Math.floor( bytes / 1024 ) + "kb" + if( bytes < 1024 * 1024 * 1024 ) return Math.floor( ( Math.floor( bytes / 1024 ) / 1024 ) * 100 ) / 100 + "Mb" + return Math.floor( ( Math.floor( bytes / ( 1024 * 1024 ) ) / 1024 ) * 100 ) / 100 + "Gb" +} + +sh._collRE = function( coll ){ + return RegExp( "^" + RegExp.escape(coll + "") + "-.*" ) +} + +sh._pchunk = function( chunk ){ + return "[" + tojson( chunk.min ) + " -> " + tojson( chunk.max ) + "]" +} + +sh.help = function() { + print( "\tsh.addShard( host ) server:port OR setname/server:port" ) + print( "\tsh.enableSharding(dbname) enables sharding on the database dbname" ) + print( "\tsh.shardCollection(fullName,key,unique) shards the collection" ); + + print( "\tsh.splitFind(fullName,find) splits the chunk that find is in at the median" ); + print( "\tsh.splitAt(fullName,middle) splits the chunk that middle is in at middle" ); + print( "\tsh.moveChunk(fullName,find,to) move the chunk where 'find' is to 'to' (name of shard)"); + + print( "\tsh.setBalancerState( <bool on or not> ) turns the balancer on or off true=on, false=off" ); + print( "\tsh.getBalancerState() return true if on, off if not" ); + print( "\tsh.isBalancerRunning() return true if the balancer is running on any mongos" ); + + print( "\tsh.addShardTag(shard,tag) adds the tag to the shard" ); + print( "\tsh.removeShardTag(shard,tag) removes the tag from the shard" ); + + print( "\tsh.status() prints a general overview of the cluster" ) +} + +sh.status = function( verbose , configDB ) { + // TODO: move the actual commadn here + printShardingStatus( configDB , verbose ); +} + +sh.addShard = function( url ){ + return sh._adminCommand( { addShard : url } , true ); +} + +sh.enableSharding = function( dbname ) { + assert( dbname , "need a valid dbname" ) + return sh._adminCommand( { enableSharding : dbname } ); +} + +sh.shardCollection = function( fullName , key , unique ) { + sh._checkFullName( fullName ) + assert( key , "need a key" ) + assert( typeof( key ) == "object" , "key needs to be an object" ) + + var cmd = { shardCollection : fullName , key : key } + if ( unique ) + cmd.unique = true; + + return sh._adminCommand( cmd ); +} + +sh.splitFind = function( fullName , find ) { + sh._checkFullName( fullName ) + return sh._adminCommand( { split : fullName , find : find } ); +} + +sh.splitAt = function( fullName , middle ) { + sh._checkFullName( fullName ) + return sh._adminCommand( { split : fullName , middle : middle } ); +} + +sh.moveChunk = function( fullName , find , to ) { + sh._checkFullName( fullName ); + return sh._adminCommand( { moveChunk : fullName , find : find , to : to } ) +} + +sh.setBalancerState = function( onOrNot ) { + db.getSisterDB( "config" ).settings.update({ _id: "balancer" }, { $set : { stopped: onOrNot ? false : true } }, true ); +} + +sh.getBalancerState = function() { + var x = db.getSisterDB( "config" ).settings.findOne({ _id: "balancer" } ) + if ( x == null ) + return true; + return ! x.stopped; +} + +sh.isBalancerRunning = function () { + var x = db.getSisterDB("config").locks.findOne({ _id: "balancer" }); + if (x == null) { + print("config.locks collection empty or missing. be sure you are connected to a mongos"); + return false; + } + return x.state > 0; +} + +sh.getBalancerHost = function() { + var x = db.getSisterDB("config").locks.findOne({ _id: "balancer" }); + if( x == null ){ + print("config.locks collection does not contain balancer lock. be sure you are connected to a mongos"); + return "" + } + return x.process.match(/[^:]+:[^:]+/)[0] +} + +sh.stopBalancer = function( timeout, interval ) { + sh.setBalancerState( false ) + sh.waitForBalancer( false, timeout, interval ) +} + +sh.startBalancer = function( timeout, interval ) { + sh.setBalancerState( true ) + sh.waitForBalancer( true, timeout, interval ) +} + +sh.waitForDLock = function( lockId, onOrNot, timeout, interval ){ + + // Wait for balancer to be on or off + // Can also wait for particular balancer state + var state = onOrNot + + var beginTS = undefined + if( state == undefined ){ + var currLock = db.getSisterDB( "config" ).locks.findOne({ _id : lockId }) + if( currLock != null ) beginTS = currLock.ts + } + + var lockStateOk = function(){ + var lock = db.getSisterDB( "config" ).locks.findOne({ _id : lockId }) + + if( state == false ) return ! lock || lock.state == 0 + if( state == true ) return lock && lock.state == 2 + if( state == undefined ) return (beginTS == undefined && lock) || + (beginTS != undefined && ( !lock || lock.ts + "" != beginTS + "" ) ) + else return lock && lock.state == state + } + + assert.soon( lockStateOk, + "Waited too long for lock " + lockId + " to " + + (state == true ? "lock" : ( state == false ? "unlock" : + "change to state " + state ) ), + timeout, + interval + ) +} + +sh.waitForPingChange = function( activePings, timeout, interval ){ + + var isPingChanged = function( activePing ){ + var newPing = db.getSisterDB( "config" ).mongos.findOne({ _id : activePing._id }) + return ! newPing || newPing.ping + "" != activePing.ping + "" + } + + // First wait for all active pings to change, so we're sure a settings reload + // happened + + // Timeout all pings on the same clock + var start = new Date() + + var remainingPings = [] + for( var i = 0; i < activePings.length; i++ ){ + + var activePing = activePings[ i ] + print( "Waiting for active host " + activePing._id + " to recognize new settings... (ping : " + activePing.ping + ")" ) + + // Do a manual timeout here, avoid scary assert.soon errors + var timeout = timeout || 30000; + var interval = interval || 200; + while( isPingChanged( activePing ) != true ){ + if( ( new Date() ).getTime() - start.getTime() > timeout ){ + print( "Waited for active ping to change for host " + activePing._id + + ", a migration may be in progress or the host may be down." ) + remainingPings.push( activePing ) + break + } + sleep( interval ) + } + + } + + return remainingPings +} + +sh.waitForBalancerOff = function( timeout, interval ){ + + var pings = db.getSisterDB( "config" ).mongos.find().toArray() + var activePings = [] + for( var i = 0; i < pings.length; i++ ){ + if( ! pings[i].waiting ) activePings.push( pings[i] ) + } + + print( "Waiting for active hosts..." ) + + activePings = sh.waitForPingChange( activePings, 60 * 1000 ) + + // After 1min, we assume that all hosts with unchanged pings are either + // offline (this is enough time for a full errored balance round, if a network + // issue, which would reload settings) or balancing, which we wait for next + // Legacy hosts we always have to wait for + + print( "Waiting for the balancer lock..." ) + + // Wait for the balancer lock to become inactive + // We can guess this is stale after 15 mins, but need to double-check manually + try{ + sh.waitForDLock( "balancer", false, 15 * 60 * 1000 ) + } + catch( e ){ + print( "Balancer still may be active, you must manually verify this is not the case using the config.changelog collection." ) + throw e + } + + print( "Waiting again for active hosts after balancer is off..." ) + + // Wait a short time afterwards, to catch the host which was balancing earlier + activePings = sh.waitForPingChange( activePings, 5 * 1000 ) + + // Warn about all the stale host pings remaining + for( var i = 0; i < activePings.length; i++ ){ + print( "Warning : host " + activePings[i]._id + " seems to have been offline since " + activePings[i].ping ) + } + +} + +sh.waitForBalancer = function( onOrNot, timeout, interval ){ + + // If we're waiting for the balancer to turn on or switch state or + // go to a particular state + if( onOrNot ){ + // Just wait for the balancer lock to change, can't ensure we'll ever see it + // actually locked + sh.waitForDLock( "balancer", undefined, timeout, interval ) + } + else { + // Otherwise we need to wait until we're sure balancing stops + sh.waitForBalancerOff( timeout, interval ) + } + +} + +sh.disableBalancing = function( coll ){ + var dbase = db + if( coll instanceof DBCollection ) dbase = coll.getDB() + dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : true } }) +} + +sh.enableBalancing = function( coll ){ + var dbase = db + if( coll instanceof DBCollection ) dbase = coll.getDB() + dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : false } }) +} + +/* + * Can call _lastMigration( coll ), _lastMigration( db ), _lastMigration( st ), _lastMigration( mongos ) + */ +sh._lastMigration = function( ns ){ + + var coll = null + var dbase = null + var config = null + + if( ! ns ){ + config = db.getSisterDB( "config" ) + } + else if( ns instanceof DBCollection ){ + coll = ns + config = coll.getDB().getSisterDB( "config" ) + } + else if( ns instanceof DB ){ + dbase = ns + config = dbase.getSisterDB( "config" ) + } + else if( ns instanceof ShardingTest ){ + config = ns.s.getDB( "config" ) + } + else if( ns instanceof Mongo ){ + config = ns.getDB( "config" ) + } + else { + // String namespace + ns = ns + "" + if( ns.indexOf( "." ) > 0 ){ + config = db.getSisterDB( "config" ) + coll = db.getMongo().getCollection( ns ) + } + else{ + config = db.getSisterDB( "config" ) + dbase = db.getSisterDB( ns ) + } + } + + var searchDoc = { what : /^moveChunk/ } + if( coll ) searchDoc.ns = coll + "" + if( dbase ) searchDoc.ns = new RegExp( "^" + dbase + "\\." ) + + var cursor = config.changelog.find( searchDoc ).sort({ time : -1 }).limit( 1 ) + if( cursor.hasNext() ) return cursor.next() + else return null +} + +sh._checkLastError = function( mydb ) { + var err = mydb.getLastError(); + if ( err ) + throw "error: " + err; +} + +sh.addShardTag = function( shard, tag ) { + var config = db.getSisterDB( "config" ); + if ( config.shards.findOne( { _id : shard } ) == null ) { + throw "can't find a shard with name: " + shard; + } + config.shards.update( { _id : shard } , { $addToSet : { tags : tag } } ); + sh._checkLastError( config ); +} + +sh.removeShardTag = function( shard, tag ) { + var config = db.getSisterDB( "config" ); + if ( config.shards.findOne( { _id : shard } ) == null ) { + throw "can't find a shard with name: " + shard; + } + config.shards.update( { _id : shard } , { $pull : { tags : tag } } ); + sh._checkLastError( config ); +} + +sh.addTagRange = function( ns, min, max, tag ) { + var config = db.getSisterDB( "config" ); + config.tags.update( { ns : ns , min : min } , + { ns : ns , min : min , max : max , tag : tag } , + true ); + sh._checkLastError( config ); +} |
