diff options
Diffstat (limited to 'shell/utils.js')
-rw-r--r-- | shell/utils.js | 284 |
1 files changed, 251 insertions, 33 deletions
diff --git a/shell/utils.js b/shell/utils.js index 6b52ab9..8380607 100644 --- a/shell/utils.js +++ b/shell/utils.js @@ -9,10 +9,24 @@ chatty = function(s){ friendlyEqual = function( a , b ){ if ( a == b ) return true; + + a = tojson(a,false,true); + b = tojson(b,false,true); - if ( tojson( a ) == tojson( b ) ) + if ( a == b ) return true; + var clean = function( s ){ + s = s.replace( /NumberInt\((\-?\d+)\)/g , "$1" ); + return s; + } + + a = clean(a); + b = clean(b); + + if ( a == b ) + return true; + return false; } @@ -35,10 +49,8 @@ doassert = function (msg) { assert = function( b , msg ){ if ( assert._debug && msg ) print( "in assert for: " + msg ); - if ( b ) - return; - + return; doassert( msg == undefined ? "assert failed" : "assert failed : " + msg ); } @@ -72,6 +84,26 @@ assert.neq = function( a , b , msg ){ doassert( "[" + a + "] != [" + b + "] are equal : " + msg ); } +assert.contains = function( o, arr, msg ){ + var wasIn = false + + if( ! arr.length ){ + for( i in arr ){ + wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) ) + return; + if( wasIn ) break + } + } + else { + for( var i = 0; i < arr.length; i++ ){ + wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) ) + if( wasIn ) break + } + } + + if( ! wasIn ) doassert( tojson( o ) + " was not in " + tojson( arr ) + " : " + msg ) +} + assert.repeat = function( f, msg, timeout, interval ) { if ( assert._debug && msg ) print( "in assert for: " + msg ); @@ -199,6 +231,18 @@ assert.gte = function( a , b , msg ){ doassert( a + " is not greater than or eq " + b + " : " + msg ); } +assert.between = function( a, b, c, msg, inclusive ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if( ( inclusive == undefined || inclusive == true ) && + a <= b && b <= c ) return; + else if( a < b && b < c ) return; + + doassert( b + " is not between " + a + " and " + c + " : " + msg ); +} + +assert.betweenIn = function( a, b, c, msg ){ assert.between( a, b, c, msg, true ) } +assert.betweenEx = function( a, b, c, msg ){ assert.between( a, b, c, msg, false ) } assert.close = function( a , b , msg , places ){ if (places === undefined) { @@ -226,6 +270,11 @@ Object.extend = function( dst , src , deep ){ return dst; } +Object.merge = function( dst, src, deep ){ + var clone = Object.extend( {}, dst, deep ) + return Object.extend( clone, src, deep ) +} + argumentsToArray = function( a ){ var arr = []; for ( var i=0; i<a.length; i++ ) @@ -370,20 +419,25 @@ Array.shuffle = function( arr ){ } -Array.tojson = function( a , indent ){ +Array.tojson = function( a , indent , nolint ){ + var lineEnding = nolint ? " " : "\n"; + if (!indent) indent = ""; + + if ( nolint ) + indent = ""; if (a.length == 0) { return "[ ]"; } - var s = "[\n"; + var s = "[" + lineEnding; indent += "\t"; for ( var i=0; i<a.length; i++){ - s += indent + tojson( a[i], indent ); + s += indent + tojson( a[i], indent , nolint ); if ( i < a.length - 1 ){ - s += ",\n"; + s += "," + lineEnding; } } if ( a.length == 0 ) { @@ -391,7 +445,7 @@ Array.tojson = function( a , indent ){ } indent = indent.substring(1); - s += "\n"+indent+"]"; + s += lineEnding+indent+"]"; return s; } @@ -459,6 +513,14 @@ NumberLong.prototype.tojson = function() { return this.toString(); } +if ( ! NumberInt.prototype ) { + NumberInt.prototype = {} +} + +NumberInt.prototype.tojson = function() { + return this.toString(); +} + if ( ! ObjectId.prototype ) ObjectId.prototype = {} @@ -533,16 +595,24 @@ if ( typeof( BinData ) != "undefined" ){ //return "BinData type: " + this.type + " len: " + this.len; return this.toString(); } + + BinData.prototype.subtype = function () { + return this.type; + } + + BinData.prototype.length = function () { + return this.len; + } } else { print( "warning: no BinData class" ); } -if ( typeof( UUID ) != "undefined" ){ +/*if ( typeof( UUID ) != "undefined" ){ UUID.prototype.tojson = function () { return this.toString(); } -} +}*/ if ( typeof _threadInject != "undefined" ){ print( "fork() available!" ); @@ -667,7 +737,9 @@ if ( typeof _threadInject != "undefined" ){ "jstests/killop.js", "jstests/run_program1.js", "jstests/notablescan.js", - "jstests/drop2.js"] ); + "jstests/drop2.js", + "jstests/dropdb_race.js", + "jstests/bench_test1.js"] ); // some tests can't be run in parallel with each other var serialTestsArr = [ "jstests/fsync.js", @@ -903,6 +975,35 @@ printjsononeline = function(x){ print( tojsononeline( x ) ); } +if ( typeof TestData == "undefined" ){ + TestData = undefined +} + +jsTestName = function(){ + if( TestData ) return TestData.testName + return "__unknown_name__" +} + +jsTestFile = function(){ + if( TestData ) return TestData.testFile + return "__unknown_file__" +} + +jsTestPath = function(){ + if( TestData ) return TestData.testPath + return "__unknown_path__" +} + +jsTestOptions = function(){ + if( TestData ) return { noJournal : TestData.noJournal, + noJournalPrealloc : TestData.noJournalPrealloc } + return {} +} + +testLog = function(x){ + print( jsTestFile() + " - " + x ) +} + shellPrintHelper = function (x) { if (typeof (x) == "undefined") { @@ -956,7 +1057,6 @@ shellAutocomplete = function (/*prefix*/){ // outer scope function called on ini builtinMethods[Mongo] = "find update insert remove".split(' '); builtinMethods[BinData] = "hex base64 length subtype".split(' '); - builtinMethods[NumberLong] = "toNumber".split(' '); var extraGlobals = "Infinity NaN undefined null true false decodeURI decodeURIComponent encodeURI encodeURIComponent escape eval isFinite isNaN parseFloat parseInt unescape Array Boolean Date Math Number RegExp String print load gc MinKey MaxKey Mongo NumberLong ObjectId DBPointer UUID BinData Map".split(' '); @@ -1017,7 +1117,7 @@ shellAutocomplete = function (/*prefix*/){ // outer scope function called on ini var p = possibilities[i]; if (typeof(curObj[p]) == "undefined" && curObj != global) continue; // extraGlobals aren't in the global object if (p.length == 0 || p.length < lastPrefix.length) continue; - if (isPrivate(p)) continue; + if (lastPrefix[0] != '_' && isPrivate(p)) continue; if (p.match(/^[0-9]+$/)) continue; // don't array number indexes if (p.substr(0, lastPrefix.length) != lastPrefix) continue; @@ -1046,7 +1146,7 @@ shellAutocomplete.showPrivate = false; // toggle to show (useful when working on shellHelper = function( command , rest , shouldPrint ){ command = command.trim(); - var args = rest.trim().replace(/;$/,"").split( "\s+" ); + var args = rest.trim().replace(/\s*;$/,"").split( "\s+" ); if ( ! shellHelper[command] ) throw "no command [" + command + "]"; @@ -1079,6 +1179,10 @@ shellHelper.it = function(){ shellHelper.show = function (what) { assert(typeof what == "string"); + var args = what.split( /\s+/ ); + what = args[0] + args = args.splice(1) + if (what == "profile") { if (db.system.profile.count() == 0) { print("db.system.profile is empty"); @@ -1087,7 +1191,32 @@ shellHelper.show = function (what) { } else { print(); - db.system.profile.find({ millis: { $gt: 0} }).sort({ $natural: -1 }).limit(5).forEach(function (x) { print("" + x.millis + "ms " + String(x.ts).substring(0, 24)); print(x.info); print("\n"); }) + db.system.profile.find({ millis: { $gt: 0} }).sort({ $natural: -1 }).limit(5).forEach( + function (x) { + print("" + x.op + "\t" + x.ns + " " + x.millis + "ms " + String(x.ts).substring(0, 24)); + var l = ""; + for ( var z in x ){ + if ( z == "op" || z == "ns" || z == "millis" || z == "ts" ) + continue; + + var val = x[z]; + var mytype = typeof(val); + + if ( mytype == "string" || + mytype == "number" ) + l += z + ":" + val + " "; + else if ( mytype == "object" ) + l += z + ":" + tojson(val ) + " "; + else if ( mytype == "boolean" ) + l += z + " "; + else + l += z + ":" + val + " "; + + } + print( l ); + print("\n"); + } + ) } return ""; } @@ -1117,6 +1246,27 @@ shellHelper.show = function (what) { //db.getMongo().getDBNames().sort().forEach(function (x) { print(x) }); return ""; } + + if (what == "log" ) { + var n = "global"; + if ( args.length > 0 ) + n = args[0] + + var res = db.adminCommand( { getLog : n } ) + for ( var i=0; i<res.log.length; i++){ + print( res.log[i] ) + } + return "" + } + + if (what == "logs" ) { + var res = db.adminCommand( { getLog : "*" } ) + for ( var i=0; i<res.names.length; i++){ + print( res.names[i] ) + } + return "" + } + throw "don't know how to show [" + what + "]"; @@ -1314,18 +1464,40 @@ rs.slaveOk = function () { return db.getMongo().setSlaveOk(); } rs.status = function () { return db._adminCommand("replSetGetStatus"); } rs.isMaster = function () { return db.isMaster(); } rs.initiate = function (c) { return db._adminCommand({ replSetInitiate: c }); } -rs.reconfig = function (cfg) { - cfg.version = rs.conf().version + 1; +rs._runCmd = function (c) { + // after the command, catch the disconnect and reconnect if necessary var res = null; try { - res = db.adminCommand({ replSetReconfig: cfg }); + res = db.adminCommand(c); } catch (e) { - print("shell got exception during reconfig: " + e); - print("in some circumstances, the primary steps down and closes connections on a reconfig"); + if (("" + e).indexOf("error doing query") >= 0) { + // closed connection. reconnect. + db.getLastErrorObj(); + var o = db.getLastErrorObj(); + if (o.ok) { + print("reconnected to server after rs command (which is normal)"); + } + else { + printjson(o); + } + } + else { + print("shell got exception during repl set operation: " + e); + print("in some circumstances, the primary steps down and closes connections on a reconfig"); + } + return ""; } return res; } +rs.reconfig = function (cfg, options) { + cfg.version = rs.conf().version + 1; + cmd = { replSetReconfig: cfg }; + for (var i in options) { + cmd[i] = options[i]; + } + return this._runCmd(cmd); +} rs.add = function (hostport, arb) { var cfg = hostport; @@ -1345,20 +1517,13 @@ rs.add = function (hostport, arb) { cfg.arbiterOnly = true; } c.members.push(cfg); - var res = null; - try { - res = db.adminCommand({ replSetReconfig: c }); - } - catch (e) { - print("shell got exception during reconfig: " + e); - print("in some circumstances, the primary steps down and closes connections on a reconfig"); - } - return res; + return this._runCmd({ replSetReconfig: c }); } -rs.stepDown = function (secs) { return db._adminCommand({ replSetStepDown:secs||60}); } +rs.stepDown = function (secs) { return db._adminCommand({ replSetStepDown:(secs === undefined) ? 60:secs}); } rs.freeze = function (secs) { return db._adminCommand({replSetFreeze:secs}); } rs.addArb = function (hn) { return this.add(hn, true); } rs.conf = function () { return db.getSisterDB("local").system.replset.findOne(); } +rs.config = function () { return rs.conf(); } rs.remove = function (hn) { var local = db.getSisterDB("local"); @@ -1377,6 +1542,41 @@ rs.remove = function (hn) { return "error: couldn't find "+hn+" in "+tojson(c.members); }; +rs.debug = {}; + +rs.debug.nullLastOpWritten = function(primary, secondary) { + var p = connect(primary+"/local"); + var s = connect(secondary+"/local"); + s.getMongo().setSlaveOk(); + + var secondToLast = s.oplog.rs.find().sort({$natural : -1}).limit(1).next(); + var last = p.runCommand({findAndModify : "oplog.rs", + query : {ts : {$gt : secondToLast.ts}}, + sort : {$natural : 1}, + update : {$set : {op : "n"}}}); + + if (!last.value.o || !last.value.o._id) { + print("couldn't find an _id?"); + } + else { + last.value.o = {_id : last.value.o._id}; + } + + print("nulling out this op:"); + printjson(last); +}; + +rs.debug.getLastOpWritten = function(server) { + var s = db.getSisterDB("local"); + if (server) { + s = connect(server+"/local"); + } + s.getMongo().setSlaveOk(); + + return s.oplog.rs.find().sort({$natural : -1}).limit(1).next(); +}; + + help = shellHelper.help = function (x) { if (x == "mr") { print("\nSee also http://www.mongodb.org/display/DOCS/MapReduce"); @@ -1408,6 +1608,17 @@ help = shellHelper.help = function (x) { print("\nNote: the REPL prompt only auto-reports getLastError() for the shell command line connection.\n"); return; } + else if (x == "keys") { + print("Tab completion and command history is available at the command prompt.\n"); + print("Some emacs keystrokes are available too:"); + print(" Ctrl-A start of line"); + print(" Ctrl-E end of line"); + print(" Ctrl-K del to end of line"); + print("\nMulti-line commands"); + print("You can enter a multi line javascript expression. If parens, braces, etc. are not closed, you will see a new line "); + print("beginning with '...' characters. Type the rest of your expression. Press Ctrl-C to abort the data entry if you"); + print("get stuck.\n"); + } else if (x == "misc") { print("\tb = new BinData(subtype,base64str) create a BSON BinData value"); print("\tb.subtype() the BinData subtype (0..255)"); @@ -1416,6 +1627,10 @@ help = shellHelper.help = function (x) { print("\tb.base64() the data as a base 64 encoded string"); print("\tb.toString()"); print(); + print("\tb = HexData(subtype,hexstr) create a BSON BinData value from a hex string"); + print("\tb = UUID(hexstr) create a BSON BinData value of UUID subtype"); + print("\tb = MD5(hexstr) create a BSON BinData value of MD5 subtype"); + print(); print("\to = new ObjectId() create a new ObjectId"); print("\to.getTimestamp() return timestamp derived from first 32 bits of the OID"); print("\to.isObjectId()"); @@ -1454,15 +1669,18 @@ help = shellHelper.help = function (x) { print("\t" + "db.help() help on db methods"); print("\t" + "db.mycoll.help() help on collection methods"); print("\t" + "rs.help() help on replica set methods"); - print("\t" + "help connect connecting to a db help"); print("\t" + "help admin administrative help"); + print("\t" + "help connect connecting to a db help"); + print("\t" + "help keys key shortcuts"); print("\t" + "help misc misc things to know"); - print("\t" + "help mr mapreduce help"); + print("\t" + "help mr mapreduce"); print(); print("\t" + "show dbs show database names"); print("\t" + "show collections show collections in current database"); print("\t" + "show users show users in current database"); print("\t" + "show profile show most recent system.profile entries with time >= 1ms"); + print("\t" + "show logs show the accessible logger names"); + print("\t" + "show log [name] prints out the last segment of log in memory, 'global' is default"); print("\t" + "use <db_name> set current database"); print("\t" + "db.foo.find() list objects in collection foo"); print("\t" + "db.foo.find( { a : 1 } ) list objects in foo where a == 1"); |