_parsePath = function() { var dbpath = ""; for( var i = 0; i < arguments.length; ++i ) if ( arguments[ i ] == "--dbpath" ) dbpath = arguments[ i + 1 ]; if ( dbpath == "" ) throw "No dbpath specified"; return dbpath; } _parsePort = function() { var port = ""; for( var i = 0; i < arguments.length; ++i ) if ( arguments[ i ] == "--port" ) port = arguments[ i + 1 ]; if ( port == "" ) throw "No port specified"; return port; } createMongoArgs = function( binaryName , args ){ var fullArgs = [ binaryName ]; if ( args.length == 1 && isObject( args[0] ) ){ var o = args[0]; for ( var k in o ){ if ( o.hasOwnProperty(k) ){ if ( k == "v" && isNumber( o[k] ) ){ var n = o[k]; if ( n > 0 ){ if ( n > 10 ) n = 10; var temp = "-"; while ( n-- > 0 ) temp += "v"; fullArgs.push( temp ); } } else { fullArgs.push( "--" + k ); if ( o[k] != "" ) fullArgs.push( "" + o[k] ); } } } } else { for ( var i=0; i " + tojsononeline( r.max ); } ShardingTest.prototype.printChangeLog = function(){ var s = this; this.config.changelog.find().forEach( function(z){ var msg = z.server + "\t" + z.time + "\t" + z.what; for ( i=z.what.length; i<15; i++ ) msg += " "; msg += " " + z.ns + "\t"; if ( z.what == "split" ){ msg += s._rangeToString( z.details.before ) + " -->> (" + s._rangeToString( z.details.left ) + "),(" + s._rangeToString( z.details.right ) + ")"; } else if (z.what == "multi-split" ){ msg += s._rangeToString( z.details.before ) + " -->> (" + z.details.number + "/" + z.details.of + " " + s._rangeToString( z.details.chunk ) + ")"; } else { msg += tojsononeline( z.details ); } print( msg ) } ); } ShardingTest.prototype.getChunksString = function( ns ){ var q = {} if ( ns ) q.ns = ns; var s = ""; this.config.chunks.find( q ).sort( { ns : 1 , min : 1 } ).forEach( function(z){ s += " " + z._id + "\t" + z.lastmod.t + "|" + z.lastmod.i + "\t" + tojson(z.min) + " -> " + tojson(z.max) + " " + z.shard + " " + z.ns + "\n"; } ); return s; } ShardingTest.prototype.printChunks = function( ns ){ print( this.getChunksString( ns ) ); } ShardingTest.prototype.printShardingStatus = function(){ printShardingStatus( this.config ); } ShardingTest.prototype.printCollectionInfo = function( ns , msg ){ var out = ""; if ( msg ) out += msg + "\n"; out += "sharding collection info: " + ns + "\n"; for ( var i=0; i> " + tojson( chunk.max ) + " on : " + chunk.shard + " " + tojson( chunk.lastmod ) ); } ); } else { output( "\t\t\ttoo many chunks to print, use verbose if you want to force print" ); } } } ) } } ); print( raw ); } printShardingSizes = function(){ configDB = db.getSisterDB('config') var version = configDB.getCollection( "version" ).findOne(); if ( version == null ){ print( "not a shard db!" ); return; } var raw = ""; var output = function(s){ raw += s + "\n"; } output( "--- Sharding Status --- " ); output( " sharding version: " + tojson( configDB.getCollection( "version" ).findOne() ) ); output( " shards:" ); var shards = {}; configDB.shards.find().forEach( function(z){ shards[z._id] = new Mongo(z.host); output( " " + tojson(z) ); } ); var saveDB = db; output( " databases:" ); configDB.databases.find().sort( { name : 1 } ).forEach( function(db){ output( "\t" + tojson(db,"",true) ); if (db.partitioned){ configDB.collections.find( { _id : new RegExp( "^" + db._id + "\." ) } ).sort( { _id : 1 } ).forEach( function( coll ){ output("\t\t" + coll._id + " chunks:"); configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach( function(chunk){ var mydb = shards[chunk.shard].getDB(db._id) var out = mydb.runCommand({dataSize: coll._id, keyPattern: coll.key, min: chunk.min, max: chunk.max }); delete out.millis; delete out.ok; output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) + " on : " + chunk.shard + " " + tojson( out ) ); } ); } ) } } ); print( raw ); } ShardingTest.prototype.sync = function(){ this.adminCommand( "connpoolsync" ); } ShardingTest.prototype.onNumShards = function( collName , dbName ){ this.sync(); // we should sync since we're going directly to mongod here dbName = dbName || "test"; var num=0; for ( var i=0; i 0 ) num++; return num; } ShardingTest.prototype.shardCounts = function( collName , dbName ){ this.sync(); // we should sync since we're going directly to mongod here dbName = dbName || "test"; var counts = {} for ( var i=0; i max ) max = c[s]; } print( "input: " + tojson( c ) + " min: " + min + " max: " + max ); return max - min; } ShardingTest.prototype.shardGo = function( collName , key , split , move , dbName ){ split = split || key; move = move || split; dbName = dbName || "test"; var c = dbName + "." + collName; s.adminCommand( { shardcollection : c , key : key } ); s.adminCommand( { split : c , middle : split } ); s.adminCommand( { movechunk : c , find : move , to : this.getOther( s.getServer( dbName ) ).name } ); }; /** * Run a mongod process. * * After initializing a MongodRunner, you must call start() on it. * @param {int} port port to run db on, use allocatePorts(num) to requision * @param {string} dbpath path to use * @param {boolean} peer pass in false (DEPRECATED, was used for replica pair host) * @param {boolean} arbiter pass in false (DEPRECATED, was used for replica pair host) * @param {array} extraArgs other arguments for the command line * @param {object} options other options include no_bind to not bind_ip to 127.0.0.1 * (necessary for replica set testing) */ MongodRunner = function( port, dbpath, peer, arbiter, extraArgs, options ) { this.port_ = port; this.dbpath_ = dbpath; this.peer_ = peer; this.arbiter_ = arbiter; this.extraArgs_ = extraArgs; this.options_ = options ? options : {}; }; /** * Start this mongod process. * * @param {boolean} reuseData If the data directory should be left intact (default is to wipe it) */ MongodRunner.prototype.start = function( reuseData ) { var args = []; if ( reuseData ) { args.push( "mongod" ); } args.push( "--port" ); args.push( this.port_ ); args.push( "--dbpath" ); args.push( this.dbpath_ ); if ( this.peer_ && this.arbiter_ ) { args.push( "--pairwith" ); args.push( this.peer_ ); args.push( "--arbiter" ); args.push( this.arbiter_ ); args.push( "--oplogSize" ); // small oplog by default so startup fast args.push( "1" ); } args.push( "--nohttpinterface" ); args.push( "--noprealloc" ); args.push( "--smallfiles" ); if (!this.options_.no_bind) { args.push( "--bind_ip" ); args.push( "127.0.0.1" ); } if ( this.extraArgs_ ) { args = args.concat( this.extraArgs_ ); } removeFile( this.dbpath_ + "/mongod.lock" ); if ( reuseData ) { return startMongoProgram.apply( null, args ); } else { return startMongod.apply( null, args ); } } MongodRunner.prototype.port = function() { return this.port_; } MongodRunner.prototype.toString = function() { return [ this.port_, this.dbpath_, this.peer_, this.arbiter_ ].toString(); } ReplPair = function( left, right, arbiter ) { this.left_ = left; this.leftC_ = null; this.right_ = right; this.rightC_ = null; this.arbiter_ = arbiter; this.arbiterC_ = null; this.master_ = null; this.slave_ = null; } ReplPair.prototype.start = function( reuseData ) { if ( this.arbiterC_ == null ) { this.arbiterC_ = this.arbiter_.start(); } if ( this.leftC_ == null ) { this.leftC_ = this.left_.start( reuseData ); } if ( this.rightC_ == null ) { this.rightC_ = this.right_.start( reuseData ); } } ReplPair.prototype.isMaster = function( mongo, debug ) { var im = mongo.getDB( "admin" ).runCommand( { ismaster : 1 } ); assert( im && im.ok, "command ismaster failed" ); if ( debug ) { printjson( im ); } return im.ismaster; } ReplPair.prototype.isInitialSyncComplete = function( mongo, debug ) { var isc = mongo.getDB( "admin" ).runCommand( { isinitialsynccomplete : 1 } ); assert( isc && isc.ok, "command isinitialsynccomplete failed" ); if ( debug ) { printjson( isc ); } return isc.initialsynccomplete; } ReplPair.prototype.checkSteadyState = function( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ) { leftValues = leftValues || {}; rightValues = rightValues || {}; var lm = null; var lisc = null; if ( this.leftC_ != null ) { lm = this.isMaster( this.leftC_, debug ); leftValues[ lm ] = true; lisc = this.isInitialSyncComplete( this.leftC_, debug ); } var rm = null; var risc = null; if ( this.rightC_ != null ) { rm = this.isMaster( this.rightC_, debug ); rightValues[ rm ] = true; risc = this.isInitialSyncComplete( this.rightC_, debug ); } var stateSet = {} state.forEach( function( i ) { stateSet[ i ] = true; } ); if ( !( 1 in stateSet ) || ( ( risc || risc == null ) && ( lisc || lisc == null ) ) ) { if ( rm == 1 && lm != 1 ) { assert( twoMasterOk || !( 1 in leftValues ) ); this.master_ = this.rightC_; this.slave_ = this.leftC_; } else if ( lm == 1 && rm != 1 ) { assert( twoMasterOk || !( 1 in rightValues ) ); this.master_ = this.leftC_; this.slave_ = this.rightC_; } if ( !twoMasterOk ) { assert( lm != 1 || rm != 1, "two masters" ); } // check for expected state if ( state.sort().toString() == [ lm, rm ].sort().toString() ) { if ( expectedMasterHost != null ) { if( expectedMasterHost == this.master_.host ) { return true; } } else { return true; } } } this.master_ = null; this.slave_ = null; return false; } ReplPair.prototype.waitForSteadyState = function( state, expectedMasterHost, twoMasterOk, debug ) { state = state || [ 1, 0 ]; twoMasterOk = twoMasterOk || false; var rp = this; var leftValues = {}; var rightValues = {}; assert.soon( function() { return rp.checkSteadyState( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ); }, "rp (" + rp + ") failed to reach expected steady state (" + state + ")" , 60000 ); } ReplPair.prototype.master = function() { return this.master_; } ReplPair.prototype.slave = function() { return this.slave_; } ReplPair.prototype.right = function() { return this.rightC_; } ReplPair.prototype.left = function() { return this.leftC_; } ReplPair.prototype.arbiter = function() { return this.arbiterC_; } ReplPair.prototype.killNode = function( mongo, signal ) { signal = signal || 15; if ( this.leftC_ != null && this.leftC_.host == mongo.host ) { stopMongod( this.left_.port_ ); this.leftC_ = null; } if ( this.rightC_ != null && this.rightC_.host == mongo.host ) { stopMongod( this.right_.port_ ); this.rightC_ = null; } if ( this.arbiterC_ != null && this.arbiterC_.host == mongo.host ) { stopMongod( this.arbiter_.port_ ); this.arbiterC_ = null; } } ReplPair.prototype._annotatedNode = function( mongo ) { var ret = ""; if ( mongo != null ) { ret += " (connected)"; if ( this.master_ != null && mongo.host == this.master_.host ) { ret += "(master)"; } if ( this.slave_ != null && mongo.host == this.slave_.host ) { ret += "(slave)"; } } return ret; } ReplPair.prototype.toString = function() { var ret = ""; ret += "left: " + this.left_; ret += " " + this._annotatedNode( this.leftC_ ); ret += " right: " + this.right_; ret += " " + this._annotatedNode( this.rightC_ ); return ret; } ToolTest = function( name ){ this.name = name; this.port = allocatePorts(1)[0]; this.baseName = "jstests_tool_" + name; this.root = "/data/db/" + this.baseName; this.dbpath = this.root + "/"; this.ext = this.root + "_external/"; this.extFile = this.root + "_external/a"; resetDbpath( this.dbpath ); } ToolTest.prototype.startDB = function( coll ){ assert( ! this.m , "db already running" ); this.m = startMongoProgram( "mongod" , "--port", this.port , "--dbpath" , this.dbpath , "--nohttpinterface", "--noprealloc" , "--smallfiles" , "--bind_ip", "127.0.0.1" ); this.db = this.m.getDB( this.baseName ); if ( coll ) return this.db.getCollection( coll ); return this.db; } ToolTest.prototype.stop = function(){ if ( ! this.m ) return; stopMongod( this.port ); this.m = null; this.db = null; print('*** ' + this.name + " completed successfully ***"); } ToolTest.prototype.runTool = function(){ var a = [ "mongo" + arguments[0] ]; var hasdbpath = false; for ( var i=1; i timeout) { throw('[' + opts['desc'] + ']' + " timed out"); } } return result; } ReplSetTest.prototype.initiate = function( cfg , initCmd , timeout ) { var master = this.nodes[0].getDB("admin"); var config = cfg || this.getReplSetConfig(); var cmd = {}; var cmdKey = initCmd || 'replSetInitiate'; var timeout = timeout || 30000; cmd[cmdKey] = config; printjson(cmd); this.attempt({timeout: timeout, desc: "Initiate replica set"}, function() { var result = master.runCommand(cmd); printjson(result); return result['ok'] == 1; }); } ReplSetTest.prototype.reInitiate = function() { var master = this.nodes[0]; var c = master.getDB("local")['system.replset'].findOne(); var config = this.getReplSetConfig(); config.version = c.version + 1; this.initiate( config , 'replSetReconfig' ); } ReplSetTest.prototype.awaitReplication = function() { this.getMaster(); latest = this.liveNodes.master.getDB("local")['oplog.rs'].find({}).sort({'$natural': -1}).limit(1).next()['ts'] print(latest); this.attempt({context: this, timeout: 30000, desc: "awaiting replication"}, function() { var synced = true; for(var i=0; i