diff options
author | Tad Marshall <tad@10gen.com> | 2012-04-12 06:50:35 -0400 |
---|---|---|
committer | Tad Marshall <tad@10gen.com> | 2012-04-12 06:50:35 -0400 |
commit | 869e8b4ace0d6f7e0379ca412f73a118b1ab3312 (patch) | |
tree | 2b95f9f3ee9f11fcd256af7a322d4778f1915987 /src/mongo/shell/shardingtest.js | |
parent | 892331fa9fe5dfdd0403882b219284f1cd199d9c (diff) | |
download | mongo-869e8b4ace0d6f7e0379ca412f73a118b1ab3312.tar.gz |
Break servers.js into several files
The addition of some (ok, a lot of) comments into shell/servers.js made
the processed file shell/mongo-server.cpp contain a string constant longer
than 65536 characters, and this made it not compile in MSVC any more (scons
or Visual Studio). This commit breaks the file into smaller sections,
somewhat logically grouped, and feeds them to the JavaScript engine in the
same order as before (so it shouldn't break anything). No code was added
or removed other than to restore Randolph's comments, and nothing was
rearranged other than the disassembly into separate source files, with
resulting separate string constants.
Diffstat (limited to 'src/mongo/shell/shardingtest.js')
-rw-r--r-- | src/mongo/shell/shardingtest.js | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js new file mode 100644 index 00000000000..c13a5df66b6 --- /dev/null +++ b/src/mongo/shell/shardingtest.js @@ -0,0 +1,900 @@ +/** + * Starts up a sharded cluster with the given specifications. The cluster + * will be fully operational after the execution of this constructor function. + * + * @param {Object} testName Contains the key value pair for the cluster + * configuration. Accpeted keys are: + * + * { + * name {string}: name for this test + * verbose {number}: the verbosity for the mongos + * keyFile {string}: the location of the keyFile + * chunksize {number}: + * nopreallocj {boolean|number}: + * + * mongos {number|Object|Array.<Object>}: number of mongos or mongos + * configuration object(s). @see MongoRunner.runMongos + * + * rs {Object|Array.<Object>}: replica set configuration object. Can + * contain: + * { + * nodes {number}: number of replica members. Defaults to 3. + * For other options, @see ReplSetTest#start + * } + * + * shards {number|Object|Array.<Object>}: number of shards or shard + * configuration object(s). @see MongoRunner.runMongod + * + * config {number|Object|Array.<Object>}: number of config server or + * config server configuration object(s). the presence of this field implies + * other.separateConfig = true, and if has 3 or more members, implies + * other.sync = true. @see MongoRunner.runMongod + * + * WARNING: use Array format for shards/config/rs/mongos when used + * together as they can overwrite each other's settings. + * + * other: { + * nopreallocj: same as above + * rs: same as above + * chunksize: same as above + * + * shardOptions {Object}: same as the shards property above. + * Can be used to specify options that are common all shards. + * + * sync {boolean}: Use SyncClusterConnection, and readies + * 3 config servers. + * separateConfig {boolean}: if false, recycle one of the running mongod + * as a config server. The config property can override this. + * configOptions {Object}: same as the config property above. + * Can be used to specify options that are common all config servers. + * mongosOptions {Object}: same as the mongos property above. + * Can be used to specify options that are common all mongos. + * + * // replica Set only: + * rsOptions {Object}: same as the rs property above. Can be used to + * specify options that are common all replica members. + * useHostname {boolean}: if true, use hostname of machine, + * otherwise use localhost + * numReplicas {number} + * } + * } + * + * Member variables: + * s {Mongo} - connection to the first mongos + * s0, s1, ... {Mongo} - connection to different mongos + * rs0, rs1, ... {ReplSetTest} - test objects to replica sets + * shard0, shard1, ... {Mongo} - connection to shards (not available for replica sets) + * d0, d1, ... {Mongo} - same as shard0, shard1, ... + * config0, config1, ... {Mongo} - connection to config servers + * c0, c1, ... {Mongo} - same as config0, config1, ... + */ +ShardingTest = function( testName , numShards , verboseLevel , numMongos , otherParams ){ + + this._startTime = new Date(); + + // Check if testName is an object, if so, pull params from there + var keyFile = undefined + otherParams = Object.merge( otherParams || {}, {} ) + otherParams.extraOptions = otherParams.extraOptions || {} + + if( isObject( testName ) ){ + + var params = Object.merge( testName, {} ) + + testName = params.name || "test" + + otherParams = Object.merge( params.other || {}, {} ) + otherParams.extraOptions = otherParams.extraOptions || {} + + numShards = params.shards || 2 + verboseLevel = params.verbose || 0 + numMongos = params.mongos || 1 + + keyFile = params.keyFile || otherParams.keyFile || otherParams.extraOptions.keyFile + otherParams.nopreallocj = params.nopreallocj || otherParams.nopreallocj + otherParams.rs = params.rs || ( params.other ? params.other.rs : undefined ) + otherParams.chunksize = params.chunksize || ( params.other ? params.other.chunksize : undefined ) + + // Allow specifying options like : + // { mongos : [ { noprealloc : "" } ], config : [ { smallfiles : "" } ], shards : { rs : true, d : true } } + if( isObject( numShards ) ){ + var len = 0 + for( var i in numShards ){ + otherParams[ "" + i ] = numShards[i] + len++ + } + numShards = len + } + + if( isObject( numMongos ) ){ + var len = 0 + for( var i in numMongos ){ + otherParams[ "" + i ] = numMongos[i] + len++ + } + numMongos = len + } + else if( Array.isArray( numMongos ) ){ + for( var i = 0; i < numMongos.length; i++ ) + otherParams[ "s" + i ] = numMongos[i] + numMongos = numMongos.length + } + + if( isObject( params.config ) ){ + var len = 0 + for( var i in params.config ){ + otherParams[ "" + i ] = params.config[i] + len++ + } + + // If we're specifying explicit config options, we need separate config servers + otherParams.separateConfig = true + if( len == 3 ) otherParams.sync = true + else otherParams.sync = false + } + else if( Array.isArray( params.config ) ){ + for( var i = 0; i < params.config.length; i++ ) + otherParams[ "c" + i ] = params.config[i] + + // If we're specifying explicit config options, we need separate config servers + otherParams.separateConfig = true + if( params.config.length == 3 ) otherParams.sync = true + else otherParams.sync = false + } + else if( params.config ) { + + if( params.config == 3 ){ + otherParams.separateConfig = otherParams.separateConfig || true + otherParams.sync = true + } + + } + } + else { + // Handle legacy stuff + keyFile = otherParams.extraOptions.keyFile + } + + this._testName = testName + this._otherParams = otherParams + + var pathOpts = this.pathOpts = { testName : testName } + + var hasRS = false + for( var k in otherParams ){ + if( k.startsWith( "rs" ) ){ + hasRS = true + break + } + } + + if( hasRS ){ + otherParams.separateConfig = true + otherParams.useHostname = otherParams.useHostname == undefined ? true : otherParams.useHostname + } + + var localhost = otherParams.useHostname ? getHostName() : "localhost"; + + this._alldbpaths = [] + this._connections = [] + this._shardServers = this._connections + this._rs = [] + this._rsObjects = [] + + for ( var i = 0; i < numShards; i++ ) { + if( otherParams.rs || otherParams["rs" + i] ){ + + otherParams.separateConfig = true + + var setName = testName + "-rs" + i; + + rsDefaults = { useHostname : otherParams.useHostname, + noJournalPrealloc : otherParams.nopreallocj, + oplogSize : 40, + nodes : 3, + pathOpts : Object.merge( pathOpts, { shard : i } )} + + rsDefaults = Object.merge( rsDefaults, otherParams.rs ) + rsDefaults = Object.merge( rsDefaults, otherParams.rsOptions ) + rsDefaults = Object.merge( rsDefaults, otherParams["rs" + i] ) + + var numReplicas = rsDefaults.nodes || otherParams.numReplicas || 3 + delete rsDefaults.nodes + + print( "Replica set test!" ) + + var rs = new ReplSetTest( { name : setName , nodes : numReplicas , startPort : 31100 + ( i * 100 ), useHostName : otherParams.useHostname, keyFile : keyFile, shardSvr : true } ); + this._rs[i] = { setName : setName , test : rs , nodes : rs.startSet( rsDefaults ) , url : rs.getURL() }; + rs.initiate(); + this["rs" + i] = rs + + this._rsObjects[i] = rs + + this._alldbpaths.push( null ) + this._connections.push( null ) + } + else { + var options = { useHostname : otherParams.useHostname, + noJournalPrealloc : otherParams.nopreallocj, + port : 30000 + i, + pathOpts : Object.merge( pathOpts, { shard : i } ), + dbpath : "$testName$shard", + keyFile : keyFile + } + + options = Object.merge( options, otherParams.shardOptions ) + options = Object.merge( options, otherParams["d" + i] ) + + var conn = MongoRunner.runMongod( options ); + + this._alldbpaths.push( testName +i ) + this._connections.push( conn ); + this["shard" + i] = conn + this["d" + i] = conn + + this._rs[i] = null + this._rsObjects[i] = null + } + } + + // Do replication on replica sets if required + for ( var i = 0; i < numShards; i++ ){ + if( ! otherParams.rs && ! otherParams["rs" + i] ) continue + + var rs = this._rs[i].test; + + rs.getMaster().getDB( "admin" ).foo.save( { x : 1 } ) + rs.awaitReplication(); + + var rsConn = new Mongo( rs.getURL() ); + rsConn.name = rs.getURL(); + this._connections[i] = rsConn + this["shard" + i] = rsConn + rsConn.rs = rs + } + + this._configServers = [] + this._configNames = [] + + if ( otherParams.sync && ! otherParams.separateConfig && numShards < 3 ) + throw "if you want sync, you need at least 3 servers"; + + for ( var i = 0; i < ( otherParams.sync ? 3 : 1 ) ; i++ ) { + + var conn = null + + if( otherParams.separateConfig ){ + + var options = { useHostname : otherParams.useHostname, + noJournalPrealloc : otherParams.nopreallocj, + port : 29000 + i, + pathOpts : Object.merge( pathOpts, { config : i } ), + dbpath : "$testName-config$config", + keyFile : keyFile + } + + options = Object.merge( options, otherParams.configOptions ) + options = Object.merge( options, otherParams["c" + i] ) + + var conn = MongoRunner.runMongod( options ) + + // TODO: Needed? + this._alldbpaths.push( testName + "-config" + i ) + } + else{ + conn = this["shard" + i] + } + + this._configServers.push( conn ); + this._configNames.push( conn.name ) + this["config" + i] = conn + this["c" + i] = conn + } + + printjson( this._configDB = this._configNames.join( "," ) ) + this._configConnection = new Mongo( this._configDB ) + if ( ! otherParams.noChunkSize ) { + this._configConnection.getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || otherParams.chunkSize || 50 } ) + } + + print( "ShardingTest " + this._testName + " :\n" + tojson( { config : this._configDB, shards : this._connections } ) ); + + this._mongos = [] + this._mongoses = this._mongos + for ( var i = 0; i < ( ( numMongos == 0 ? -1 : numMongos ) || 1 ); i++ ){ + + var options = { useHostname : otherParams.useHostname, + port : 31000 - i - 1, + pathOpts : Object.merge( pathOpts, { mongos : i } ), + configdb : this._configDB, + verbose : verboseLevel || 0, + keyFile : keyFile + } + + options = Object.merge( options, otherParams.mongosOptions ) + options = Object.merge( options, otherParams.extraOptions ) + options = Object.merge( options, otherParams["s" + i] ) + + var conn = MongoRunner.runMongos( options ) + + this._mongos.push( conn ); + if ( i == 0 ) this.s = conn + this["s" + i] = conn + } + + var admin = this.admin = this.s.getDB( "admin" ); + this.config = this.s.getDB( "config" ); + + if ( ! otherParams.manualAddShard ){ + this._shardNames = [] + var shardNames = this._shardNames + this._connections.forEach( + function(z){ + var n = z.name; + if ( ! n ){ + n = z.host; + if ( ! n ) + n = z; + } + print( "ShardingTest " + this._testName + " going to add shard : " + n ) + x = admin.runCommand( { addshard : n } ); + printjson( x ) + shardNames.push( x.shardAdded ) + z.shardName = x.shardAdded + } + ); + } + + if (jsTestOptions().keyFile && !keyFile) { + jsTest.addAuth(this._mongos[0]); + jsTest.authenticateNodes(this._connections); + jsTest.authenticateNodes(this._configServers); + jsTest.authenticateNodes(this._mongos); + } +} + +ShardingTest.prototype.getRSEntry = function( setName ){ + for ( var i=0; i<this._rs.length; i++ ) + if ( this._rs[i].setName == setName ) + return this._rs[i]; + throw "can't find rs: " + setName; +} + +ShardingTest.prototype.getConfigIndex = function( config ){ + + // Assume config is a # if not a conn object + if( ! isObject( config ) ) config = getHostName() + ":" + config + + for( var i = 0; i < this._configServers.length; i++ ){ + if( connectionURLTheSame( this._configServers[i], config ) ) return i + } + + return -1 +} + +ShardingTest.prototype.getDB = function( name ){ + return this.s.getDB( name ); +} + +ShardingTest.prototype.getServerName = function( dbname ){ + var x = this.config.databases.findOne( { _id : "" + dbname } ); + if ( x ) + return x.primary; + this.config.databases.find().forEach( printjson ); + throw "couldn't find dbname: " + dbname + " total: " + this.config.databases.count(); +} + + +ShardingTest.prototype.getNonPrimaries = function( dbname ){ + var x = this.config.databases.findOne( { _id : dbname } ); + if ( ! x ){ + this.config.databases.find().forEach( printjson ); + throw "couldn't find dbname: " + dbname + " total: " + this.config.databases.count(); + } + + return this.config.shards.find( { _id : { $ne : x.primary } } ).map( function(z){ return z._id; } ) +} + + +ShardingTest.prototype.getConnNames = function(){ + var names = []; + for ( var i=0; i<this._connections.length; i++ ){ + names.push( this._connections[i].name ); + } + return names; +} + +ShardingTest.prototype.getServer = function( dbname ){ + var name = this.getServerName( dbname ); + + var x = this.config.shards.findOne( { _id : name } ); + if ( x ) + name = x.host; + + var rsName = null; + if ( name.indexOf( "/" ) > 0 ) + rsName = name.substring( 0 , name.indexOf( "/" ) ); + + for ( var i=0; i<this._connections.length; i++ ){ + var c = this._connections[i]; + if ( connectionURLTheSame( name , c.name ) || + connectionURLTheSame( rsName , c.name ) ) + return c; + } + + throw "can't find server for: " + dbname + " name:" + name; + +} + +ShardingTest.prototype.normalize = function( x ){ + var z = this.config.shards.findOne( { host : x } ); + if ( z ) + return z._id; + return x; +} + +ShardingTest.prototype.getOther = function( one ){ + if ( this._connections.length < 2 ) + throw "getOther only works with 2 servers"; + + if ( one._mongo ) + one = one._mongo + + for( var i = 0; i < this._connections.length; i++ ){ + if( this._connections[i] != one ) return this._connections[i] + } + + return null +} + +ShardingTest.prototype.getAnother = function( one ){ + if(this._connections.length < 2) + throw "getAnother() only works with multiple servers"; + + if ( one._mongo ) + one = one._mongo + + for(var i = 0; i < this._connections.length; i++){ + if(this._connections[i] == one) + return this._connections[(i + 1) % this._connections.length]; + } +} + +ShardingTest.prototype.getFirstOther = function( one ){ + for ( var i=0; i<this._connections.length; i++ ){ + if ( this._connections[i] != one ) + return this._connections[i]; + } + throw "impossible"; +} + +ShardingTest.prototype.stop = function(){ + for ( var i=0; i<this._mongos.length; i++ ){ + stopMongoProgram( 31000 - i - 1 ); + } + for ( var i=0; i<this._connections.length; i++){ + stopMongod( 30000 + i ); + } + if ( this._rs ){ + for ( var i=0; i<this._rs.length; i++ ){ + if( this._rs[i] ) this._rs[i].test.stopSet( 15 ); + } + } + if( this._otherParams.separateConfig ){ + for ( var i=0; i<this._configServers.length; i++ ){ + MongoRunner.stopMongod( this._configServers[i] ) + } + } + if ( this._alldbpaths ){ + for( i=0; i<this._alldbpaths.length; i++ ){ + resetDbpath( "/data/db/" + this._alldbpaths[i] ); + } + } + + var timeMillis = new Date().getTime() - this._startTime.getTime(); + + print('*** ShardingTest ' + this._testName + " completed successfully in " + ( timeMillis / 1000 ) + " seconds ***"); +} + +ShardingTest.prototype.adminCommand = function(cmd){ + var res = this.admin.runCommand( cmd ); + if ( res && res.ok == 1 ) + return true; + + throw "command " + tojson( cmd ) + " failed: " + tojson( res ); +} + +ShardingTest.prototype._rangeToString = function(r){ + return tojsononeline( r.min ) + " -> " + 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( "ShardingTest " + 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( "ShardingTest " + 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<this._connections.length; i++ ){ + var c = this._connections[i]; + out += " mongod " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n"; + } + for ( var i=0; i<this._mongos.length; i++ ){ + var c = this._mongos[i]; + out += " mongos " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n"; + } + + out += this.getChunksString( ns ); + + print( "ShardingTest " + out ); +} + +printShardingStatus = function( configDB , verbose ){ + if (configDB === undefined) + configDB = db.getSisterDB('config') + + var version = configDB.getCollection( "version" ).findOne(); + if ( version == null ){ + print( "printShardingStatus: this db does not have sharding enabled. be sure you are connecting to a mongos from the shell and not to a mongod." ); + return; + } + + var raw = ""; + var output = function(s){ + raw += s + "\n"; + } + output( "--- Sharding Status --- " ); + output( " sharding version: " + tojson( configDB.getCollection( "version" ).findOne() ) ); + + output( " shards:" ); + configDB.shards.find().sort( { _id : 1 } ).forEach( + function(z){ + output( "\t" + tojsononeline( z ) ); + } + ); + + output( " databases:" ); + configDB.databases.find().sort( { name : 1 } ).forEach( + function(db){ + output( "\t" + tojsononeline(db,"",true) ); + + if (db.partitioned){ + configDB.collections.find( { _id : new RegExp( "^" + + RegExp.escape(db._id) + "\\." ) } ). + sort( { _id : 1 } ).forEach( function( coll ){ + if ( coll.dropped == false ){ + output("\t\t" + coll._id + " chunks:"); + + res = configDB.chunks.group( { cond : { ns : coll._id } , key : { shard : 1 }, + reduce : function( doc , out ){ out.nChunks++; } , initial : { nChunks : 0 } } ); + var totalChunks = 0; + res.forEach( function(z){ + totalChunks += z.nChunks; + output( "\t\t\t\t" + z.shard + "\t" + z.nChunks ); + } ) + + if ( totalChunks < 20 || verbose ){ + configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach( + function(chunk){ + output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) + + " on : " + chunk.shard + " " + tojson( chunk.lastmod ) + " " + + ( chunk.jumbo ? "jumbo " : "" ) ); + } + ); + } + 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( "printShardingSizes : 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( "^" + + RegExp.escape(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<this._connections.length; i++ ) + if ( this._connections[i].getDB( dbName ).getCollection( collName ).count() > 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<this._connections.length; i++ ) + counts[i] = this._connections[i].getDB( dbName ).getCollection( collName ).count(); + return counts; +} + +ShardingTest.prototype.chunkCounts = function( collName , dbName ){ + dbName = dbName || "test"; + var x = {} + + s.config.shards.find().forEach( + function(z){ + x[z._id] = 0; + } + ); + + s.config.chunks.find( { ns : dbName + "." + collName } ).forEach( + function(z){ + if ( x[z.shard] ) + x[z.shard]++ + else + x[z.shard] = 1; + } + ); + return x; + +} + +ShardingTest.prototype.chunkDiff = function( collName , dbName ){ + var c = this.chunkCounts( collName , dbName ); + var min = 100000000; + var max = 0; + for ( var s in c ){ + if ( c[s] < min ) + min = c[s]; + if ( c[s] > max ) + max = c[s]; + } + print( "ShardingTest input: " + tojson( c ) + " min: " + min + " max: " + max ); + return max - min; +} + +ShardingTest.prototype.getShard = function( coll, query, includeEmpty ){ + var shards = this.getShards( coll, query, includeEmpty ) + assert.eq( shards.length, 1 ) + return shards[0] +} + +// Returns the shards on which documents matching a particular query reside +ShardingTest.prototype.getShards = function( coll, query, includeEmpty ){ + if( ! coll.getDB ) + coll = this.s.getCollection( coll ) + + var explain = coll.find( query ).explain() + var shards = [] + + if( explain.shards ){ + + for( var shardName in explain.shards ){ + for( var i = 0; i < explain.shards[shardName].length; i++ ){ + if( includeEmpty || ( explain.shards[shardName][i].n && explain.shards[shardName][i].n > 0 ) ) + shards.push( shardName ) + } + } + + } + + for( var i = 0; i < shards.length; i++ ){ + for( var j = 0; j < this._connections.length; j++ ){ + if ( connectionURLTheSame( this._connections[j] , shards[i] ) ){ + shards[i] = this._connections[j] + break; + } + } + } + + return shards +} + +ShardingTest.prototype.isSharded = function( collName ){ + + var collName = "" + collName + var dbName = undefined + + if( typeof collName.getCollectionNames == 'function' ){ + dbName = "" + collName + collName = undefined + } + + if( dbName ){ + var x = this.config.databases.findOne( { _id : dbname } ) + if( x ) return x.partitioned + else return false + } + + if( collName ){ + var x = this.config.collections.findOne( { _id : collName } ) + if( x ) return true + else return false + } + +} + +ShardingTest.prototype.shardGo = function( collName , key , split , move , dbName ){ + + split = ( split != false ? ( split || key ) : split ) + move = ( split != false && move != false ? ( move || split ) : false ) + + if( collName.getDB ) + dbName = "" + collName.getDB() + else dbName = dbName || "test"; + + var c = dbName + "." + collName; + if( collName.getDB ) + c = "" + collName + + var isEmpty = this.s.getCollection( c ).count() == 0 + + if( ! this.isSharded( dbName ) ) + this.s.adminCommand( { enableSharding : dbName } ) + + var result = this.s.adminCommand( { shardcollection : c , key : key } ) + if( ! result.ok ){ + printjson( result ) + assert( false ) + } + + if( split == false ) return + + result = this.s.adminCommand( { split : c , middle : split } ); + if( ! result.ok ){ + printjson( result ) + assert( false ) + } + + if( move == false ) return + + var result = null + for( var i = 0; i < 5; i++ ){ + result = this.s.adminCommand( { movechunk : c , find : move , to : this.getOther( this.getServer( dbName ) ).name } ); + if( result.ok ) break; + sleep( 5 * 1000 ); + } + printjson( result ) + assert( result.ok ) + +}; + +ShardingTest.prototype.shardColl = ShardingTest.prototype.shardGo + +ShardingTest.prototype.setBalancer = function( balancer ){ + if( balancer || balancer == undefined ){ + this.config.settings.update( { _id: "balancer" }, { $set : { stopped: false } } , true ) + } + else if( balancer == false ){ + this.config.settings.update( { _id: "balancer" }, { $set : { stopped: true } } , true ) + } +} + +ShardingTest.prototype.stopBalancer = function( timeout, interval ) { + this.setBalancer( false ) + + if( typeof db == "undefined" ) db = undefined + var oldDB = db + + db = this.config + sh.waitForBalancer( false, timeout, interval ) + db = oldDB +} + +ShardingTest.prototype.startBalancer = function( timeout, interval ) { + this.setBalancer( true ) + + if( typeof db == "undefined" ) db = undefined + var oldDB = db + + db = this.config + sh.waitForBalancer( true, timeout, interval ) + db = oldDB +} |