From 7645618fd3914cb8a20561625913c20d49504a49 Mon Sep 17 00:00:00 2001 From: Antonin Kral Date: Wed, 11 Aug 2010 12:38:57 +0200 Subject: Imported Upstream version 1.6.0 --- shell/collection.js | 83 +- shell/db.js | 108 +- shell/dbshell.cpp | 190 ++- shell/mongo.js | 5 +- shell/mongo_vstudio.cpp | 3295 ++++++++++++++++++++------------------ shell/msvc/mongo.ico | Bin 0 -> 1078 bytes shell/msvc/mongo.sln | 20 + shell/msvc/mongo.vcxproj | 253 +++ shell/msvc/mongo.vcxproj.filters | 262 +++ shell/query.js | 77 +- shell/servers.js | 774 ++++++++- shell/shell_utils.cpp | 899 +++++++++++ shell/utils.cpp | 713 --------- shell/utils.js | 271 +++- 14 files changed, 4507 insertions(+), 2443 deletions(-) create mode 100755 shell/msvc/mongo.ico create mode 100644 shell/msvc/mongo.sln create mode 100644 shell/msvc/mongo.vcxproj create mode 100644 shell/msvc/mongo.vcxproj.filters create mode 100644 shell/shell_utils.cpp delete mode 100644 shell/utils.cpp (limited to 'shell') diff --git a/shell/collection.js b/shell/collection.js index edb07ae..68ee03d 100644 --- a/shell/collection.js +++ b/shell/collection.js @@ -1,5 +1,6 @@ -// collection.js - +// collection.js - DBCollection support in the mongo shell +// db.colName is a DBCollection object +// or db["colName"] if ( ( typeof DBCollection ) == "undefined" ){ DBCollection = function( mongo , db , shortName , fullName ){ @@ -26,39 +27,42 @@ DBCollection.prototype.getName = function(){ return this._shortName; } -DBCollection.prototype.help = function() { +DBCollection.prototype.help = function () { + var shortName = this.getName(); print("DBCollection help"); - print("\tdb.foo.count()"); - print("\tdb.foo.dataSize()"); - print("\tdb.foo.distinct( key ) - eg. db.foo.distinct( 'x' )"); - print("\tdb.foo.drop() drop the collection"); - print("\tdb.foo.dropIndex(name)"); - print("\tdb.foo.dropIndexes()"); - print("\tdb.foo.ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups"); - print("\tdb.foo.reIndex()"); - print("\tdb.foo.find( [query] , [fields]) - first parameter is an optional query filter. second parameter is optional set of fields to return."); - print("\t e.g. db.foo.find( { x : 77 } , { name : 1 , x : 1 } )"); - print("\tdb.foo.find(...).count()"); - print("\tdb.foo.find(...).limit(n)"); - print("\tdb.foo.find(...).skip(n)"); - print("\tdb.foo.find(...).sort(...)"); - print("\tdb.foo.findOne([query])"); - print("\tdb.foo.findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )"); - print("\tdb.foo.getDB() get DB object associated with collection"); - print("\tdb.foo.getIndexes()"); - print("\tdb.foo.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )"); - print("\tdb.foo.mapReduce( mapFunction , reduceFunction , )"); - print("\tdb.foo.remove(query)"); - print("\tdb.foo.renameCollection( newName , ) renames the collection."); - print("\tdb.foo.runCommand( name , ) runs a db command with the given name where the 1st param is the colleciton name" ); - print("\tdb.foo.save(obj)"); - print("\tdb.foo.stats()"); - print("\tdb.foo.storageSize() - includes free space allocated to this collection"); - print("\tdb.foo.totalIndexSize() - size in bytes of all the indexes"); - print("\tdb.foo.totalSize() - storage allocated for all data and indexes"); - print("\tdb.foo.update(query, object[, upsert_bool, multi_bool])"); - print("\tdb.foo.validate() - SLOW"); - print("\tdb.foo.getShardVersion() - only for use with sharding"); + print("\tdb." + shortName + ".find().help() - show DBCursor help"); + print("\tdb." + shortName + ".count()"); + print("\tdb." + shortName + ".dataSize()"); + print("\tdb." + shortName + ".distinct( key ) - eg. db." + shortName + ".distinct( 'x' )"); + print("\tdb." + shortName + ".drop() drop the collection"); + print("\tdb." + shortName + ".dropIndex(name)"); + print("\tdb." + shortName + ".dropIndexes()"); + print("\tdb." + shortName + ".ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups"); + print("\tdb." + shortName + ".reIndex()"); + print("\tdb." + shortName + ".find( [query] , [fields]) - first parameter is an optional query filter. second parameter is optional set of fields to return."); + print("\t e.g. db." + shortName + ".find( { x : 77 } , { name : 1 , x : 1 } )"); + print("\tdb." + shortName + ".find(...).count()"); + print("\tdb." + shortName + ".find(...).limit(n)"); + print("\tdb." + shortName + ".find(...).skip(n)"); + print("\tdb." + shortName + ".find(...).sort(...)"); + print("\tdb." + shortName + ".findOne([query])"); + print("\tdb." + shortName + ".findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )"); + print("\tdb." + shortName + ".getDB() get DB object associated with collection"); + print("\tdb." + shortName + ".getIndexes()"); + print("\tdb." + shortName + ".group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )"); + print("\tdb." + shortName + ".mapReduce( mapFunction , reduceFunction , )"); + print("\tdb." + shortName + ".remove(query)"); + print("\tdb." + shortName + ".renameCollection( newName , ) renames the collection."); + print("\tdb." + shortName + ".runCommand( name , ) runs a db command with the given name where the first param is the collection name"); + print("\tdb." + shortName + ".save(obj)"); + print("\tdb." + shortName + ".stats()"); + print("\tdb." + shortName + ".storageSize() - includes free space allocated to this collection"); + print("\tdb." + shortName + ".totalIndexSize() - size in bytes of all the indexes"); + print("\tdb." + shortName + ".totalSize() - storage allocated for all data and indexes"); + print("\tdb." + shortName + ".update(query, object[, upsert_bool, multi_bool])"); + print("\tdb." + shortName + ".validate() - SLOW"); + print("\tdb." + shortName + ".getShardVersion() - only for use with sharding"); + return __magicNoPrint; } DBCollection.prototype.getFullName = function(){ @@ -333,7 +337,7 @@ DBCollection.prototype.findAndModify = function(args){ var ret = this._db.runCommand( cmd ); if ( ! ret.ok ){ if (ret.errmsg == "No matching object found"){ - return {}; + return null; } throw "findAndModifyFailed failed: " + tojson( ret.errmsg ); } @@ -351,8 +355,10 @@ DBCollection.prototype.validate = function() { res.valid = false; - if ( res.result ){ - var str = "-" + tojson( res.result ); + var raw = res.result || res.raw; + + if ( raw ){ + var str = "-" + tojson( raw ); res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) ); var p = /lastExtentSize:(\d+)/; @@ -572,6 +578,3 @@ DBCollection.prototype.toString = function(){ DBCollection.prototype.tojson = DBCollection.prototype.toString; DBCollection.prototype.shellPrint = DBCollection.prototype.toString; - - - diff --git a/shell/db.js b/shell/db.js index bdb1153..8299695 100644 --- a/shell/db.js +++ b/shell/db.js @@ -259,7 +259,7 @@ DB.prototype.help = function() { print("\tdb.commandHelp(name) returns the help for the command"); print("\tdb.copyDatabase(fromdb, todb, fromhost)"); print("\tdb.createCollection(name, { size : ..., capped : ..., max : ... } )"); - print("\tdb.currentOp() displays the current operation in the db" ); + print("\tdb.currentOp() displays the current operation in the db"); print("\tdb.dropDatabase()"); print("\tdb.eval(func, args) run code server-side"); print("\tdb.getCollection(cname) same as db['cname'] or db.cname"); @@ -271,10 +271,12 @@ DB.prototype.help = function() { print("\tdb.getName()"); print("\tdb.getPrevError()"); print("\tdb.getProfilingLevel()"); - print("\tdb.getReplicationInfo()"); - print("\tdb.getSisterDB(name) get the db at the same server as this onew"); - print("\tdb.killOp(opid) kills the current operation in the db" ); - print("\tdb.printCollectionStats()" ); + print("\tdb.getReplicationInfo()"); + print("\tdb.getSisterDB(name) get the db at the same server as this one"); + print("\tdb.isMaster() check replica primary status"); + print("\tdb.killOp(opid) kills the current operation in the db"); + print("\tdb.listCommands() lists all the db commands"); + print("\tdb.printCollectionStats()"); print("\tdb.printReplicationInfo()"); print("\tdb.printSlaveReplicationInfo()"); print("\tdb.printShardingStatus()"); @@ -286,7 +288,10 @@ DB.prototype.help = function() { print("\tdb.setProfilingLevel(level,) 0=off 1=slow 2=all"); print("\tdb.shutdownServer()"); print("\tdb.stats()"); - print("\tdb.version() current version of the server" ); + print("\tdb.version() current version of the server"); + print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server"); + + return __magicNoPrint; } DB.prototype.printCollectionStats = function(){ @@ -309,9 +314,10 @@ DB.prototype.printCollectionStats = function(){ *

Levels :

*
    *
  • 0=off
  • - *
  • 1=log very slow (>100ms) operations
  • + *
  • 1=log very slow operations; optional argument slowms specifies slowness threshold
  • *
  • 2=log all
  • * @param {String} level Desired level of profiling + * @param {String} slowms For slow logging, query duration that counts as slow (default 100ms) * @return SOMETHING_FIXME or null on error */ DB.prototype.setProfilingLevel = function(level,slowms) { @@ -471,14 +477,21 @@ DB.prototype.forceError = function(){ return this.runCommand( { forceerror : 1 } ); } -DB.prototype.getLastError = function(){ - var res = this.runCommand( { getlasterror : 1 } ); +DB.prototype.getLastError = function( w , wtimeout ){ + var res = this.getLastErrorObj( w , wtimeout ); if ( ! res.ok ) throw "getlasterror failed: " + tojson( res ); return res.err; } -DB.prototype.getLastErrorObj = function(){ - var res = this.runCommand( { getlasterror : 1 } ); +DB.prototype.getLastErrorObj = function( w , wtimeout ){ + var cmd = { getlasterror : 1 }; + if ( w ){ + cmd.w = w; + if ( wtimeout ) + cmd.wtimeout = wtimeout; + } + var res = this.runCommand( cmd ); + if ( ! res.ok ) throw "getlasterror failed: " + tojson( res ); return res; @@ -502,17 +515,17 @@ DB.prototype.getCollectionNames = function(){ var nsLength = this._name.length + 1; - this.getCollection( "system.namespaces" ).find().sort({name:1}).forEach( - function(z){ - var name = z.name; - - if ( name.indexOf( "$" ) >= 0 && name != "local.oplog.$main" ) - return; - - all.push( name.substring( nsLength ) ); - } - ); - return all; + var c = this.getCollection( "system.namespaces" ).find(); + while ( c.hasNext() ){ + var name = c.next().name; + + if ( name.indexOf( "$" ) >= 0 && name.indexOf( ".oplog.$" ) < 0 ) + continue; + + all.push( name.substring( nsLength ) ); + } + + return all.sort(); } DB.prototype.tojson = function(){ @@ -521,7 +534,9 @@ DB.prototype.tojson = function(){ DB.prototype.toString = function(){ return this._name; -} +} + +DB.prototype.isMaster = function () { return this.runCommand("isMaster"); } DB.prototype.currentOp = function(){ return db.$cmd.sys.inprog.findOne(); @@ -615,13 +630,19 @@ DB.prototype.printReplicationInfo = function() { DB.prototype.printSlaveReplicationInfo = function() { function g(x) { + assert( x , "how could this be null (printSlaveReplicationInfo gx)" ) print("source: " + x.host); - var st = new Date( DB.tsToSeconds( x.syncedTo ) * 1000 ); - var now = new Date(); - print("syncedTo: " + st.toString() ); - var ago = (now-st)/1000; - var hrs = Math.round(ago/36)/100; - print(" = " + Math.round(ago) + "secs ago (" + hrs + "hrs)"); + if ( x.syncedTo ){ + var st = new Date( DB.tsToSeconds( x.syncedTo ) * 1000 ); + var now = new Date(); + print("\t syncedTo: " + st.toString() ); + var ago = (now-st)/1000; + var hrs = Math.round(ago/36)/100; + print("\t\t = " + Math.round(ago) + "secs ago (" + hrs + "hrs)"); + } + else { + print( "\t doing initial sync" ); + } } var L = this.getSisterDB("local"); if( L.sources.count() == 0 ) { @@ -639,10 +660,39 @@ DB.prototype.serverStatus = function(){ return this._adminCommand( "serverStatus" ); } +DB.prototype.serverCmdLineOpts = function(){ + return this._adminCommand( "getCmdLineOpts" ); +} + DB.prototype.version = function(){ return this.serverBuildInfo().version; } +DB.prototype.listCommands = function(){ + var x = this.runCommand( "listCommands" ); + for ( var name in x.commands ){ + var c = x.commands[name]; + + var s = name + ": "; + + switch ( c.lockType ){ + case -1: s += "read-lock"; break; + case 0: s += "no-lock"; break; + case 1: s += "write-lock"; break; + default: s += c.lockType; + } + + if (c.adminOnly) s += " adminOnly "; + if (c.adminOnly) s += " slaveOk "; + + s += "\n "; + s += c.help.replace(/\n/g, '\n '); + s += "\n"; + + print( s ); + } +} + DB.prototype.printShardingStatus = function(){ printShardingStatus( this.getSisterDB( "config" ) ); } diff --git a/shell/dbshell.cpp b/shell/dbshell.cpp index cad3698..2bd8973 100644 --- a/shell/dbshell.cpp +++ b/shell/dbshell.cpp @@ -15,9 +15,15 @@ * limitations under the License. */ - +#include "pch.h" #include +#if defined(_WIN32) +# if defined(USE_READLINE) +# define USE_READLINE_STATIC +# endif +#endif + #ifdef USE_READLINE #include #include @@ -30,18 +36,87 @@ jmp_buf jbuf; #include "../util/unittest.h" #include "../db/cmdline.h" #include "utils.h" +#include "../util/password.h" +#include "../util/version.h" +#include "../util/goodies.h" using namespace std; using namespace boost::filesystem; +using mongo::BSONObj; +using mongo::BSONObjBuilder; +using mongo::BSONObjIterator; +using mongo::BSONElement; + string historyFile; bool gotInterrupted = 0; bool inMultiLine = 0; +static volatile bool atPrompt = false; // can eval before getting to prompt +bool autoKillOp = false; + -#if defined(USE_READLINE) && !defined(__freebsd__) && !defined(_WIN32) +#if defined(USE_READLINE) && !defined(__freebsd__) && !defined(__openbsd__) && !defined(_WIN32) #define CTRLC_HANDLE #endif +mongo::Scope * shellMainScope; + +void generateCompletions( const string& prefix , vector& all ){ + if ( prefix.find( '"' ) != string::npos ) + return; + shellMainScope->exec( "shellAutocomplete( \"" + prefix + "\" );" , "autocomplete help" , false , true , false ); + + BSONObjBuilder b; + shellMainScope->append( b , "" , "__autocomplete__" ); + BSONObj res = b.obj(); + BSONObj arr = res.firstElement().Obj(); + + BSONObjIterator i(arr); + while ( i.more() ){ + BSONElement e = i.next(); + all.push_back( e.String() ); + } + +} + +#ifdef USE_READLINE +static char** completionHook(const char* text , int start ,int end ){ + static map m; + + vector all; + + if ( start == 0 ){ + generateCompletions( string(text,end) , all ); + } + + if ( all.size() == 0 ){ + rl_bind_key('\t',0); + return 0; + } + + string longest = all[0]; + for ( vector::iterator i=all.begin(); i!=all.end(); ++i ){ + string s = *i; + for ( unsigned j=0; j> yn; + + if (yn != 'y' && yn != 'Y') + return; + } + + vector< string > uris; for( map< const void*, string >::iterator i = mongo::shellUtils::_allMyUris.begin(); i != mongo::shellUtils::_allMyUris.end(); ++i ) uris.push_back( i->second ); @@ -95,6 +195,7 @@ void killOps() { } void quitNicely( int sig ){ + mongo::goingAway = true; if ( sig == SIGINT && inMultiLine ){ gotInterrupted = 1; return; @@ -105,14 +206,28 @@ void quitNicely( int sig ){ shellHistoryDone(); exit(0); } +#else +void quitNicely( int sig ){ + mongo::goingAway = true; + //killOps(); + shellHistoryDone(); + exit(0); +} #endif char * shellReadline( const char * prompt , int handlesigint = 0 ){ + atPrompt = true; #ifdef USE_READLINE + rl_bind_key('\t',rl_complete); + + #ifdef CTRLC_HANDLE - if ( ! handlesigint ) - return readline( prompt ); + if ( ! handlesigint ){ + char* ret = readline( prompt ); + atPrompt = false; + return ret; + } if ( setjmp( jbuf ) ){ gotInterrupted = 1; sigrelse(SIGINT); @@ -124,13 +239,16 @@ char * shellReadline( const char * prompt , int handlesigint = 0 ){ char * ret = readline( prompt ); signal( SIGINT , quitNicely ); + atPrompt = false; return ret; #else - printf("%s", prompt); + printf("%s", prompt); cout.flush(); char * buf = new char[1024]; char * l = fgets( buf , 1024 , stdin ); int len = strlen( buf ); - buf[len-1] = 0; + if ( len ) + buf[len-1] = 0; + atPrompt = false; return l; #endif } @@ -173,8 +291,8 @@ string fixHost( string url , string host , string port ){ if ( url.find( "." ) != string::npos ) return url + "/test"; - if ( url.find( ":" ) != string::npos && - isdigit( url[url.find(":")+1] ) ) + if ( url.rfind( ":" ) != string::npos && + isdigit( url[url.rfind(":")+1] ) ) return url + "/test"; } return url; @@ -191,6 +309,10 @@ string fixHost( string url , string host , string port ){ string newurl = host; if ( port.size() > 0 ) newurl += ":" + port; + else if (host.find(':') == string::npos){ + // need to add port with IPv6 addresses + newurl += ":27017"; + } newurl += "/" + url; @@ -283,7 +405,12 @@ bool fileExists( string file ){ } } +namespace mongo { + extern bool isShell; +} + int _main(int argc, char* argv[]) { + mongo::isShell = true; setupSignals(); mongo::shellUtils::RecordMyLocation( argv[ 0 ] ); @@ -314,15 +441,18 @@ int _main(int argc, char* argv[]) { ("host", po::value(&dbhost), "server to connect to") ("eval", po::value(&script), "evaluate javascript") ("username,u", po::value(&username), "username for authentication") - ("password,p", po::value(&password), "password for authentication") + ("password,p", new mongo::PasswordValue(&password), + "password for authentication") ("help,h", "show this usage information") ("version", "show version information") + ("ipv6", "enable IPv6 support (disabled by default)") ; hidden_options.add_options() ("dbaddress", po::value(), "dbaddress") ("files", po::value< vector >(), "files") ("nokillop", "nokillop") // for testing, kill op will also be disabled automatically if the tests starts a mongo program + ("autokillop", "autokillop") // for testing, will kill op without prompting ; positional_options.add("dbaddress", 1); @@ -350,6 +480,16 @@ int _main(int argc, char* argv[]) { return mongo::EXIT_BADOPTIONS; } + // hide password from ps output + for (int i=0; i < (argc-1); ++i){ + if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--password")){ + char* arg = argv[i+1]; + while (*arg){ + *arg++ = 'x'; + } + } + } + if (params.count("shell")) { runShell = true; } @@ -373,6 +513,9 @@ int _main(int argc, char* argv[]) { if (params.count("nokillop")) { mongo::shellUtils::_nokillop = true; } + if (params.count("autokillop")) { + autoKillOp = true; + } /* This is a bit confusing, here are the rules: * @@ -395,6 +538,9 @@ int _main(int argc, char* argv[]) { } } } + if (params.count("ipv6")){ + mongo::enableIPv6(); + } if ( ! mongo::cmdLine.quiet ) cout << "MongoDB shell version: " << mongo::versionString << endl; @@ -402,7 +548,7 @@ int _main(int argc, char* argv[]) { mongo::UnitTest::runTests(); if ( !nodb ) { // connect to db - if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl; + //if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl; stringstream ss; if ( mongo::cmdLine.quiet ) @@ -411,6 +557,11 @@ int _main(int argc, char* argv[]) { mongo::shellUtils::_dbConnect = ss.str(); + if ( params.count( "password" ) + && ( password.empty() ) ) { + password = mongo::askPassword(); + } + if ( username.size() && password.size() ){ stringstream ss; ss << "if ( ! db.auth( \"" << username << "\" , \"" << password << "\" ) ){ throw 'login failed'; }"; @@ -423,6 +574,10 @@ int _main(int argc, char* argv[]) { mongo::ScriptEngine::setup(); mongo::globalScriptEngine->setScopeInitCallback( mongo::shellUtils::initScope ); auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() ); + shellMainScope = scope.get(); + + if( runShell ) + cout << "type \"help\" for help" << endl; if ( !script.empty() ) { mongo::shellUtils::MongoProgramScope s; @@ -452,8 +607,6 @@ int _main(int argc, char* argv[]) { shellHistoryInit(); - cout << "type \"help\" for help" << endl; - //v8::Handle shellHelper = baseContext_->Global()->Get( v8::String::New( "shellHelper" ) )->ToObject(); while ( 1 ){ @@ -510,8 +663,8 @@ int _main(int argc, char* argv[]) { if ( ! wascmd ){ try { - scope->exec( code.c_str() , "(shell)" , false , true , false ); - scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false ); + if ( scope->exec( code.c_str() , "(shell)" , false , true , false ) ) + scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false ); } catch ( std::exception& e ){ cout << "error:" << e.what() << endl; @@ -525,6 +678,7 @@ int _main(int argc, char* argv[]) { shellHistoryDone(); } + mongo::goingAway = true; return 0; } diff --git a/shell/mongo.js b/shell/mongo.js index acd028b..7353ca5 100644 --- a/shell/mongo.js +++ b/shell/mongo.js @@ -56,8 +56,9 @@ Mongo.prototype.getCollection = function(ns){ } Mongo.prototype.toString = function(){ - return "mongo connection to " + this.host; + return "connection to " + this.host; } +Mongo.prototype.tojson = Mongo.prototype.toString; connect = function( url , user , pass ){ chatty( "connecting to: " + url ) @@ -65,7 +66,7 @@ connect = function( url , user , pass ){ if ( user && ! pass ) throw "you specified a user and not a password. either you need a password, or you're using the old connect api"; - var idx = url.indexOf( "/" ); + var idx = url.lastIndexOf( "/" ); var db; diff --git a/shell/mongo_vstudio.cpp b/shell/mongo_vstudio.cpp index f88b3c2..06384ca 100644 --- a/shell/mongo_vstudio.cpp +++ b/shell/mongo_vstudio.cpp @@ -1,1529 +1,1766 @@ -const char * jsconcatcode = -"__quiet = false;\n" - "chatty = function(s){\n" - "if ( ! __quiet )\n" - "print( s );}\n" - "friendlyEqual = function( a , b ){\n" - "if ( a == b )\n" - "return true;\n" - "if ( tojson( a ) == tojson( b ) )\n" - "return true;\n" - "return false;}\n" - "doassert = function( msg ){\n" - "print( \"assert: \" + msg );\n" - "throw msg;}\n" - "assert = function( b , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( b )\n" - "return;\n" - "doassert( \"assert failed : \" + msg );}\n" - "assert._debug = false;\n" - "assert.eq = function( a , b , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( a == b )\n" - "return;\n" - "if ( ( a != null && b != null ) && friendlyEqual( a , b ) )\n" - "return;\n" - "doassert( \"[\" + tojson( a ) + \"] != [\" + tojson( b ) + \"] are not equal : \" + msg );}\n" - "assert.neq = function( a , b , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( a != b )\n" - "return;\n" - "doassert( \"[\" + a + \"] != [\" + b + \"] are equal : \" + msg );}\n" - "assert.soon = function( f, msg, timeout, interval ) {\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "var start = new Date();\n" - "timeout = timeout || 30000;\n" - "interval = interval || 200;\n" - "var last;\n" - "while( 1 ) {\n" - "if ( typeof( f ) == \"string\" ){\n" - "if ( eval( f ) )\n" - "return;}\n" - "else {\n" - "if ( f() )\n" - "return;}\n" - "if ( ( new Date() ).getTime() - start.getTime() > timeout )\n" - "doassert( \"assert.soon failed: \" + f + \", msg:\" + msg );\n" - "sleep( interval );}}\n" - "assert.throws = function( func , params , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "try {\n" - "func.apply( null , params );}\n" - "catch ( e ){\n" - "return e;}\n" - "doassert( \"did not throw exception: \" + msg );}\n" - "assert.commandWorked = function( res , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( res.ok == 1 )\n" - "return;\n" - "doassert( \"command failed: \" + tojson( res ) + \" : \" + msg );}\n" - "assert.commandFailed = function( res , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( res.ok == 0 )\n" - "return;\n" - "doassert( \"command worked when it should have failed: \" + tojson( res ) + \" : \" + msg );}\n" - "assert.isnull = function( what , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( what == null )\n" - "return;\n" - "doassert( \"supposed to null (\" + ( msg || \"\" ) + \") was: \" + tojson( what ) );}\n" - "assert.lt = function( a , b , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( a < b )\n" - "return;\n" - "doassert( a + \" is not less than \" + b + \" : \" + msg );}\n" - "assert.gt = function( a , b , msg ){\n" - "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" - "if ( a > b )\n" - "return;\n" - "doassert( a + \" is not greater than \" + b + \" : \" + msg );}\n" - "assert.close = function( a , b , msg ){\n" - "var diff = Math.abs( (a-b)/((a+b)/2) );\n" - "if ( diff < .001 )\n" - "return;\n" - "doassert( a + \" is not close to \" + b + \" diff: \" + diff + \" : \" + msg );}\n" - "Object.extend = function( dst , src , deep ){\n" - "for ( var k in src ){\n" - "var v = src[k];\n" - "if ( deep && typeof(v) == \"object\" ){\n" - "v = Object.extend( typeof ( v.length ) == \"number\" ? [] : {} , v , true );}\n" - "dst[k] = v;}\n" - "return dst;}\n" - "argumentsToArray = function( a ){\n" - "var arr = [];\n" - "for ( var i=0; i>>>>>>>>>>>>>> skipping \" + x.name);\n" - "return;}\n" - "params[ i % n ].push( x.name );\n" - "++i;}\n" - ");\n" - "params[ 0 ] = Array.shuffle( params[ 0 ] );\n" - "for( var i in params ) {\n" - "params[ i ].unshift( i );}\n" - "return params;}\n" - "ParallelTester.fileTester = function() {\n" - "var args = argumentsToArray( arguments );\n" - "var suite = args.shift();\n" - "args.forEach(\n" - "function( x ) {\n" - "print(\" S\" + suite + \" Test : \" + x + \" ...\");\n" - "var time = Date.timeFunc( function() { load(x); }, 1);\n" - "print(\" S\" + suite + \" Test : \" + x + \" \" + time + \"ms\" );}\n" - ");}\n" - "assert.parallelTests = function( params, msg, newScopes ) {\n" - "newScopes = newScopes || false;\n" - "var wrapper = function( fun, argv ) {\n" - "eval (\n" - "\"var z = function() {\" +\n" - "\"var __parallelTests__fun = \" + fun.toString() + \";\" +\n" - "\"var __parallelTests__argv = \" + tojson( argv ) + \";\" +\n" - "\"var __parallelTests__passed = false;\" +\n" - "\"try {\" +\n" - "\"__parallelTests__fun.apply( 0, __parallelTests__argv );\" +\n" - "\"__parallelTests__passed = true;\" +\n" - "\"} catch ( e ) {\" +\n" - "\"print( e );\" +\n" - "\"}\" +\n" - "\"return __parallelTests__passed;\" +\n" - "\"}\"\n" - ");\n" - "return z;}\n" - "var runners = new Array();\n" - "for( var i in params ) {\n" - "var param = params[ i ];\n" - "var test = param.shift();\n" - "var t;\n" - "if ( newScopes )\n" - "t = new ScopedThread( wrapper( test, param ) );\n" - "else\n" - "t = new Thread( wrapper( test, param ) );\n" - "runners.push( t );}\n" - "runners.forEach( function( x ) { x.start(); } );\n" - "var nFailed = 0;\n" - "runners.forEach( function( x ) { if( !x.returnData() ) { ++nFailed; } } );\n" - "assert.eq( 0, nFailed, msg );}}\n" - "tojson = function( x, indent , nolint ){\n" - "if ( x === null )\n" - "return \"null\";\n" - "if ( x === undefined )\n" - "return \"undefined\";\n" - "if (!indent)\n" - "indent = \"\";\n" - "switch ( typeof x ){\n" - "case \"string\": {\n" - "var s = \"\\\"\";\n" - "for ( var i=0; i= 1ms\");\n" - "print( \"\\t\" + \"use set curent database to \" );\n" - "print( \"\\t\" + \"db.help() help on DB methods\");\n" - "print( \"\\t\" + \"db.foo.help() help on collection methods\");\n" - "print( \"\\t\" + \"db.foo.find() list objects in collection foo\" );\n" - "print( \"\\t\" + \"db.foo.find( { a : 1 } ) list objects in foo where a == 1\" );\n" - "print( \"\\t\" + \"it result of the last line evaluated; use to further iterate\");}\n" - "shellHelper.use = function( dbname ){\n" - "db = db.getMongo().getDB( dbname );\n" - "print( \"switched to db \" + db.getName() );}\n" - "shellHelper.it = function(){\n" - "if ( typeof( ___it___ ) == \"undefined\" || ___it___ == null ){\n" - "print( \"no cursor\" );\n" - "return;}\n" - "shellPrintHelper( ___it___ );}\n" - "shellHelper.show = function( what ){\n" - "assert( typeof what == \"string\" );\n" - "if( what == \"profile\" ) {\n" - "if( db.system.profile.count() == 0 ) {\n" - "print(\"db.system.profile is empty\");\n" - "print(\"Use db.setProfilingLevel(2) will enable profiling\");\n" - "print(\"Use db.system.profile.find() to show raw profile entries\");}\n" - "else {\n" - "print();\n" - "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\");} )}\n" - "return \"\";}\n" - "if ( what == \"users\" ){\n" - "db.system.users.find().forEach( printjson );\n" - "return \"\";}\n" - "if ( what == \"collections\" || what == \"tables\" ) {\n" - "db.getCollectionNames().forEach( function(x){print(x)} );\n" - "return \"\";}\n" - "if ( what == \"dbs\" ) {\n" - "db.getMongo().getDBNames().sort().forEach( function(x){print(x)} );\n" - "return \"\";}\n" - "throw \"don't know how to show [\" + what + \"]\";}\n" - "if ( typeof( Map ) == \"undefined\" ){\n" - "Map = function(){\n" - "this._data = {};}}\n" - "Map.hash = function( val ){\n" - "if ( ! val )\n" - "return val;\n" - "switch ( typeof( val ) ){\n" - "case 'string':\n" - "case 'number':\n" - "case 'date':\n" - "return val.toString();\n" - "case 'object':\n" - "case 'array':\n" - "var s = \"\";\n" - "for ( var k in val ){\n" - "s += k + val[k];}\n" - "return s;}\n" - "throw \"can't hash : \" + typeof( val );}\n" - "Map.prototype.put = function( key , value ){\n" - "var o = this._get( key );\n" - "var old = o.value;\n" - "o.value = value;\n" - "return old;}\n" - "Map.prototype.get = function( key ){\n" - "return this._get( key ).value;}\n" - "Map.prototype._get = function( key ){\n" - "var h = Map.hash( key );\n" - "var a = this._data[h];\n" - "if ( ! a ){\n" - "a = [];\n" - "this._data[h] = a;}\n" - "for ( var i=0; i= 0 , \"unexpected error: \" + tojson( e ) );\n" - "print( \"server should be down...\" );}}\n" - "\n" - "DB.prototype.cloneDatabase = function(from) {\n" - "assert( isString(from) && from.length );\n" - "return this._dbCommand( { clone: from } );}\n" - "\n" - "DB.prototype.cloneCollection = function(from, collection, query) {\n" - "assert( isString(from) && from.length );\n" - "assert( isString(collection) && collection.length );\n" - "collection = this._name + \".\" + collection;\n" - "query = query || {};\n" - "return this._dbCommand( { cloneCollection:collection, from:from, query:query } );}\n" - "\n" - "DB.prototype.copyDatabase = function(fromdb, todb, fromhost, username, password) {\n" - "assert( isString(fromdb) && fromdb.length );\n" - "assert( isString(todb) && todb.length );\n" - "fromhost = fromhost || \"\";\n" - "if ( username && password ) {\n" - "var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );\n" - "return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );\n" - "} else {\n" - "return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );}}\n" - "\n" - "DB.prototype.repairDatabase = function() {\n" - "return this._dbCommand( { repairDatabase: 1 } );}\n" - "DB.prototype.help = function() {\n" - "print(\"DB methods:\");\n" - "print(\"\\tdb.addUser(username, password[, readOnly=false])\");\n" - "print(\"\\tdb.auth(username, password)\");\n" - "print(\"\\tdb.cloneDatabase(fromhost)\");\n" - "print(\"\\tdb.commandHelp(name) returns the help for the command\");\n" - "print(\"\\tdb.copyDatabase(fromdb, todb, fromhost)\");\n" - "print(\"\\tdb.createCollection(name, { size : ..., capped : ..., max : ... } )\");\n" - "print(\"\\tdb.currentOp() displays the current operation in the db\" );\n" - "print(\"\\tdb.dropDatabase()\");\n" - "print(\"\\tdb.eval(func, args) run code server-side\");\n" - "print(\"\\tdb.getCollection(cname) same as db['cname'] or db.cname\");\n" - "print(\"\\tdb.getCollectionNames()\");\n" - "print(\"\\tdb.getLastError() - just returns the err msg string\");\n" - "print(\"\\tdb.getLastErrorObj() - return full status object\");\n" - "print(\"\\tdb.getMongo() get the server connection object\");\n" - "print(\"\\tdb.getMongo().setSlaveOk() allow this connection to read from the nonmaster member of a replica pair\");\n" - "print(\"\\tdb.getName()\");\n" - "print(\"\\tdb.getPrevError()\");\n" - "print(\"\\tdb.getProfilingLevel()\");\n" - "print(\"\\tdb.getReplicationInfo()\");\n" - "print(\"\\tdb.getSisterDB(name) get the db at the same server as this onew\");\n" - "print(\"\\tdb.killOp(opid) kills the current operation in the db\" );\n" - "print(\"\\tdb.printCollectionStats()\" );\n" - "print(\"\\tdb.printReplicationInfo()\");\n" - "print(\"\\tdb.printSlaveReplicationInfo()\");\n" - "print(\"\\tdb.printShardingStatus()\");\n" - "print(\"\\tdb.removeUser(username)\");\n" - "print(\"\\tdb.repairDatabase()\");\n" - "print(\"\\tdb.resetError()\");\n" - "print(\"\\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }\");\n" - "print(\"\\tdb.setProfilingLevel(level,) 0=off 1=slow 2=all\");\n" - "print(\"\\tdb.shutdownServer()\");\n" - "print(\"\\tdb.stats()\");\n" - "print(\"\\tdb.version() current version of the server\" );}\n" - "DB.prototype.printCollectionStats = function(){\n" - "var mydb = this;\n" - "this.getCollectionNames().forEach(\n" - "function(z){\n" - "print( z );\n" - "printjson( mydb.getCollection(z).stats() );\n" - "print( \"---\" );}\n" - ");}\n" - "\n" - "DB.prototype.setProfilingLevel = function(level,slowms) {\n" - "if (level < 0 || level > 2) {\n" - "throw { dbSetProfilingException : \"input level \" + level + \" is out of range [0..2]\" };}\n" - "var cmd = { profile: level };\n" - "if ( slowms )\n" - "cmd[\"slowms\"] = slowms;\n" - "return this._dbCommand( cmd );}\n" - "\n" - "DB.prototype.eval = function(jsfunction) {\n" - "var cmd = { $eval : jsfunction };\n" - "if ( arguments.length > 1 ) {\n" - "cmd.args = argumentsToArray( arguments ).slice(1);}\n" - "var res = this._dbCommand( cmd );\n" - "if (!res.ok)\n" - "throw tojson( res );\n" - "return res.retval;}\n" - "DB.prototype.dbEval = DB.prototype.eval;\n" - "\n" - "DB.prototype.groupeval = function(parmsObj) {\n" - "var groupFunction = function() {\n" - "var parms = args[0];\n" - "var c = db[parms.ns].find(parms.cond||{});\n" - "var map = new Map();\n" - "var pks = parms.key ? Object.keySet( parms.key ) : null;\n" - "var pkl = pks ? pks.length : 0;\n" - "var key = {};\n" - "while( c.hasNext() ) {\n" - "var obj = c.next();\n" - "if ( pks ) {\n" - "for( var i=0; i, nPrev : , ok : 1 }\n" - "result.err will be null if no error has occurred.\n" - "*/\n" - "DB.prototype.getPrevError = function(){\n" - "return this.runCommand( { getpreverror : 1 } );}\n" - "DB.prototype.getCollectionNames = function(){\n" - "var all = [];\n" - "var nsLength = this._name.length + 1;\n" - "this.getCollection( \"system.namespaces\" ).find().sort({name:1}).forEach(\n" - "function(z){\n" - "var name = z.name;\n" - "if ( name.indexOf( \"$\" ) >= 0 && name != \"local.oplog.$main\" )\n" - "return;\n" - "all.push( name.substring( nsLength ) );}\n" - ");\n" - "return all;}\n" - "DB.prototype.tojson = function(){\n" - "return this._name;}\n" - "DB.prototype.toString = function(){\n" - "return this._name;}\n" - "DB.prototype.currentOp = function(){\n" - "return db.$cmd.sys.inprog.findOne();}\n" - "DB.prototype.currentOP = DB.prototype.currentOp;\n" - "DB.prototype.killOp = function(op) {\n" - "if( !op )\n" - "throw \"no opNum to kill specified\";\n" - "return db.$cmd.sys.killop.findOne({'op':op});}\n" - "DB.prototype.killOP = DB.prototype.killOp;\n" - "DB.tsToSeconds = function(x){\n" - "if ( x.t && x.i )\n" - "return x.t / 1000;\n" - "return x / 4294967296;}\n" - "\n" - "DB.prototype.getReplicationInfo = function() {\n" - "var db = this.getSisterDB(\"local\");\n" - "var result = { };\n" - "var ol = db.system.namespaces.findOne({name:\"local.oplog.$main\"});\n" - "if( ol && ol.options ) {\n" - "result.logSizeMB = ol.options.size / 1000 / 1000;\n" - "} else {\n" - "result.errmsg = \"local.oplog.$main, or its options, not found in system.namespaces collection (not --master?)\";\n" - "return result;}\n" - "var firstc = db.oplog.$main.find().sort({$natural:1}).limit(1);\n" - "var lastc = db.oplog.$main.find().sort({$natural:-1}).limit(1);\n" - "if( !firstc.hasNext() || !lastc.hasNext() ) {\n" - "result.errmsg = \"objects not found in local.oplog.$main -- is this a new and empty db instance?\";\n" - "result.oplogMainRowCount = db.oplog.$main.count();\n" - "return result;}\n" - "var first = firstc.next();\n" - "var last = lastc.next();\n" - "{\n" - "var tfirst = first.ts;\n" - "var tlast = last.ts;\n" - "if( tfirst && tlast ) {\n" - "tfirst = DB.tsToSeconds( tfirst );\n" - "tlast = DB.tsToSeconds( tlast );\n" - "result.timeDiff = tlast - tfirst;\n" - "result.timeDiffHours = Math.round(result.timeDiff / 36)/100;\n" - "result.tFirst = (new Date(tfirst*1000)).toString();\n" - "result.tLast = (new Date(tlast*1000)).toString();\n" - "result.now = Date();}\n" - "else {\n" - "result.errmsg = \"ts element not found in oplog objects\";}}\n" - "return result;}\n" - "DB.prototype.printReplicationInfo = function() {\n" - "var result = this.getReplicationInfo();\n" - "if( result.errmsg ) {\n" - "print(tojson(result));\n" - "return;}\n" - "print(\"configured oplog size: \" + result.logSizeMB + \"MB\");\n" - "print(\"log length start to end: \" + result.timeDiff + \"secs (\" + result.timeDiffHours + \"hrs)\");\n" - "print(\"oplog first event time: \" + result.tFirst);\n" - "print(\"oplog last event time: \" + result.tLast);\n" - "print(\"now: \" + result.now);}\n" - "DB.prototype.printSlaveReplicationInfo = function() {\n" - "function g(x) {\n" - "print(\"source: \" + x.host);\n" - "var st = new Date( DB.tsToSeconds( x.syncedTo ) * 1000 );\n" - "var now = new Date();\n" - "print(\"syncedTo: \" + st.toString() );\n" - "var ago = (now-st)/1000;\n" - "var hrs = Math.round(ago/36)/100;\n" - "print(\" = \" + Math.round(ago) + \"secs ago (\" + hrs + \"hrs)\");}\n" - "var L = this.getSisterDB(\"local\");\n" - "if( L.sources.count() == 0 ) {\n" - "print(\"local.sources is empty; is this db a --slave?\");\n" - "return;}\n" - "L.sources.find().forEach(g);}\n" - "DB.prototype.serverBuildInfo = function(){\n" - "return this._adminCommand( \"buildinfo\" );}\n" - "DB.prototype.serverStatus = function(){\n" - "return this._adminCommand( \"serverStatus\" );}\n" - "DB.prototype.version = function(){\n" - "return this.serverBuildInfo().version;}\n" - "DB.prototype.printShardingStatus = function(){\n" - "printShardingStatus( this.getSisterDB( \"config\" ) );}\n" - "if ( typeof Mongo == \"undefined\" ){\n" - "Mongo = function( host ){\n" - "this.init( host );}}\n" - "if ( ! Mongo.prototype ){\n" - "throw \"Mongo.prototype not defined\";}\n" - "if ( ! Mongo.prototype.find )\n" - "Mongo.prototype.find = function( ns , query , fields , limit , skip ){ throw \"find not implemented\"; }\n" - "if ( ! Mongo.prototype.insert )\n" - "Mongo.prototype.insert = function( ns , obj ){ throw \"insert not implemented\"; }\n" - "if ( ! Mongo.prototype.remove )\n" - "Mongo.prototype.remove = function( ns , pattern ){ throw \"remove not implemented;\" }\n" - "if ( ! Mongo.prototype.update )\n" - "Mongo.prototype.update = function( ns , query , obj , upsert ){ throw \"update not implemented;\" }\n" - "if ( typeof mongoInject == \"function\" ){\n" - "mongoInject( Mongo.prototype );}\n" - "Mongo.prototype.setSlaveOk = function() {\n" - "this.slaveOk = true;}\n" - "Mongo.prototype.getDB = function( name ){\n" - "return new DB( this , name );}\n" - "Mongo.prototype.getDBs = function(){\n" - "var res = this.getDB( \"admin\" ).runCommand( { \"listDatabases\" : 1 } );\n" - "assert( res.ok == 1 , \"listDatabases failed:\" + tojson( res ) );\n" - "return res;}\n" - "Mongo.prototype.getDBNames = function(){\n" - "return this.getDBs().databases.map(\n" - "function(z){\n" - "return z.name;}\n" - ");}\n" - "Mongo.prototype.getCollection = function(ns){\n" - "var idx = ns.indexOf( \".\" );\n" - "if ( idx < 0 )\n" - "throw \"need . in ns\";\n" - "var db = ns.substring( 0 , idx );\n" - "var c = ns.substring( idx + 1 );\n" - "return this.getDB( db ).getCollection( c );}\n" - "Mongo.prototype.toString = function(){\n" - "return \"mongo connection to \" + this.host;}\n" - "connect = function( url , user , pass ){\n" - "chatty( \"connecting to: \" + url )\n" - "if ( user && ! pass )\n" - "throw \"you specified a user and not a password. either you need a password, or you're using the old connect api\";\n" - "var idx = url.indexOf( \"/\" );\n" - "var db;\n" - "if ( idx < 0 )\n" - "db = new Mongo().getDB( url );\n" - "else\n" - "db = new Mongo( url.substring( 0 , idx ) ).getDB( url.substring( idx + 1 ) );\n" - "if ( user && pass ){\n" - "if ( ! db.auth( user , pass ) ){\n" - "throw \"couldn't login\";}}\n" - "return db;}\n" - "MR = {};\n" - "MR.init = function(){\n" - "$max = 0;\n" - "$arr = [];\n" - "emit = MR.emit;\n" - "$numEmits = 0;\n" - "$numReduces = 0;\n" - "$numReducesToDB = 0;\n" - "gc();}\n" - "MR.cleanup = function(){\n" - "MR.init();\n" - "gc();}\n" - "MR.emit = function(k,v){\n" - "$numEmits++;\n" - "var num = nativeHelper.apply( get_num_ , [ k ] );\n" - "var data = $arr[num];\n" - "if ( ! data ){\n" - "data = { key : k , values : new Array(1000) , count : 0 };\n" - "$arr[num] = data;}\n" - "data.values[data.count++] = v;\n" - "$max = Math.max( $max , data.count );}\n" - "MR.doReduce = function( useDB ){\n" - "$numReduces++;\n" - "if ( useDB )\n" - "$numReducesToDB++;\n" - "$max = 0;\n" - "for ( var i=0; i<$arr.length; i++){\n" - "var data = $arr[i];\n" - "if ( ! data )\n" - "continue;\n" - "if ( useDB ){\n" - "var x = tempcoll.findOne( { _id : data.key } );\n" - "if ( x ){\n" - "data.values[data.count++] = x.value;}}\n" - "var r = $reduce( data.key , data.values.slice( 0 , data.count ) );\n" - "if ( r && r.length && r[0] ){\n" - "data.values = r;\n" - "data.count = r.length;}\n" - "else{\n" - "data.values[0] = r;\n" - "data.count = 1;}\n" - "$max = Math.max( $max , data.count );\n" - "if ( useDB ){\n" - "if ( data.count == 1 ){\n" - "tempcoll.save( { _id : data.key , value : data.values[0] } );}\n" - "else {\n" - "tempcoll.save( { _id : data.key , value : data.values.slice( 0 , data.count ) } );}}}}\n" - "MR.check = function(){\n" - "if ( $max < 2000 && $arr.length < 1000 ){\n" - "return 0;}\n" - "MR.doReduce();\n" - "if ( $max < 2000 && $arr.length < 1000 ){\n" - "return 1;}\n" - "MR.doReduce( true );\n" - "$arr = [];\n" - "$max = 0;\n" - "reset_num();\n" - "gc();\n" - "return 2;}\n" - "MR.finalize = function(){\n" - "tempcoll.find().forEach(\n" - "function(z){\n" - "z.value = $finalize( z._id , z.value );\n" - "tempcoll.save( z );}\n" - ");}\n" - "if ( typeof DBQuery == \"undefined\" ){\n" - "DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip , batchSize ){\n" - "this._mongo = mongo;\n" - "this._db = db;\n" - "this._collection = collection;\n" - "this._ns = ns;\n" - "this._query = query || {};\n" - "this._fields = fields;\n" - "this._limit = limit || 0;\n" - "this._skip = skip || 0;\n" - "this._batchSize = batchSize || 0;\n" - "this._cursor = null;\n" - "this._numReturned = 0;\n" - "this._special = false;}\n" - "print( \"DBQuery probably won't have array access \" );}\n" - "DBQuery.prototype.help = function(){\n" - "print( \"DBQuery help\" );\n" - "print( \"\\t.sort( {...} )\" )\n" - "print( \"\\t.limit( n )\" )\n" - "print( \"\\t.skip( n )\" )\n" - "print( \"\\t.count() - total # of objects matching query, ignores skip,limit\" )\n" - "print( \"\\t.size() - total # of objects cursor would return skip,limit effect this\" )\n" - "print( \"\\t.explain()\" )\n" - "print( \"\\t.forEach( func )\" )\n" - "print( \"\\t.map( func )\" )}\n" - "DBQuery.prototype.clone = function(){\n" - "var q = new DBQuery( this._mongo , this._db , this._collection , this._ns ,\n" - "this._query , this._fields ,\n" - "this._limit , this._skip , this._batchSize );\n" - "q._special = this._special;\n" - "return q;}\n" - "DBQuery.prototype._ensureSpecial = function(){\n" - "if ( this._special )\n" - "return;\n" - "var n = { query : this._query };\n" - "this._query = n;\n" - "this._special = true;}\n" - "DBQuery.prototype._checkModify = function(){\n" - "if ( this._cursor )\n" - "throw \"query already executed\";}\n" - "DBQuery.prototype._exec = function(){\n" - "if ( ! this._cursor ){\n" - "assert.eq( 0 , this._numReturned );\n" - "this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip , this._batchSize );\n" - "this._cursorSeen = 0;}\n" - "return this._cursor;}\n" - "DBQuery.prototype.limit = function( limit ){\n" - "this._checkModify();\n" - "this._limit = limit;\n" - "return this;}\n" - "DBQuery.prototype.batchSize = function( batchSize ){\n" - "this._checkModify();\n" - "this._batchSize = batchSize;\n" - "return this;}\n" - "DBQuery.prototype.skip = function( skip ){\n" - "this._checkModify();\n" - "this._skip = skip;\n" - "return this;}\n" - "DBQuery.prototype.hasNext = function(){\n" - "this._exec();\n" - "if ( this._limit > 0 && this._cursorSeen >= this._limit )\n" - "return false;\n" - "var o = this._cursor.hasNext();\n" - "return o;}\n" - "DBQuery.prototype.next = function(){\n" - "this._exec();\n" - "var o = this._cursor.hasNext();\n" - "if ( o )\n" - "this._cursorSeen++;\n" - "else\n" - "throw \"error hasNext: \" + o;\n" - "var ret = this._cursor.next();\n" - "if ( ret.$err && this._numReturned == 0 && ! this.hasNext() )\n" - "throw \"error: \" + tojson( ret );\n" - "this._numReturned++;\n" - "return ret;}\n" - "DBQuery.prototype.toArray = function(){\n" - "if ( this._arr )\n" - "return this._arr;\n" - "var a = [];\n" - "while ( this.hasNext() )\n" - "a.push( this.next() );\n" - "this._arr = a;\n" - "return a;}\n" - "DBQuery.prototype.count = function( applySkipLimit ){\n" - "var cmd = { count: this._collection.getName() };\n" - "if ( this._query ){\n" - "if ( this._special )\n" - "cmd.query = this._query.query;\n" - "else\n" - "cmd.query = this._query;}\n" - "cmd.fields = this._fields || {};\n" - "if ( applySkipLimit ){\n" - "if ( this._limit )\n" - "cmd.limit = this._limit;\n" - "if ( this._skip )\n" - "cmd.skip = this._skip;}\n" - "var res = this._db.runCommand( cmd );\n" - "if( res && res.n != null ) return res.n;\n" - "throw \"count failed: \" + tojson( res );}\n" - "DBQuery.prototype.size = function(){\n" - "return this.count( true );}\n" - "DBQuery.prototype.countReturn = function(){\n" - "var c = this.count();\n" - "if ( this._skip )\n" - "c = c - this._skip;\n" - "if ( this._limit > 0 && this._limit < c )\n" - "return this._limit;\n" - "return c;}\n" - "\n" - "DBQuery.prototype.itcount = function(){\n" - "var num = 0;\n" - "while ( this.hasNext() ){\n" - "num++;\n" - "this.next();}\n" - "return num;}\n" - "DBQuery.prototype.length = function(){\n" - "return this.toArray().length;}\n" - "DBQuery.prototype._addSpecial = function( name , value ){\n" - "this._ensureSpecial();\n" - "this._query[name] = value;\n" - "return this;}\n" - "DBQuery.prototype.sort = function( sortBy ){\n" - "return this._addSpecial( \"orderby\" , sortBy );}\n" - "DBQuery.prototype.hint = function( hint ){\n" - "return this._addSpecial( \"$hint\" , hint );}\n" - "DBQuery.prototype.min = function( min ) {\n" - "return this._addSpecial( \"$min\" , min );}\n" - "DBQuery.prototype.max = function( max ) {\n" - "return this._addSpecial( \"$max\" , max );}\n" - "DBQuery.prototype.forEach = function( func ){\n" - "while ( this.hasNext() )\n" - "func( this.next() );}\n" - "DBQuery.prototype.map = function( func ){\n" - "var a = [];\n" - "while ( this.hasNext() )\n" - "a.push( func( this.next() ) );\n" - "return a;}\n" - "DBQuery.prototype.arrayAccess = function( idx ){\n" - "return this.toArray()[idx];}\n" - "DBQuery.prototype.explain = function(){\n" - "var n = this.clone();\n" - "n._ensureSpecial();\n" - "n._query.$explain = true;\n" - "n._limit = n._limit * -1;\n" - "return n.next();}\n" - "DBQuery.prototype.snapshot = function(){\n" - "this._ensureSpecial();\n" - "this._query.$snapshot = true;\n" - "return this;}\n" - "DBQuery.prototype.shellPrint = function(){\n" - "try {\n" - "var n = 0;\n" - "while ( this.hasNext() && n < 20 ){\n" - "var s = tojson( this.next() , \"\" , true );\n" - "print( s );\n" - "n++;}\n" - "if ( this.hasNext() ){\n" - "print( \"has more\" );\n" - "___it___ = this;}\n" - "else {\n" - "___it___ = null;}}\n" - "catch ( e ){\n" - "print( e );}}\n" - "DBQuery.prototype.toString = function(){\n" - "return \"DBQuery: \" + this._ns + \" -> \" + tojson( this.query );}\n" - "if ( ( typeof DBCollection ) == \"undefined\" ){\n" - "DBCollection = function( mongo , db , shortName , fullName ){\n" - "this._mongo = mongo;\n" - "this._db = db;\n" - "this._shortName = shortName;\n" - "this._fullName = fullName;\n" - "this.verify();}}\n" - "DBCollection.prototype.verify = function(){\n" - "assert( this._fullName , \"no fullName\" );\n" - "assert( this._shortName , \"no shortName\" );\n" - "assert( this._db , \"no db\" );\n" - "assert.eq( this._fullName , this._db._name + \".\" + this._shortName , \"name mismatch\" );\n" - "assert( this._mongo , \"no mongo in DBCollection\" );}\n" - "DBCollection.prototype.getName = function(){\n" - "return this._shortName;}\n" - "DBCollection.prototype.help = function() {\n" - "print(\"DBCollection help\");\n" - "print(\"\\tdb.foo.count()\");\n" - "print(\"\\tdb.foo.dataSize()\");\n" - "print(\"\\tdb.foo.distinct( key ) - eg. db.foo.distinct( 'x' )\");\n" - "print(\"\\tdb.foo.drop() drop the collection\");\n" - "print(\"\\tdb.foo.dropIndex(name)\");\n" - "print(\"\\tdb.foo.dropIndexes()\");\n" - "print(\"\\tdb.foo.ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups\");\n" - "print(\"\\tdb.foo.reIndex()\");\n" - "print(\"\\tdb.foo.find( [query] , [fields]) - first parameter is an optional query filter. second parameter is optional set of fields to return.\");\n" - "print(\"\\t e.g. db.foo.find( { x : 77 } , { name : 1 , x : 1 } )\");\n" - "print(\"\\tdb.foo.find(...).count()\");\n" - "print(\"\\tdb.foo.find(...).limit(n)\");\n" - "print(\"\\tdb.foo.find(...).skip(n)\");\n" - "print(\"\\tdb.foo.find(...).sort(...)\");\n" - "print(\"\\tdb.foo.findOne([query])\");\n" - "print(\"\\tdb.foo.findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )\");\n" - "print(\"\\tdb.foo.getDB() get DB object associated with collection\");\n" - "print(\"\\tdb.foo.getIndexes()\");\n" - "print(\"\\tdb.foo.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )\");\n" - "print(\"\\tdb.foo.mapReduce( mapFunction , reduceFunction , )\");\n" - "print(\"\\tdb.foo.remove(query)\");\n" - "print(\"\\tdb.foo.renameCollection( newName , ) renames the collection.\");\n" - "print(\"\\tdb.foo.runCommand( name , ) runs a db command with the given name where the 1st param is the colleciton name\" );\n" - "print(\"\\tdb.foo.save(obj)\");\n" - "print(\"\\tdb.foo.stats()\");\n" - "print(\"\\tdb.foo.storageSize() - includes free space allocated to this collection\");\n" - "print(\"\\tdb.foo.totalIndexSize() - size in bytes of all the indexes\");\n" - "print(\"\\tdb.foo.totalSize() - storage allocated for all data and indexes\");\n" - "print(\"\\tdb.foo.update(query, object[, upsert_bool, multi_bool])\");\n" - "print(\"\\tdb.foo.validate() - SLOW\");\n" - "print(\"\\tdb.foo.getShardVersion() - only for use with sharding\");}\n" - "DBCollection.prototype.getFullName = function(){\n" - "return this._fullName;}\n" - "DBCollection.prototype.getDB = function(){\n" - "return this._db;}\n" - "DBCollection.prototype._dbCommand = function( cmd , params ){\n" - "if ( typeof( cmd ) == \"object\" )\n" - "return this._db._dbCommand( cmd );\n" - "var c = {};\n" - "c[cmd] = this.getName();\n" - "if ( params )\n" - "Object.extend( c , params );\n" - "return this._db._dbCommand( c );}\n" - "DBCollection.prototype.runCommand = DBCollection.prototype._dbCommand;\n" - "DBCollection.prototype._massageObject = function( q ){\n" - "if ( ! q )\n" - "return {};\n" - "var type = typeof q;\n" - "if ( type == \"function\" )\n" - "return { $where : q };\n" - "if ( q.isObjectId )\n" - "return { _id : q };\n" - "if ( type == \"object\" )\n" - "return q;\n" - "if ( type == \"string\" ){\n" - "if ( q.length == 24 )\n" - "return { _id : q };\n" - "return { $where : q };}\n" - "throw \"don't know how to massage : \" + type;}\n" - "DBCollection.prototype._validateObject = function( o ){\n" - "if ( o._ensureSpecial && o._checkModify )\n" - "throw \"can't save a DBQuery object\";}\n" - "DBCollection._allowedFields = { $id : 1 , $ref : 1 };\n" - "DBCollection.prototype._validateForStorage = function( o ){\n" - "this._validateObject( o );\n" - "for ( var k in o ){\n" - "if ( k.indexOf( \".\" ) >= 0 ) {\n" - "throw \"can't have . in field names [\" + k + \"]\" ;}\n" - "if ( k.indexOf( \"$\" ) == 0 && ! DBCollection._allowedFields[k] ) {\n" - "throw \"field names cannot start with $ [\" + k + \"]\";}\n" - "if ( o[k] !== null && typeof( o[k] ) === \"object\" ) {\n" - "this._validateForStorage( o[k] );}}\n" - "};\n" - "DBCollection.prototype.find = function( query , fields , limit , skip ){\n" - "return new DBQuery( this._mongo , this._db , this ,\n" - "this._fullName , this._massageObject( query ) , fields , limit , skip );}\n" - "DBCollection.prototype.findOne = function( query , fields ){\n" - "var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , -1 , 0 , 0 );\n" - "if ( ! cursor.hasNext() )\n" - "return null;\n" - "var ret = cursor.next();\n" - "if ( cursor.hasNext() ) throw \"findOne has more than 1 result!\";\n" - "if ( ret.$err )\n" - "throw \"error \" + tojson( ret );\n" - "return ret;}\n" - "DBCollection.prototype.insert = function( obj , _allow_dot ){\n" - "if ( ! obj )\n" - "throw \"no object passed to insert!\";\n" - "if ( ! _allow_dot ) {\n" - "this._validateForStorage( obj );}\n" - "if ( typeof( obj._id ) == \"undefined\" ){\n" - "var tmp = obj;\n" - "obj = {_id: new ObjectId()};\n" - "for (var key in tmp){\n" - "obj[key] = tmp[key];}}\n" - "this._mongo.insert( this._fullName , obj );\n" - "return obj._id;}\n" - "DBCollection.prototype.remove = function( t ){\n" - "this._mongo.remove( this._fullName , this._massageObject( t ) );}\n" - "DBCollection.prototype.update = function( query , obj , upsert , multi ){\n" - "assert( query , \"need a query\" );\n" - "assert( obj , \"need an object\" );\n" - "this._validateObject( obj );\n" - "this._mongo.update( this._fullName , query , obj , upsert ? true : false , multi ? true : false );}\n" - "DBCollection.prototype.save = function( obj ){\n" - "if ( obj == null || typeof( obj ) == \"undefined\" )\n" - "throw \"can't save a null\";\n" - "if ( typeof( obj._id ) == \"undefined\" ){\n" - "obj._id = new ObjectId();\n" - "return this.insert( obj );}\n" - "else {\n" - "return this.update( { _id : obj._id } , obj , true );}}\n" - "DBCollection.prototype._genIndexName = function( keys ){\n" - "var name = \"\";\n" - "for ( var k in keys ){\n" - "var v = keys[k];\n" - "if ( typeof v == \"function\" )\n" - "continue;\n" - "if ( name.length > 0 )\n" - "name += \"_\";\n" - "name += k + \"_\";\n" - "if ( typeof v == \"number\" )\n" - "name += v;}\n" - "return name;}\n" - "DBCollection.prototype._indexSpec = function( keys, options ) {\n" - "var ret = { ns : this._fullName , key : keys , name : this._genIndexName( keys ) };\n" - "if ( ! options ){}\n" - "else if ( typeof ( options ) == \"string\" )\n" - "ret.name = options;\n" - "else if ( typeof ( options ) == \"boolean\" )\n" - "ret.unique = true;\n" - "else if ( typeof ( options ) == \"object\" ){\n" - "if ( options.length ){\n" - "var nb = 0;\n" - "for ( var i=0; i 0 ) {\n" - "ret.unique = true;}\n" - "if ( nTrue > 1 ) {\n" - "ret.dropDups = true;}}\n" - "*/\n" - "return ret;}\n" - "DBCollection.prototype.createIndex = function( keys , options ){\n" - "var o = this._indexSpec( keys, options );\n" - "this._db.getCollection( \"system.indexes\" ).insert( o , true );}\n" - "DBCollection.prototype.ensureIndex = function( keys , options ){\n" - "var name = this._indexSpec( keys, options ).name;\n" - "this._indexCache = this._indexCache || {};\n" - "if ( this._indexCache[ name ] ){\n" - "return;}\n" - "this.createIndex( keys , options );\n" - "if ( this.getDB().getLastError() == \"\" ) {\n" - "this._indexCache[name] = true;}}\n" - "DBCollection.prototype.resetIndexCache = function(){\n" - "this._indexCache = {};}\n" - "DBCollection.prototype.reIndex = function() {\n" - "return this._db.runCommand({ reIndex: this.getName() });}\n" - "DBCollection.prototype.dropIndexes = function(){\n" - "this.resetIndexCache();\n" - "var res = this._db.runCommand( { deleteIndexes: this.getName(), index: \"*\" } );\n" - "assert( res , \"no result from dropIndex result\" );\n" - "if ( res.ok )\n" - "return res;\n" - "if ( res.errmsg.match( /not found/ ) )\n" - "return res;\n" - "throw \"error dropping indexes : \" + tojson( res );}\n" - "DBCollection.prototype.drop = function(){\n" - "this.resetIndexCache();\n" - "var ret = this._db.runCommand( { drop: this.getName() } );\n" - "if ( ! ret.ok ){\n" - "if ( ret.errmsg == \"ns not found\" )\n" - "return false;\n" - "throw \"drop failed: \" + tojson( ret );}\n" - "return true;}\n" - "DBCollection.prototype.findAndModify = function(args){\n" - "var cmd = { findandmodify: this.getName() };\n" - "for (var key in args){\n" - "cmd[key] = args[key];}\n" - "var ret = this._db.runCommand( cmd );\n" - "if ( ! ret.ok ){\n" - "if (ret.errmsg == \"No matching object found\"){\n" - "return {};}\n" - "throw \"findAndModifyFailed failed: \" + tojson( ret.errmsg );}\n" - "return ret.value;}\n" - "DBCollection.prototype.renameCollection = function( newName , dropTarget ){\n" - "return this._db._adminCommand( { renameCollection : this._fullName ,\n" - "to : this._db._name + \".\" + newName ,\n" - "dropTarget : dropTarget } )}\n" - "DBCollection.prototype.validate = function() {\n" - "var res = this._db.runCommand( { validate: this.getName() } );\n" - "res.valid = false;\n" - "if ( res.result ){\n" - "var str = \"-\" + tojson( res.result );\n" - "res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) );\n" - "var p = /lastExtentSize:(\\d+)/;\n" - "var r = p.exec( str );\n" - "if ( r ){\n" - "res.lastExtentSize = Number( r[1] );}}\n" - "return res;}\n" - "DBCollection.prototype.getShardVersion = function(){\n" - "return this._db._adminCommand( { getShardVersion : this._fullName } );}\n" - "DBCollection.prototype.getIndexes = function(){\n" - "return this.getDB().getCollection( \"system.indexes\" ).find( { ns : this.getFullName() } ).toArray();}\n" - "DBCollection.prototype.getIndices = DBCollection.prototype.getIndexes;\n" - "DBCollection.prototype.getIndexSpecs = DBCollection.prototype.getIndexes;\n" - "DBCollection.prototype.getIndexKeys = function(){\n" - "return this.getIndexes().map(\n" - "function(i){\n" - "return i.key;}\n" - ");}\n" - "DBCollection.prototype.count = function( x ){\n" - "return this.find( x ).count();}\n" - "\n" - "DBCollection.prototype.clean = function() {\n" - "return this._dbCommand( { clean: this.getName() } );}\n" - "\n" - "DBCollection.prototype.dropIndex = function(index) {\n" - "assert(index , \"need to specify index to dropIndex\" );\n" - "if ( ! isString( index ) && isObject( index ) )\n" - "index = this._genIndexName( index );\n" - "var res = this._dbCommand( \"deleteIndexes\" ,{ index: index } );\n" - "this.resetIndexCache();\n" - "return res;}\n" - "DBCollection.prototype.copyTo = function( newName ){\n" - "return this.getDB().eval(\n" - "function( collName , newName ){\n" - "var from = db[collName];\n" - "var to = db[newName];\n" - "to.ensureIndex( { _id : 1 } );\n" - "var count = 0;\n" - "var cursor = from.find();\n" - "while ( cursor.hasNext() ){\n" - "var o = cursor.next();\n" - "count++;\n" - "to.save( o );}\n" - "return count;\n" - "} , this.getName() , newName\n" - ");}\n" - "DBCollection.prototype.getCollection = function( subName ){\n" - "return this._db.getCollection( this._shortName + \".\" + subName );}\n" - "DBCollection.prototype.stats = function( scale ){\n" - "return this._db.runCommand( { collstats : this._shortName , scale : scale } );}\n" - "DBCollection.prototype.dataSize = function(){\n" - "return this.stats().size;}\n" - "DBCollection.prototype.storageSize = function(){\n" - "return this.stats().storageSize;}\n" - "DBCollection.prototype.totalIndexSize = function( verbose ){\n" - "var stats = this.stats();\n" - "if (verbose){\n" - "for (var ns in stats.indexSizes){\n" - "print( ns + \"\\t\" + stats.indexSizes[ns] );}}\n" - "return stats.totalIndexSize;}\n" - "DBCollection.prototype.totalSize = function(){\n" - "var total = this.storageSize();\n" - "var mydb = this._db;\n" - "var shortName = this._shortName;\n" - "this.getIndexes().forEach(\n" - "function( spec ){\n" - "var coll = mydb.getCollection( shortName + \".$\" + spec.name );\n" - "var mysize = coll.storageSize();\n" - "total += coll.dataSize();}\n" - ");\n" - "return total;}\n" - "DBCollection.prototype.convertToCapped = function( bytes ){\n" - "if ( ! bytes )\n" - "throw \"have to specify # of bytes\";\n" - "return this._dbCommand( { convertToCapped : this._shortName , size : bytes } )}\n" - "DBCollection.prototype.exists = function(){\n" - "return this._db.system.namespaces.findOne( { name : this._fullName } );}\n" - "DBCollection.prototype.isCapped = function(){\n" - "var e = this.exists();\n" - "return ( e && e.options && e.options.capped ) ? true : false;}\n" - "DBCollection.prototype.distinct = function( keyString , query ){\n" - "var res = this._dbCommand( { distinct : this._shortName , key : keyString , query : query || {} } );\n" - "if ( ! res.ok )\n" - "throw \"distinct failed: \" + tojson( res );\n" - "return res.values;}\n" - "DBCollection.prototype.group = function( params ){\n" - "params.ns = this._shortName;\n" - "return this._db.group( params );}\n" - "DBCollection.prototype.groupcmd = function( params ){\n" - "params.ns = this._shortName;\n" - "return this._db.groupcmd( params );}\n" - "MapReduceResult = function( db , o ){\n" - "Object.extend( this , o );\n" - "this._o = o;\n" - "this._keys = Object.keySet( o );\n" - "this._db = db;\n" - "this._coll = this._db.getCollection( this.result );}\n" - "MapReduceResult.prototype._simpleKeys = function(){\n" - "return this._o;}\n" - "MapReduceResult.prototype.find = function(){\n" - "return DBCollection.prototype.find.apply( this._coll , arguments );}\n" - "MapReduceResult.prototype.drop = function(){\n" - "return this._coll.drop();}\n" - "\n" - "MapReduceResult.prototype.convertToSingleObject = function(){\n" - "var z = {};\n" - "this._coll.find().forEach( function(a){ z[a._id] = a.value; } );\n" - "return z;}\n" - "\n" - "DBCollection.prototype.mapReduce = function( map , reduce , optional ){\n" - "var c = { mapreduce : this._shortName , map : map , reduce : reduce };\n" - "if ( optional )\n" - "Object.extend( c , optional );\n" - "var raw = this._db.runCommand( c );\n" - "if ( ! raw.ok )\n" - "throw \"map reduce failed: \" + tojson( raw );\n" - "return new MapReduceResult( this._db , raw );}\n" - "DBCollection.prototype.toString = function(){\n" - "return this.getFullName();}\n" - "DBCollection.prototype.toString = function(){\n" - "return this.getFullName();}\n" - "DBCollection.prototype.tojson = DBCollection.prototype.toString;\n" - "DBCollection.prototype.shellPrint = DBCollection.prototype.toString;\n" - ; - +const char * jsconcatcode = +"__quiet = false;\n" + "__magicNoPrint = { __magicNoPrint : 1111 }\n" + "chatty = function(s){\n" + "if ( ! __quiet )\n" + "print( s );}\n" + "friendlyEqual = function( a , b ){\n" + "if ( a == b )\n" + "return true;\n" + "if ( tojson( a ) == tojson( b ) )\n" + "return true;\n" + "return false;}\n" + "doassert = function (msg) {\n" + "if (msg.indexOf(\"assert\") == 0)\n" + "print(msg);\n" + "else\n" + "print(\"assert: \" + msg);\n" + "throw msg;}\n" + "assert = function( b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( b )\n" + "return;\n" + "doassert( msg == undefined ? \"assert failed\" : \"assert failed : \" + msg );}\n" + "assert.automsg = function( b ) {\n" + "assert( eval( b ), b );}\n" + "assert._debug = false;\n" + "assert.eq = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a == b )\n" + "return;\n" + "if ( ( a != null && b != null ) && friendlyEqual( a , b ) )\n" + "return;\n" + "doassert( \"[\" + tojson( a ) + \"] != [\" + tojson( b ) + \"] are not equal : \" + msg );}\n" + "assert.eq.automsg = function( a, b ) {\n" + "assert.eq( eval( a ), eval( b ), \"[\" + a + \"] != [\" + b + \"]\" );}\n" + "assert.neq = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a != b )\n" + "return;\n" + "doassert( \"[\" + a + \"] != [\" + b + \"] are equal : \" + msg );}\n" + "assert.repeat = function( f, msg, timeout, interval ) {\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "var start = new Date();\n" + "timeout = timeout || 30000;\n" + "interval = interval || 200;\n" + "var last;\n" + "while( 1 ) {\n" + "if ( typeof( f ) == \"string\" ){\n" + "if ( eval( f ) )\n" + "return;}\n" + "else {\n" + "if ( f() )\n" + "return;}\n" + "if ( ( new Date() ).getTime() - start.getTime() > timeout )\n" + "break;\n" + "sleep( interval );}}\n" + "assert.soon = function( f, msg, timeout, interval ) {\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "var start = new Date();\n" + "timeout = timeout || 30000;\n" + "interval = interval || 200;\n" + "var last;\n" + "while( 1 ) {\n" + "if ( typeof( f ) == \"string\" ){\n" + "if ( eval( f ) )\n" + "return;}\n" + "else {\n" + "if ( f() )\n" + "return;}\n" + "if ( ( new Date() ).getTime() - start.getTime() > timeout )\n" + "doassert( \"assert.soon failed: \" + f + \", msg:\" + msg );\n" + "sleep( interval );}}\n" + "assert.throws = function( func , params , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "try {\n" + "func.apply( null , params );}\n" + "catch ( e ){\n" + "return e;}\n" + "doassert( \"did not throw exception: \" + msg );}\n" + "assert.throws.automsg = function( func, params ) {\n" + "assert.throws( func, params, func.toString() );}\n" + "assert.commandWorked = function( res , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( res.ok == 1 )\n" + "return;\n" + "doassert( \"command failed: \" + tojson( res ) + \" : \" + msg );}\n" + "assert.commandFailed = function( res , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( res.ok == 0 )\n" + "return;\n" + "doassert( \"command worked when it should have failed: \" + tojson( res ) + \" : \" + msg );}\n" + "assert.isnull = function( what , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( what == null )\n" + "return;\n" + "doassert( \"supposed to null (\" + ( msg || \"\" ) + \") was: \" + tojson( what ) );}\n" + "assert.lt = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a < b )\n" + "return;\n" + "doassert( a + \" is not less than \" + b + \" : \" + msg );}\n" + "assert.gt = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a > b )\n" + "return;\n" + "doassert( a + \" is not greater than \" + b + \" : \" + msg );}\n" + "assert.lte = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a <= b )\n" + "return;\n" + "doassert( a + \" is not less than or eq \" + b + \" : \" + msg );}\n" + "assert.gte = function( a , b , msg ){\n" + "if ( assert._debug && msg ) print( \"in assert for: \" + msg );\n" + "if ( a >= b )\n" + "return;\n" + "doassert( a + \" is not greater than or eq \" + b + \" : \" + msg );}\n" + "assert.close = function( a , b , msg , places ){\n" + "if (places === undefined) {\n" + "places = 4;}\n" + "if (Math.round((a - b) * Math.pow(10, places)) === 0) {\n" + "return;}\n" + "doassert( a + \" is not equal to \" + b + \" within \" + places +\n" + "\" places, diff: \" + (a-b) + \" : \" + msg );\n" + "};\n" + "Object.extend = function( dst , src , deep ){\n" + "for ( var k in src ){\n" + "var v = src[k];\n" + "if ( deep && typeof(v) == \"object\" ){\n" + "v = Object.extend( typeof ( v.length ) == \"number\" ? [] : {} , v , true );}\n" + "dst[k] = v;}\n" + "return dst;}\n" + "argumentsToArray = function( a ){\n" + "var arr = [];\n" + "for ( var i=0; i>>>>>>>>>>>>>> skipping \" + x.name);\n" + "return;}\n" + "params[ i % n ].push( x.name );\n" + "++i;}\n" + ");\n" + "params[ 0 ] = Array.shuffle( params[ 0 ] );\n" + "for( var i in params ) {\n" + "params[ i ].unshift( i );}\n" + "return params;}\n" + "ParallelTester.fileTester = function() {\n" + "var args = argumentsToArray( arguments );\n" + "var suite = args.shift();\n" + "args.forEach(\n" + "function( x ) {\n" + "print(\" S\" + suite + \" Test : \" + x + \" ...\");\n" + "var time = Date.timeFunc( function() { load(x); }, 1);\n" + "print(\" S\" + suite + \" Test : \" + x + \" \" + time + \"ms\" );}\n" + ");}\n" + "assert.parallelTests = function( params, msg, newScopes ) {\n" + "newScopes = newScopes || false;\n" + "var wrapper = function( fun, argv ) {\n" + "eval (\n" + "\"var z = function() {\" +\n" + "\"var __parallelTests__fun = \" + fun.toString() + \";\" +\n" + "\"var __parallelTests__argv = \" + tojson( argv ) + \";\" +\n" + "\"var __parallelTests__passed = false;\" +\n" + "\"try {\" +\n" + "\"__parallelTests__fun.apply( 0, __parallelTests__argv );\" +\n" + "\"__parallelTests__passed = true;\" +\n" + "\"} catch ( e ) {\" +\n" + "\"print( e );\" +\n" + "\"}\" +\n" + "\"return __parallelTests__passed;\" +\n" + "\"}\"\n" + ");\n" + "return z;}\n" + "var runners = new Array();\n" + "for( var i in params ) {\n" + "var param = params[ i ];\n" + "var test = param.shift();\n" + "var t;\n" + "if ( newScopes )\n" + "t = new ScopedThread( wrapper( test, param ) );\n" + "else\n" + "t = new Thread( wrapper( test, param ) );\n" + "runners.push( t );}\n" + "runners.forEach( function( x ) { x.start(); } );\n" + "var nFailed = 0;\n" + "runners.forEach( function( x ) { if( !x.returnData() ) { ++nFailed; } } );\n" + "assert.eq( 0, nFailed, msg );}}\n" + "tojsononeline = function( x ){\n" + "return tojson( x , \" \" , true );}\n" + "tojson = function( x, indent , nolint ){\n" + "if ( x === null )\n" + "return \"null\";\n" + "if ( x === undefined )\n" + "return \"undefined\";\n" + "if (!indent)\n" + "indent = \"\";\n" + "switch ( typeof x ) {\n" + "case \"string\": {\n" + "var s = \"\\\"\";\n" + "for ( var i=0; i:28017/_replSet for additional diagnostic info\");}\n" + "rs.slaveOk = function () { return db.getMongo().setSlaveOk(); }\n" + "rs.status = function () { return db._adminCommand(\"replSetGetStatus\"); }\n" + "rs.isMaster = function () { return db.isMaster(); }\n" + "rs.initiate = function (c) { return db._adminCommand({ replSetInitiate: c }); }\n" + "rs.add = function (hostport, arb) {\n" + "var cfg = hostport;\n" + "var local = db.getSisterDB(\"local\");\n" + "assert(local.system.replset.count() <= 1, \"error: local.system.replset has unexpected contents\");\n" + "var c = local.system.replset.findOne();\n" + "assert(c, \"no config object retrievable from local.system.replset\");\n" + "c.version++;\n" + "var max = 0;\n" + "for (var i in c.members)\n" + "if (c.members[i]._id > max) max = c.members[i]._id;\n" + "if (isString(hostport)) {\n" + "cfg = { _id: max + 1, host: hostport };\n" + "if (arb)\n" + "cfg.arbiterOnly = true;}\n" + "c.members.push(cfg);\n" + "return db._adminCommand({ replSetReconfig: c });}\n" + "rs.stepDown = function () { return db._adminCommand({ replSetStepDown:true}); }\n" + "rs.addArb = function (hn) { return this.add(hn, true); }\n" + "rs.conf = function () { return db.getSisterDB(\"local\").system.replset.findOne(); }\n" + "help = shellHelper.help = function (x) {\n" + "if (x == \"connect\") {\n" + "print(\"\\nNormally one specifies the server on the mongo shell command line. Run mongo --help to see those options.\");\n" + "print(\"Additional connections may be opened:\\n\");\n" + "print(\" var x = new Mongo('host[:port]');\");\n" + "print(\" var mydb = x.getDB('mydb');\");\n" + "print(\" or\");\n" + "print(\" var mydb = connect('host[:port]/mydb');\");\n" + "print(\"\\nNote: the REPL prompt only auto-reports getLastError() for the shell command line connection.\\n\");\n" + "return;}\n" + "if (x == \"misc\") {\n" + "print(\"\\tb = new BinData(subtype,base64str) create a BSON BinData value\");\n" + "print(\"\\tb.subtype() the BinData subtype (0..255)\");\n" + "print(\"\\tb.length() length of the BinData data in bytes\");\n" + "print(\"\\tb.hex() the data as a hex encoded string\");\n" + "print(\"\\tb.base64() the data as a base 64 encoded string\");\n" + "print(\"\\tb.toString()\");\n" + "return;}\n" + "if (x == \"admin\") {\n" + "print(\"\\tls([path]) list files\");\n" + "print(\"\\tpwd() returns current directory\");\n" + "print(\"\\tlistFiles([path]) returns file list\");\n" + "print(\"\\thostname() returns name of this host\");\n" + "print(\"\\tcat(fname) returns contents of text file as a string\");\n" + "print(\"\\tremoveFile(f) delete a file\");\n" + "print(\"\\tload(jsfilename) load and execute a .js file\");\n" + "print(\"\\trun(program[, args...]) spawn a program and wait for its completion\");\n" + "print(\"\\tsleep(m) sleep m milliseconds\");\n" + "print(\"\\tgetMemInfo() diagnostic\");\n" + "return;}\n" + "if (x == \"test\") {\n" + "print(\"\\tstartMongodEmpty(args) DELETES DATA DIR and then starts mongod\");\n" + "print(\"\\t returns a connection to the new server\");\n" + "print(\"\\tstartMongodTest() DELETES DATA DIR\");\n" + "print(\"\\t automatically picks port #s starting at 27000 and increasing\");\n" + "print(\"\\t or you can specify the port as the first arg\");\n" + "print(\"\\t dir is /data/db// if not specified as the 2nd arg\");\n" + "print(\"\\t returns a connection to the new server\");\n" + "return;}\n" + "print(\"\\t\" + \"db.help() help on db methods\");\n" + "print(\"\\t\" + \"db.mycoll.help() help on collection methods\");\n" + "print(\"\\t\" + \"rs.help() help on replica set methods\");\n" + "print(\"\\t\" + \"help connect connecting to a db help\");\n" + "print(\"\\t\" + \"help admin administrative help\");\n" + "print(\"\\t\" + \"help misc misc things to know\");\n" + "print();\n" + "print(\"\\t\" + \"show dbs show database names\");\n" + "print(\"\\t\" + \"show collections show collections in current database\");\n" + "print(\"\\t\" + \"show users show users in current database\");\n" + "print(\"\\t\" + \"show profile show most recent system.profile entries with time >= 1ms\");\n" + "print(\"\\t\" + \"use set current database\");\n" + "print(\"\\t\" + \"db.foo.find() list objects in collection foo\");\n" + "print(\"\\t\" + \"db.foo.find( { a : 1 } ) list objects in foo where a == 1\");\n" + "print(\"\\t\" + \"it result of the last line evaluated; use to further iterate\");\n" + "print(\"\\t\" + \"exit quit the mongo shell\");}\n" + "if ( typeof DB == \"undefined\" ){\n" + "DB = function( mongo , name ){\n" + "this._mongo = mongo;\n" + "this._name = name;}}\n" + "DB.prototype.getMongo = function(){\n" + "assert( this._mongo , \"why no mongo!\" );\n" + "return this._mongo;}\n" + "DB.prototype.getSisterDB = function( name ){\n" + "return this.getMongo().getDB( name );}\n" + "DB.prototype.getName = function(){\n" + "return this._name;}\n" + "DB.prototype.stats = function(){\n" + "return this.runCommand( { dbstats : 1 } );}\n" + "DB.prototype.getCollection = function( name ){\n" + "return new DBCollection( this._mongo , this , name , this._name + \".\" + name );}\n" + "DB.prototype.commandHelp = function( name ){\n" + "var c = {};\n" + "c[name] = 1;\n" + "c.help = true;\n" + "return this.runCommand( c ).help;}\n" + "DB.prototype.runCommand = function( obj ){\n" + "if ( typeof( obj ) == \"string\" ){\n" + "var n = {};\n" + "n[obj] = 1;\n" + "obj = n;}\n" + "return this.getCollection( \"$cmd\" ).findOne( obj );}\n" + "DB.prototype._dbCommand = DB.prototype.runCommand;\n" + "DB.prototype._adminCommand = function( obj ){\n" + "if ( this._name == \"admin\" )\n" + "return this.runCommand( obj );\n" + "return this.getSisterDB( \"admin\" ).runCommand( obj );}\n" + "DB.prototype.addUser = function( username , pass, readOnly ){\n" + "readOnly = readOnly || false;\n" + "var c = this.getCollection( \"system.users\" );\n" + "var u = c.findOne( { user : username } ) || { user : username };\n" + "u.readOnly = readOnly;\n" + "u.pwd = hex_md5( username + \":mongo:\" + pass );\n" + "print( tojson( u ) );\n" + "c.save( u );}\n" + "DB.prototype.removeUser = function( username ){\n" + "this.getCollection( \"system.users\" ).remove( { user : username } );}\n" + "DB.prototype.__pwHash = function( nonce, username, pass ) {\n" + "return hex_md5( nonce + username + hex_md5( username + \":mongo:\" + pass ) );}\n" + "DB.prototype.auth = function( username , pass ){\n" + "var n = this.runCommand( { getnonce : 1 } );\n" + "var a = this.runCommand(\n" + "{\n" + "authenticate : 1 ,\n" + "user : username ,\n" + "nonce : n.nonce ,\n" + "key : this.__pwHash( n.nonce, username, pass )}\n" + ");\n" + "return a.ok;}\n" + "\n" + "DB.prototype.createCollection = function(name, opt) {\n" + "var options = opt || {};\n" + "var cmd = { create: name, capped: options.capped, size: options.size, max: options.max };\n" + "var res = this._dbCommand(cmd);\n" + "return res;}\n" + "\n" + "DB.prototype.getProfilingLevel = function() {\n" + "var res = this._dbCommand( { profile: -1 } );\n" + "return res ? res.was : null;}\n" + "\n" + "DB.prototype.dropDatabase = function() {\n" + "if ( arguments.length )\n" + "throw \"dropDatabase doesn't take arguments\";\n" + "return this._dbCommand( { dropDatabase: 1 } );}\n" + "DB.prototype.shutdownServer = function() {\n" + "if( \"admin\" != this._name ){\n" + "return \"shutdown command only works with the admin database; try 'use admin'\";}\n" + "try {\n" + "var res = this._dbCommand(\"shutdown\");\n" + "if( res )\n" + "throw \"shutdownServer failed: \" + res.errmsg;\n" + "throw \"shutdownServer failed\";}\n" + "catch ( e ){\n" + "assert( tojson( e ).indexOf( \"error doing query: failed\" ) >= 0 , \"unexpected error: \" + tojson( e ) );\n" + "print( \"server should be down...\" );}}\n" + "\n" + "DB.prototype.cloneDatabase = function(from) {\n" + "assert( isString(from) && from.length );\n" + "return this._dbCommand( { clone: from } );}\n" + "\n" + "DB.prototype.cloneCollection = function(from, collection, query) {\n" + "assert( isString(from) && from.length );\n" + "assert( isString(collection) && collection.length );\n" + "collection = this._name + \".\" + collection;\n" + "query = query || {};\n" + "return this._dbCommand( { cloneCollection:collection, from:from, query:query } );}\n" + "\n" + "DB.prototype.copyDatabase = function(fromdb, todb, fromhost, username, password) {\n" + "assert( isString(fromdb) && fromdb.length );\n" + "assert( isString(todb) && todb.length );\n" + "fromhost = fromhost || \"\";\n" + "if ( username && password ) {\n" + "var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );\n" + "return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );\n" + "} else {\n" + "return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );}}\n" + "\n" + "DB.prototype.repairDatabase = function() {\n" + "return this._dbCommand( { repairDatabase: 1 } );}\n" + "DB.prototype.help = function() {\n" + "print(\"DB methods:\");\n" + "print(\"\\tdb.addUser(username, password[, readOnly=false])\");\n" + "print(\"\\tdb.auth(username, password)\");\n" + "print(\"\\tdb.cloneDatabase(fromhost)\");\n" + "print(\"\\tdb.commandHelp(name) returns the help for the command\");\n" + "print(\"\\tdb.copyDatabase(fromdb, todb, fromhost)\");\n" + "print(\"\\tdb.createCollection(name, { size : ..., capped : ..., max : ... } )\");\n" + "print(\"\\tdb.currentOp() displays the current operation in the db\");\n" + "print(\"\\tdb.dropDatabase()\");\n" + "print(\"\\tdb.eval(func, args) run code server-side\");\n" + "print(\"\\tdb.getCollection(cname) same as db['cname'] or db.cname\");\n" + "print(\"\\tdb.getCollectionNames()\");\n" + "print(\"\\tdb.getLastError() - just returns the err msg string\");\n" + "print(\"\\tdb.getLastErrorObj() - return full status object\");\n" + "print(\"\\tdb.getMongo() get the server connection object\");\n" + "print(\"\\tdb.getMongo().setSlaveOk() allow this connection to read from the nonmaster member of a replica pair\");\n" + "print(\"\\tdb.getName()\");\n" + "print(\"\\tdb.getPrevError()\");\n" + "print(\"\\tdb.getProfilingLevel()\");\n" + "print(\"\\tdb.getReplicationInfo()\");\n" + "print(\"\\tdb.getSisterDB(name) get the db at the same server as this one\");\n" + "print(\"\\tdb.isMaster() check replica primary status\");\n" + "print(\"\\tdb.killOp(opid) kills the current operation in the db\");\n" + "print(\"\\tdb.listCommands() lists all the db commands\");\n" + "print(\"\\tdb.printCollectionStats()\");\n" + "print(\"\\tdb.printReplicationInfo()\");\n" + "print(\"\\tdb.printSlaveReplicationInfo()\");\n" + "print(\"\\tdb.printShardingStatus()\");\n" + "print(\"\\tdb.removeUser(username)\");\n" + "print(\"\\tdb.repairDatabase()\");\n" + "print(\"\\tdb.resetError()\");\n" + "print(\"\\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }\");\n" + "print(\"\\tdb.serverStatus()\");\n" + "print(\"\\tdb.setProfilingLevel(level,) 0=off 1=slow 2=all\");\n" + "print(\"\\tdb.shutdownServer()\");\n" + "print(\"\\tdb.stats()\");\n" + "print(\"\\tdb.version() current version of the server\");\n" + "print(\"\\tdb.getMongo().setSlaveOk() allow queries on a replication slave server\");\n" + "return __magicNoPrint;}\n" + "DB.prototype.printCollectionStats = function(){\n" + "var mydb = this;\n" + "this.getCollectionNames().forEach(\n" + "function(z){\n" + "print( z );\n" + "printjson( mydb.getCollection(z).stats() );\n" + "print( \"---\" );}\n" + ");}\n" + "\n" + "DB.prototype.setProfilingLevel = function(level,slowms) {\n" + "if (level < 0 || level > 2) {\n" + "throw { dbSetProfilingException : \"input level \" + level + \" is out of range [0..2]\" };}\n" + "var cmd = { profile: level };\n" + "if ( slowms )\n" + "cmd[\"slowms\"] = slowms;\n" + "return this._dbCommand( cmd );}\n" + "\n" + "DB.prototype.eval = function(jsfunction) {\n" + "var cmd = { $eval : jsfunction };\n" + "if ( arguments.length > 1 ) {\n" + "cmd.args = argumentsToArray( arguments ).slice(1);}\n" + "var res = this._dbCommand( cmd );\n" + "if (!res.ok)\n" + "throw tojson( res );\n" + "return res.retval;}\n" + "DB.prototype.dbEval = DB.prototype.eval;\n" + "\n" + "DB.prototype.groupeval = function(parmsObj) {\n" + "var groupFunction = function() {\n" + "var parms = args[0];\n" + "var c = db[parms.ns].find(parms.cond||{});\n" + "var map = new Map();\n" + "var pks = parms.key ? Object.keySet( parms.key ) : null;\n" + "var pkl = pks ? pks.length : 0;\n" + "var key = {};\n" + "while( c.hasNext() ) {\n" + "var obj = c.next();\n" + "if ( pks ) {\n" + "for( var i=0; i, nPrev : , ok : 1 }\n" + "result.err will be null if no error has occurred.\n" + "*/\n" + "DB.prototype.getPrevError = function(){\n" + "return this.runCommand( { getpreverror : 1 } );}\n" + "DB.prototype.getCollectionNames = function(){\n" + "var all = [];\n" + "var nsLength = this._name.length + 1;\n" + "var c = this.getCollection( \"system.namespaces\" ).find();\n" + "while ( c.hasNext() ){\n" + "var name = c.next().name;\n" + "if ( name.indexOf( \"$\" ) >= 0 && name.indexOf( \".oplog.$\" ) < 0 )\n" + "continue;\n" + "all.push( name.substring( nsLength ) );}\n" + "return all.sort();}\n" + "DB.prototype.tojson = function(){\n" + "return this._name;}\n" + "DB.prototype.toString = function(){\n" + "return this._name;}\n" + "DB.prototype.isMaster = function () { return this.runCommand(\"isMaster\"); }\n" + "DB.prototype.currentOp = function(){\n" + "return db.$cmd.sys.inprog.findOne();}\n" + "DB.prototype.currentOP = DB.prototype.currentOp;\n" + "DB.prototype.killOp = function(op) {\n" + "if( !op )\n" + "throw \"no opNum to kill specified\";\n" + "return db.$cmd.sys.killop.findOne({'op':op});}\n" + "DB.prototype.killOP = DB.prototype.killOp;\n" + "DB.tsToSeconds = function(x){\n" + "if ( x.t && x.i )\n" + "return x.t / 1000;\n" + "return x / 4294967296;}\n" + "\n" + "DB.prototype.getReplicationInfo = function() {\n" + "var db = this.getSisterDB(\"local\");\n" + "var result = { };\n" + "var ol = db.system.namespaces.findOne({name:\"local.oplog.$main\"});\n" + "if( ol && ol.options ) {\n" + "result.logSizeMB = ol.options.size / 1000 / 1000;\n" + "} else {\n" + "result.errmsg = \"local.oplog.$main, or its options, not found in system.namespaces collection (not --master?)\";\n" + "return result;}\n" + "var firstc = db.oplog.$main.find().sort({$natural:1}).limit(1);\n" + "var lastc = db.oplog.$main.find().sort({$natural:-1}).limit(1);\n" + "if( !firstc.hasNext() || !lastc.hasNext() ) {\n" + "result.errmsg = \"objects not found in local.oplog.$main -- is this a new and empty db instance?\";\n" + "result.oplogMainRowCount = db.oplog.$main.count();\n" + "return result;}\n" + "var first = firstc.next();\n" + "var last = lastc.next();\n" + "{\n" + "var tfirst = first.ts;\n" + "var tlast = last.ts;\n" + "if( tfirst && tlast ) {\n" + "tfirst = DB.tsToSeconds( tfirst );\n" + "tlast = DB.tsToSeconds( tlast );\n" + "result.timeDiff = tlast - tfirst;\n" + "result.timeDiffHours = Math.round(result.timeDiff / 36)/100;\n" + "result.tFirst = (new Date(tfirst*1000)).toString();\n" + "result.tLast = (new Date(tlast*1000)).toString();\n" + "result.now = Date();}\n" + "else {\n" + "result.errmsg = \"ts element not found in oplog objects\";}}\n" + "return result;}\n" + "DB.prototype.printReplicationInfo = function() {\n" + "var result = this.getReplicationInfo();\n" + "if( result.errmsg ) {\n" + "print(tojson(result));\n" + "return;}\n" + "print(\"configured oplog size: \" + result.logSizeMB + \"MB\");\n" + "print(\"log length start to end: \" + result.timeDiff + \"secs (\" + result.timeDiffHours + \"hrs)\");\n" + "print(\"oplog first event time: \" + result.tFirst);\n" + "print(\"oplog last event time: \" + result.tLast);\n" + "print(\"now: \" + result.now);}\n" + "DB.prototype.printSlaveReplicationInfo = function() {\n" + "function g(x) {\n" + "assert( x , \"how could this be null (printSlaveReplicationInfo gx)\" )\n" + "print(\"source: \" + x.host);\n" + "if ( x.syncedTo ){\n" + "var st = new Date( DB.tsToSeconds( x.syncedTo ) * 1000 );\n" + "var now = new Date();\n" + "print(\"\\t syncedTo: \" + st.toString() );\n" + "var ago = (now-st)/1000;\n" + "var hrs = Math.round(ago/36)/100;\n" + "print(\"\\t\\t = \" + Math.round(ago) + \"secs ago (\" + hrs + \"hrs)\");}\n" + "else {\n" + "print( \"\\t doing initial sync\" );}}\n" + "var L = this.getSisterDB(\"local\");\n" + "if( L.sources.count() == 0 ) {\n" + "print(\"local.sources is empty; is this db a --slave?\");\n" + "return;}\n" + "L.sources.find().forEach(g);}\n" + "DB.prototype.serverBuildInfo = function(){\n" + "return this._adminCommand( \"buildinfo\" );}\n" + "DB.prototype.serverStatus = function(){\n" + "return this._adminCommand( \"serverStatus\" );}\n" + "DB.prototype.serverCmdLineOpts = function(){\n" + "return this._adminCommand( \"getCmdLineOpts\" );}\n" + "DB.prototype.version = function(){\n" + "return this.serverBuildInfo().version;}\n" + "DB.prototype.listCommands = function(){\n" + "var x = this.runCommand( \"listCommands\" );\n" + "for ( var name in x.commands ){\n" + "var c = x.commands[name];\n" + "var s = name + \": \";\n" + "switch ( c.lockType ){\n" + "case -1: s += \"read-lock\"; break;\n" + "case 0: s += \"no-lock\"; break;\n" + "case 1: s += \"write-lock\"; break;\n" + "default: s += c.lockType;}\n" + "if (c.adminOnly) s += \" adminOnly \";\n" + "if (c.adminOnly) s += \" slaveOk \";\n" + "s += \"\\n \";\n" + "s += c.help.replace(/\\n/g, '\\n ');\n" + "s += \"\\n\";\n" + "print( s );}}\n" + "DB.prototype.printShardingStatus = function(){\n" + "printShardingStatus( this.getSisterDB( \"config\" ) );}\n" + "if ( typeof Mongo == \"undefined\" ){\n" + "Mongo = function( host ){\n" + "this.init( host );}}\n" + "if ( ! Mongo.prototype ){\n" + "throw \"Mongo.prototype not defined\";}\n" + "if ( ! Mongo.prototype.find )\n" + "Mongo.prototype.find = function( ns , query , fields , limit , skip ){ throw \"find not implemented\"; }\n" + "if ( ! Mongo.prototype.insert )\n" + "Mongo.prototype.insert = function( ns , obj ){ throw \"insert not implemented\"; }\n" + "if ( ! Mongo.prototype.remove )\n" + "Mongo.prototype.remove = function( ns , pattern ){ throw \"remove not implemented;\" }\n" + "if ( ! Mongo.prototype.update )\n" + "Mongo.prototype.update = function( ns , query , obj , upsert ){ throw \"update not implemented;\" }\n" + "if ( typeof mongoInject == \"function\" ){\n" + "mongoInject( Mongo.prototype );}\n" + "Mongo.prototype.setSlaveOk = function() {\n" + "this.slaveOk = true;}\n" + "Mongo.prototype.getDB = function( name ){\n" + "return new DB( this , name );}\n" + "Mongo.prototype.getDBs = function(){\n" + "var res = this.getDB( \"admin\" ).runCommand( { \"listDatabases\" : 1 } );\n" + "assert( res.ok == 1 , \"listDatabases failed:\" + tojson( res ) );\n" + "return res;}\n" + "Mongo.prototype.getDBNames = function(){\n" + "return this.getDBs().databases.map(\n" + "function(z){\n" + "return z.name;}\n" + ");}\n" + "Mongo.prototype.getCollection = function(ns){\n" + "var idx = ns.indexOf( \".\" );\n" + "if ( idx < 0 )\n" + "throw \"need . in ns\";\n" + "var db = ns.substring( 0 , idx );\n" + "var c = ns.substring( idx + 1 );\n" + "return this.getDB( db ).getCollection( c );}\n" + "Mongo.prototype.toString = function(){\n" + "return \"connection to \" + this.host;}\n" + "Mongo.prototype.tojson = Mongo.prototype.toString;\n" + "connect = function( url , user , pass ){\n" + "chatty( \"connecting to: \" + url )\n" + "if ( user && ! pass )\n" + "throw \"you specified a user and not a password. either you need a password, or you're using the old connect api\";\n" + "var idx = url.lastIndexOf( \"/\" );\n" + "var db;\n" + "if ( idx < 0 )\n" + "db = new Mongo().getDB( url );\n" + "else\n" + "db = new Mongo( url.substring( 0 , idx ) ).getDB( url.substring( idx + 1 ) );\n" + "if ( user && pass ){\n" + "if ( ! db.auth( user , pass ) ){\n" + "throw \"couldn't login\";}}\n" + "return db;}\n" + "MR = {};\n" + "MR.init = function(){\n" + "$max = 0;\n" + "$arr = [];\n" + "emit = MR.emit;\n" + "$numEmits = 0;\n" + "$numReduces = 0;\n" + "$numReducesToDB = 0;\n" + "gc();}\n" + "MR.cleanup = function(){\n" + "MR.init();\n" + "gc();}\n" + "MR.emit = function(k,v){\n" + "$numEmits++;\n" + "var num = nativeHelper.apply( get_num_ , [ k ] );\n" + "var data = $arr[num];\n" + "if ( ! data ){\n" + "data = { key : k , values : new Array(1000) , count : 0 };\n" + "$arr[num] = data;}\n" + "data.values[data.count++] = v;\n" + "$max = Math.max( $max , data.count );}\n" + "MR.doReduce = function( useDB ){\n" + "$numReduces++;\n" + "if ( useDB )\n" + "$numReducesToDB++;\n" + "$max = 0;\n" + "for ( var i=0; i<$arr.length; i++){\n" + "var data = $arr[i];\n" + "if ( ! data )\n" + "continue;\n" + "if ( useDB ){\n" + "var x = tempcoll.findOne( { _id : data.key } );\n" + "if ( x ){\n" + "data.values[data.count++] = x.value;}}\n" + "var r = $reduce( data.key , data.values.slice( 0 , data.count ) );\n" + "if ( r && r.length && r[0] ){\n" + "data.values = r;\n" + "data.count = r.length;}\n" + "else{\n" + "data.values[0] = r;\n" + "data.count = 1;}\n" + "$max = Math.max( $max , data.count );\n" + "if ( useDB ){\n" + "if ( data.count == 1 ){\n" + "tempcoll.save( { _id : data.key , value : data.values[0] } );}\n" + "else {\n" + "tempcoll.save( { _id : data.key , value : data.values.slice( 0 , data.count ) } );}}}}\n" + "MR.check = function(){\n" + "if ( $max < 2000 && $arr.length < 1000 ){\n" + "return 0;}\n" + "MR.doReduce();\n" + "if ( $max < 2000 && $arr.length < 1000 ){\n" + "return 1;}\n" + "MR.doReduce( true );\n" + "$arr = [];\n" + "$max = 0;\n" + "reset_num();\n" + "gc();\n" + "return 2;}\n" + "MR.finalize = function(){\n" + "tempcoll.find().forEach(\n" + "function(z){\n" + "z.value = $finalize( z._id , z.value );\n" + "tempcoll.save( z );}\n" + ");}\n" + "if ( typeof DBQuery == \"undefined\" ){\n" + "DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip , batchSize ){\n" + "this._mongo = mongo;\n" + "this._db = db;\n" + "this._collection = collection;\n" + "this._ns = ns;\n" + "this._query = query || {};\n" + "this._fields = fields;\n" + "this._limit = limit || 0;\n" + "this._skip = skip || 0;\n" + "this._batchSize = batchSize || 0;\n" + "this._cursor = null;\n" + "this._numReturned = 0;\n" + "this._special = false;\n" + "this._prettyShell = false;}\n" + "print( \"DBQuery probably won't have array access \" );}\n" + "DBQuery.prototype.help = function () {\n" + "print(\"find() modifiers\")\n" + "print(\"\\t.sort( {...} )\")\n" + "print(\"\\t.limit( n )\")\n" + "print(\"\\t.skip( n )\")\n" + "print(\"\\t.count() - total # of objects matching query, ignores skip,limit\")\n" + "print(\"\\t.size() - total # of objects cursor would return, honors skip,limit\")\n" + "print(\"\\t.explain([verbose])\")\n" + "print(\"\\t.hint(...)\")\n" + "print(\"\\t.showDiskLoc() - adds a $diskLoc field to each returned object\")\n" + "print(\"\\nCursor methods\");\n" + "print(\"\\t.forEach( func )\")\n" + "print(\"\\t.print() - output to console in full pretty format\")\n" + "print(\"\\t.map( func )\")\n" + "print(\"\\t.hasNext()\")\n" + "print(\"\\t.next()\")}\n" + "DBQuery.prototype.clone = function(){\n" + "var q = new DBQuery( this._mongo , this._db , this._collection , this._ns ,\n" + "this._query , this._fields ,\n" + "this._limit , this._skip , this._batchSize );\n" + "q._special = this._special;\n" + "return q;}\n" + "DBQuery.prototype._ensureSpecial = function(){\n" + "if ( this._special )\n" + "return;\n" + "var n = { query : this._query };\n" + "this._query = n;\n" + "this._special = true;}\n" + "DBQuery.prototype._checkModify = function(){\n" + "if ( this._cursor )\n" + "throw \"query already executed\";}\n" + "DBQuery.prototype._exec = function(){\n" + "if ( ! this._cursor ){\n" + "assert.eq( 0 , this._numReturned );\n" + "this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip , this._batchSize );\n" + "this._cursorSeen = 0;}\n" + "return this._cursor;}\n" + "DBQuery.prototype.limit = function( limit ){\n" + "this._checkModify();\n" + "this._limit = limit;\n" + "return this;}\n" + "DBQuery.prototype.batchSize = function( batchSize ){\n" + "this._checkModify();\n" + "this._batchSize = batchSize;\n" + "return this;}\n" + "DBQuery.prototype.skip = function( skip ){\n" + "this._checkModify();\n" + "this._skip = skip;\n" + "return this;}\n" + "DBQuery.prototype.hasNext = function(){\n" + "this._exec();\n" + "if ( this._limit > 0 && this._cursorSeen >= this._limit )\n" + "return false;\n" + "var o = this._cursor.hasNext();\n" + "return o;}\n" + "DBQuery.prototype.next = function(){\n" + "this._exec();\n" + "var o = this._cursor.hasNext();\n" + "if ( o )\n" + "this._cursorSeen++;\n" + "else\n" + "throw \"error hasNext: \" + o;\n" + "var ret = this._cursor.next();\n" + "if ( ret.$err && this._numReturned == 0 && ! this.hasNext() )\n" + "throw \"error: \" + tojson( ret );\n" + "this._numReturned++;\n" + "return ret;}\n" + "DBQuery.prototype.objsLeftInBatch = function(){\n" + "this._exec();\n" + "var ret = this._cursor.objsLeftInBatch();\n" + "if ( ret.$err )\n" + "throw \"error: \" + tojson( ret );\n" + "return ret;}\n" + "DBQuery.prototype.toArray = function(){\n" + "if ( this._arr )\n" + "return this._arr;\n" + "var a = [];\n" + "while ( this.hasNext() )\n" + "a.push( this.next() );\n" + "this._arr = a;\n" + "return a;}\n" + "DBQuery.prototype.count = function( applySkipLimit ){\n" + "var cmd = { count: this._collection.getName() };\n" + "if ( this._query ){\n" + "if ( this._special )\n" + "cmd.query = this._query.query;\n" + "else\n" + "cmd.query = this._query;}\n" + "cmd.fields = this._fields || {};\n" + "if ( applySkipLimit ){\n" + "if ( this._limit )\n" + "cmd.limit = this._limit;\n" + "if ( this._skip )\n" + "cmd.skip = this._skip;}\n" + "var res = this._db.runCommand( cmd );\n" + "if( res && res.n != null ) return res.n;\n" + "throw \"count failed: \" + tojson( res );}\n" + "DBQuery.prototype.size = function(){\n" + "return this.count( true );}\n" + "DBQuery.prototype.countReturn = function(){\n" + "var c = this.count();\n" + "if ( this._skip )\n" + "c = c - this._skip;\n" + "if ( this._limit > 0 && this._limit < c )\n" + "return this._limit;\n" + "return c;}\n" + "\n" + "DBQuery.prototype.itcount = function(){\n" + "var num = 0;\n" + "while ( this.hasNext() ){\n" + "num++;\n" + "this.next();}\n" + "return num;}\n" + "DBQuery.prototype.length = function(){\n" + "return this.toArray().length;}\n" + "DBQuery.prototype._addSpecial = function( name , value ){\n" + "this._ensureSpecial();\n" + "this._query[name] = value;\n" + "return this;}\n" + "DBQuery.prototype.sort = function( sortBy ){\n" + "return this._addSpecial( \"orderby\" , sortBy );}\n" + "DBQuery.prototype.hint = function( hint ){\n" + "return this._addSpecial( \"$hint\" , hint );}\n" + "DBQuery.prototype.min = function( min ) {\n" + "return this._addSpecial( \"$min\" , min );}\n" + "DBQuery.prototype.max = function( max ) {\n" + "return this._addSpecial( \"$max\" , max );}\n" + "DBQuery.prototype.showDiskLoc = function() {\n" + "return this._addSpecial( \"$showDiskLoc\" , true);}\n" + "DBQuery.prototype.forEach = function( func ){\n" + "while ( this.hasNext() )\n" + "func( this.next() );}\n" + "DBQuery.prototype.map = function( func ){\n" + "var a = [];\n" + "while ( this.hasNext() )\n" + "a.push( func( this.next() ) );\n" + "return a;}\n" + "DBQuery.prototype.arrayAccess = function( idx ){\n" + "return this.toArray()[idx];}\n" + "DBQuery.prototype.explain = function (verbose) {\n" + "/* verbose=true --> include allPlans, oldPlan fields */\n" + "var n = this.clone();\n" + "n._ensureSpecial();\n" + "n._query.$explain = true;\n" + "n._limit = n._limit * -1;\n" + "var e = n.next();\n" + "if (!verbose) {\n" + "delete e.allPlans;\n" + "delete e.oldPlan;}\n" + "return e;}\n" + "DBQuery.prototype.snapshot = function(){\n" + "this._ensureSpecial();\n" + "this._query.$snapshot = true;\n" + "return this;}\n" + "DBQuery.prototype.pretty = function(){\n" + "this._prettyShell = true;\n" + "return this;}\n" + "DBQuery.prototype.shellPrint = function(){\n" + "try {\n" + "var n = 0;\n" + "while ( this.hasNext() && n < DBQuery.shellBatchSize ){\n" + "var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , \"\" , true );\n" + "print( s );\n" + "n++;}\n" + "if ( this.hasNext() ){\n" + "print( \"has more\" );\n" + "___it___ = this;}\n" + "else {\n" + "___it___ = null;}}\n" + "catch ( e ){\n" + "print( e );}}\n" + "DBQuery.prototype.toString = function(){\n" + "return \"DBQuery: \" + this._ns + \" -> \" + tojson( this.query );}\n" + "DBQuery.shellBatchSize = 20;\n" + "// or db[\"colName\"]\n" + "if ( ( typeof DBCollection ) == \"undefined\" ){\n" + "DBCollection = function( mongo , db , shortName , fullName ){\n" + "this._mongo = mongo;\n" + "this._db = db;\n" + "this._shortName = shortName;\n" + "this._fullName = fullName;\n" + "this.verify();}}\n" + "DBCollection.prototype.verify = function(){\n" + "assert( this._fullName , \"no fullName\" );\n" + "assert( this._shortName , \"no shortName\" );\n" + "assert( this._db , \"no db\" );\n" + "assert.eq( this._fullName , this._db._name + \".\" + this._shortName , \"name mismatch\" );\n" + "assert( this._mongo , \"no mongo in DBCollection\" );}\n" + "DBCollection.prototype.getName = function(){\n" + "return this._shortName;}\n" + "DBCollection.prototype.help = function () {\n" + "var shortName = this.getName();\n" + "print(\"DBCollection help\");\n" + "print(\"\\tdb.\" + shortName + \".find().help() - show DBCursor help\");\n" + "print(\"\\tdb.\" + shortName + \".count()\");\n" + "print(\"\\tdb.\" + shortName + \".dataSize()\");\n" + "print(\"\\tdb.\" + shortName + \".distinct( key ) - eg. db.\" + shortName + \".distinct( 'x' )\");\n" + "print(\"\\tdb.\" + shortName + \".drop() drop the collection\");\n" + "print(\"\\tdb.\" + shortName + \".dropIndex(name)\");\n" + "print(\"\\tdb.\" + shortName + \".dropIndexes()\");\n" + "print(\"\\tdb.\" + shortName + \".ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups\");\n" + "print(\"\\tdb.\" + shortName + \".reIndex()\");\n" + "print(\"\\tdb.\" + shortName + \".find( [query] , [fields]) - first parameter is an optional query filter. second parameter is optional set of fields to return.\");\n" + "print(\"\\t e.g. db.\" + shortName + \".find( { x : 77 } , { name : 1 , x : 1 } )\");\n" + "print(\"\\tdb.\" + shortName + \".find(...).count()\");\n" + "print(\"\\tdb.\" + shortName + \".find(...).limit(n)\");\n" + "print(\"\\tdb.\" + shortName + \".find(...).skip(n)\");\n" + "print(\"\\tdb.\" + shortName + \".find(...).sort(...)\");\n" + "print(\"\\tdb.\" + shortName + \".findOne([query])\");\n" + "print(\"\\tdb.\" + shortName + \".findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )\");\n" + "print(\"\\tdb.\" + shortName + \".getDB() get DB object associated with collection\");\n" + "print(\"\\tdb.\" + shortName + \".getIndexes()\");\n" + "print(\"\\tdb.\" + shortName + \".group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )\");\n" + "print(\"\\tdb.\" + shortName + \".mapReduce( mapFunction , reduceFunction , )\");\n" + "print(\"\\tdb.\" + shortName + \".remove(query)\");\n" + "print(\"\\tdb.\" + shortName + \".renameCollection( newName , ) renames the collection.\");\n" + "print(\"\\tdb.\" + shortName + \".runCommand( name , ) runs a db command with the given name where the first param is the collection name\");\n" + "print(\"\\tdb.\" + shortName + \".save(obj)\");\n" + "print(\"\\tdb.\" + shortName + \".stats()\");\n" + "print(\"\\tdb.\" + shortName + \".storageSize() - includes free space allocated to this collection\");\n" + "print(\"\\tdb.\" + shortName + \".totalIndexSize() - size in bytes of all the indexes\");\n" + "print(\"\\tdb.\" + shortName + \".totalSize() - storage allocated for all data and indexes\");\n" + "print(\"\\tdb.\" + shortName + \".update(query, object[, upsert_bool, multi_bool])\");\n" + "print(\"\\tdb.\" + shortName + \".validate() - SLOW\");\n" + "print(\"\\tdb.\" + shortName + \".getShardVersion() - only for use with sharding\");\n" + "return __magicNoPrint;}\n" + "DBCollection.prototype.getFullName = function(){\n" + "return this._fullName;}\n" + "DBCollection.prototype.getDB = function(){\n" + "return this._db;}\n" + "DBCollection.prototype._dbCommand = function( cmd , params ){\n" + "if ( typeof( cmd ) == \"object\" )\n" + "return this._db._dbCommand( cmd );\n" + "var c = {};\n" + "c[cmd] = this.getName();\n" + "if ( params )\n" + "Object.extend( c , params );\n" + "return this._db._dbCommand( c );}\n" + "DBCollection.prototype.runCommand = DBCollection.prototype._dbCommand;\n" + "DBCollection.prototype._massageObject = function( q ){\n" + "if ( ! q )\n" + "return {};\n" + "var type = typeof q;\n" + "if ( type == \"function\" )\n" + "return { $where : q };\n" + "if ( q.isObjectId )\n" + "return { _id : q };\n" + "if ( type == \"object\" )\n" + "return q;\n" + "if ( type == \"string\" ){\n" + "if ( q.length == 24 )\n" + "return { _id : q };\n" + "return { $where : q };}\n" + "throw \"don't know how to massage : \" + type;}\n" + "DBCollection.prototype._validateObject = function( o ){\n" + "if ( o._ensureSpecial && o._checkModify )\n" + "throw \"can't save a DBQuery object\";}\n" + "DBCollection._allowedFields = { $id : 1 , $ref : 1 };\n" + "DBCollection.prototype._validateForStorage = function( o ){\n" + "this._validateObject( o );\n" + "for ( var k in o ){\n" + "if ( k.indexOf( \".\" ) >= 0 ) {\n" + "throw \"can't have . in field names [\" + k + \"]\" ;}\n" + "if ( k.indexOf( \"$\" ) == 0 && ! DBCollection._allowedFields[k] ) {\n" + "throw \"field names cannot start with $ [\" + k + \"]\";}\n" + "if ( o[k] !== null && typeof( o[k] ) === \"object\" ) {\n" + "this._validateForStorage( o[k] );}}\n" + "};\n" + "DBCollection.prototype.find = function( query , fields , limit , skip ){\n" + "return new DBQuery( this._mongo , this._db , this ,\n" + "this._fullName , this._massageObject( query ) , fields , limit , skip );}\n" + "DBCollection.prototype.findOne = function( query , fields ){\n" + "var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , -1 , 0 , 0 );\n" + "if ( ! cursor.hasNext() )\n" + "return null;\n" + "var ret = cursor.next();\n" + "if ( cursor.hasNext() ) throw \"findOne has more than 1 result!\";\n" + "if ( ret.$err )\n" + "throw \"error \" + tojson( ret );\n" + "return ret;}\n" + "DBCollection.prototype.insert = function( obj , _allow_dot ){\n" + "if ( ! obj )\n" + "throw \"no object passed to insert!\";\n" + "if ( ! _allow_dot ) {\n" + "this._validateForStorage( obj );}\n" + "if ( typeof( obj._id ) == \"undefined\" ){\n" + "var tmp = obj;\n" + "obj = {_id: new ObjectId()};\n" + "for (var key in tmp){\n" + "obj[key] = tmp[key];}}\n" + "this._mongo.insert( this._fullName , obj );\n" + "this._lastID = obj._id;}\n" + "DBCollection.prototype.remove = function( t ){\n" + "this._mongo.remove( this._fullName , this._massageObject( t ) );}\n" + "DBCollection.prototype.update = function( query , obj , upsert , multi ){\n" + "assert( query , \"need a query\" );\n" + "assert( obj , \"need an object\" );\n" + "this._validateObject( obj );\n" + "this._mongo.update( this._fullName , query , obj , upsert ? true : false , multi ? true : false );}\n" + "DBCollection.prototype.save = function( obj ){\n" + "if ( obj == null || typeof( obj ) == \"undefined\" )\n" + "throw \"can't save a null\";\n" + "if ( typeof( obj._id ) == \"undefined\" ){\n" + "obj._id = new ObjectId();\n" + "return this.insert( obj );}\n" + "else {\n" + "return this.update( { _id : obj._id } , obj , true );}}\n" + "DBCollection.prototype._genIndexName = function( keys ){\n" + "var name = \"\";\n" + "for ( var k in keys ){\n" + "var v = keys[k];\n" + "if ( typeof v == \"function\" )\n" + "continue;\n" + "if ( name.length > 0 )\n" + "name += \"_\";\n" + "name += k + \"_\";\n" + "if ( typeof v == \"number\" )\n" + "name += v;}\n" + "return name;}\n" + "DBCollection.prototype._indexSpec = function( keys, options ) {\n" + "var ret = { ns : this._fullName , key : keys , name : this._genIndexName( keys ) };\n" + "if ( ! options ){}\n" + "else if ( typeof ( options ) == \"string\" )\n" + "ret.name = options;\n" + "else if ( typeof ( options ) == \"boolean\" )\n" + "ret.unique = true;\n" + "else if ( typeof ( options ) == \"object\" ){\n" + "if ( options.length ){\n" + "var nb = 0;\n" + "for ( var i=0; i 0 ) {\n" + "ret.unique = true;}\n" + "if ( nTrue > 1 ) {\n" + "ret.dropDups = true;}}\n" + "*/\n" + "return ret;}\n" + "DBCollection.prototype.createIndex = function( keys , options ){\n" + "var o = this._indexSpec( keys, options );\n" + "this._db.getCollection( \"system.indexes\" ).insert( o , true );}\n" + "DBCollection.prototype.ensureIndex = function( keys , options ){\n" + "var name = this._indexSpec( keys, options ).name;\n" + "this._indexCache = this._indexCache || {};\n" + "if ( this._indexCache[ name ] ){\n" + "return;}\n" + "this.createIndex( keys , options );\n" + "if ( this.getDB().getLastError() == \"\" ) {\n" + "this._indexCache[name] = true;}}\n" + "DBCollection.prototype.resetIndexCache = function(){\n" + "this._indexCache = {};}\n" + "DBCollection.prototype.reIndex = function() {\n" + "return this._db.runCommand({ reIndex: this.getName() });}\n" + "DBCollection.prototype.dropIndexes = function(){\n" + "this.resetIndexCache();\n" + "var res = this._db.runCommand( { deleteIndexes: this.getName(), index: \"*\" } );\n" + "assert( res , \"no result from dropIndex result\" );\n" + "if ( res.ok )\n" + "return res;\n" + "if ( res.errmsg.match( /not found/ ) )\n" + "return res;\n" + "throw \"error dropping indexes : \" + tojson( res );}\n" + "DBCollection.prototype.drop = function(){\n" + "this.resetIndexCache();\n" + "var ret = this._db.runCommand( { drop: this.getName() } );\n" + "if ( ! ret.ok ){\n" + "if ( ret.errmsg == \"ns not found\" )\n" + "return false;\n" + "throw \"drop failed: \" + tojson( ret );}\n" + "return true;}\n" + "DBCollection.prototype.findAndModify = function(args){\n" + "var cmd = { findandmodify: this.getName() };\n" + "for (var key in args){\n" + "cmd[key] = args[key];}\n" + "var ret = this._db.runCommand( cmd );\n" + "if ( ! ret.ok ){\n" + "if (ret.errmsg == \"No matching object found\"){\n" + "return null;}\n" + "throw \"findAndModifyFailed failed: \" + tojson( ret.errmsg );}\n" + "return ret.value;}\n" + "DBCollection.prototype.renameCollection = function( newName , dropTarget ){\n" + "return this._db._adminCommand( { renameCollection : this._fullName ,\n" + "to : this._db._name + \".\" + newName ,\n" + "dropTarget : dropTarget } )}\n" + "DBCollection.prototype.validate = function() {\n" + "var res = this._db.runCommand( { validate: this.getName() } );\n" + "res.valid = false;\n" + "var raw = res.result || res.raw;\n" + "if ( raw ){\n" + "var str = \"-\" + tojson( raw );\n" + "res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) );\n" + "var p = /lastExtentSize:(\\d+)/;\n" + "var r = p.exec( str );\n" + "if ( r ){\n" + "res.lastExtentSize = Number( r[1] );}}\n" + "return res;}\n" + "DBCollection.prototype.getShardVersion = function(){\n" + "return this._db._adminCommand( { getShardVersion : this._fullName } );}\n" + "DBCollection.prototype.getIndexes = function(){\n" + "return this.getDB().getCollection( \"system.indexes\" ).find( { ns : this.getFullName() } ).toArray();}\n" + "DBCollection.prototype.getIndices = DBCollection.prototype.getIndexes;\n" + "DBCollection.prototype.getIndexSpecs = DBCollection.prototype.getIndexes;\n" + "DBCollection.prototype.getIndexKeys = function(){\n" + "return this.getIndexes().map(\n" + "function(i){\n" + "return i.key;}\n" + ");}\n" + "DBCollection.prototype.count = function( x ){\n" + "return this.find( x ).count();}\n" + "\n" + "DBCollection.prototype.clean = function() {\n" + "return this._dbCommand( { clean: this.getName() } );}\n" + "\n" + "DBCollection.prototype.dropIndex = function(index) {\n" + "assert(index , \"need to specify index to dropIndex\" );\n" + "if ( ! isString( index ) && isObject( index ) )\n" + "index = this._genIndexName( index );\n" + "var res = this._dbCommand( \"deleteIndexes\" ,{ index: index } );\n" + "this.resetIndexCache();\n" + "return res;}\n" + "DBCollection.prototype.copyTo = function( newName ){\n" + "return this.getDB().eval(\n" + "function( collName , newName ){\n" + "var from = db[collName];\n" + "var to = db[newName];\n" + "to.ensureIndex( { _id : 1 } );\n" + "var count = 0;\n" + "var cursor = from.find();\n" + "while ( cursor.hasNext() ){\n" + "var o = cursor.next();\n" + "count++;\n" + "to.save( o );}\n" + "return count;\n" + "} , this.getName() , newName\n" + ");}\n" + "DBCollection.prototype.getCollection = function( subName ){\n" + "return this._db.getCollection( this._shortName + \".\" + subName );}\n" + "DBCollection.prototype.stats = function( scale ){\n" + "return this._db.runCommand( { collstats : this._shortName , scale : scale } );}\n" + "DBCollection.prototype.dataSize = function(){\n" + "return this.stats().size;}\n" + "DBCollection.prototype.storageSize = function(){\n" + "return this.stats().storageSize;}\n" + "DBCollection.prototype.totalIndexSize = function( verbose ){\n" + "var stats = this.stats();\n" + "if (verbose){\n" + "for (var ns in stats.indexSizes){\n" + "print( ns + \"\\t\" + stats.indexSizes[ns] );}}\n" + "return stats.totalIndexSize;}\n" + "DBCollection.prototype.totalSize = function(){\n" + "var total = this.storageSize();\n" + "var mydb = this._db;\n" + "var shortName = this._shortName;\n" + "this.getIndexes().forEach(\n" + "function( spec ){\n" + "var coll = mydb.getCollection( shortName + \".$\" + spec.name );\n" + "var mysize = coll.storageSize();\n" + "//print( coll + \"\\t\" + mysize + \"\\t\" + tojson( coll.validate() ) );\n" + "total += coll.dataSize();}\n" + ");\n" + "return total;}\n" + "DBCollection.prototype.convertToCapped = function( bytes ){\n" + "if ( ! bytes )\n" + "throw \"have to specify # of bytes\";\n" + "return this._dbCommand( { convertToCapped : this._shortName , size : bytes } )}\n" + "DBCollection.prototype.exists = function(){\n" + "return this._db.system.namespaces.findOne( { name : this._fullName } );}\n" + "DBCollection.prototype.isCapped = function(){\n" + "var e = this.exists();\n" + "return ( e && e.options && e.options.capped ) ? true : false;}\n" + "DBCollection.prototype.distinct = function( keyString , query ){\n" + "var res = this._dbCommand( { distinct : this._shortName , key : keyString , query : query || {} } );\n" + "if ( ! res.ok )\n" + "throw \"distinct failed: \" + tojson( res );\n" + "return res.values;}\n" + "DBCollection.prototype.group = function( params ){\n" + "params.ns = this._shortName;\n" + "return this._db.group( params );}\n" + "DBCollection.prototype.groupcmd = function( params ){\n" + "params.ns = this._shortName;\n" + "return this._db.groupcmd( params );}\n" + "MapReduceResult = function( db , o ){\n" + "Object.extend( this , o );\n" + "this._o = o;\n" + "this._keys = Object.keySet( o );\n" + "this._db = db;\n" + "this._coll = this._db.getCollection( this.result );}\n" + "MapReduceResult.prototype._simpleKeys = function(){\n" + "return this._o;}\n" + "MapReduceResult.prototype.find = function(){\n" + "return DBCollection.prototype.find.apply( this._coll , arguments );}\n" + "MapReduceResult.prototype.drop = function(){\n" + "return this._coll.drop();}\n" + "\n" + "MapReduceResult.prototype.convertToSingleObject = function(){\n" + "var z = {};\n" + "this._coll.find().forEach( function(a){ z[a._id] = a.value; } );\n" + "return z;}\n" + "\n" + "DBCollection.prototype.mapReduce = function( map , reduce , optional ){\n" + "var c = { mapreduce : this._shortName , map : map , reduce : reduce };\n" + "if ( optional )\n" + "Object.extend( c , optional );\n" + "var raw = this._db.runCommand( c );\n" + "if ( ! raw.ok )\n" + "throw \"map reduce failed: \" + tojson( raw );\n" + "return new MapReduceResult( this._db , raw );}\n" + "DBCollection.prototype.toString = function(){\n" + "return this.getFullName();}\n" + "DBCollection.prototype.toString = function(){\n" + "return this.getFullName();}\n" + "DBCollection.prototype.tojson = DBCollection.prototype.toString;\n" + "DBCollection.prototype.shellPrint = DBCollection.prototype.toString;\n" + ; + diff --git a/shell/msvc/mongo.ico b/shell/msvc/mongo.ico new file mode 100755 index 0000000..1eba9ed Binary files /dev/null and b/shell/msvc/mongo.ico differ diff --git a/shell/msvc/mongo.sln b/shell/msvc/mongo.sln new file mode 100644 index 0000000..01c9e1e --- /dev/null +++ b/shell/msvc/mongo.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mongo", "mongo.vcxproj", "{FE959BD8-8EE2-4555-AE59-9FA14FFD410E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|Win32.Build.0 = Debug|Win32 + {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|Win32.ActiveCfg = Release|Win32 + {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/shell/msvc/mongo.vcxproj b/shell/msvc/mongo.vcxproj new file mode 100644 index 0000000..b158b9e --- /dev/null +++ b/shell/msvc/mongo.vcxproj @@ -0,0 +1,253 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {FE959BD8-8EE2-4555-AE59-9FA14FFD410E} + Win32Proj + mongo + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + \boost\lib\vs2010_32\;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib + $(VCInstallDir)bin;$(WindowsSdkDir)bin\NETFX 4.0 Tools;$(WindowsSdkDir)bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)\bin;$(MSBuildToolsPath32);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); + ..\..\..\readline\include;..\..\..\js\src\;..\..\pcre-7.4;..\..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include + + + ..\..\..\readline\include;..\..\..\js\src\;..\..\pcre-7.4;..\..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include + false + \boost\lib\vs2010_32\;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib + + + + Use + Level3 + Disabled + USE_READLINE;XP_WIN;PCRE_STATIC;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + \boost\ + pch.h + 4355;4800;4267;4244;%(DisableSpecificWarnings) + + + Console + true + ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + Use + MaxSpeed + true + true + USE_READLINE;XP_WIN;_WIN32;PCRE_STATIC;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + \boost\ + pch.h + true + MultiThreaded + 4355;4800;4267;4244;%(DisableSpecificWarnings) + + + Console + true + true + true + ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + NotUsing + NotUsing + + + NotUsing + + + NotUsing + NotUsing + + + NotUsing + + + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + NotUsing + + + + + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + + + + + + Create + pch.h + + + + + + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + + + + + + + + + + + + + + true + + + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/shell/msvc/mongo.vcxproj.filters b/shell/msvc/mongo.vcxproj.filters new file mode 100644 index 0000000..426a8b0 --- /dev/null +++ b/shell/msvc/mongo.vcxproj.filters @@ -0,0 +1,262 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {2a0d6120-434d-4732-ac31-2a7bf077f6ee} + + + {a1e59094-b70c-463a-8dc1-691efe337f14} + + + {2d0fd975-0cc9-43dc-ac8e-53cb8c3a0040} + + + {a33442e2-39da-4c70-8310-6de9fa70cd71} + + + {1044ce7b-72c4-4892-82c0-f46d8708a6ff} + + + {fc0f6c1a-9627-4254-9b5e-0bcb8b3257f3} + + + {30b62472-d7a7-4b8a-8a07-d7d341bc6252} + + + {291e0d72-13ca-42d7-b0fd-2e7b5f89639f} + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {473e7192-9f2a-47c5-ad95-e5b75d4f48f9} + + + {96e4c411-7ab4-4bcd-b7c6-a33059f5d492} + + + + + shell + + + util + + + util\concurrency + + + scripting + + + db + + + client + + + client + + + + shared source files + + + shell + + + shell + + + shared source files + + + shared source files + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + client + + + util + + + db + + + scripting + + + util + + + util + + + util + + + client + + + util + + + util + + + util + + + util + + + client + + + pcre + + + pcre + + + pcre + + + shell + + + shell + + + util + + + shell + + + shared source files + + + shared source files + + + shell + + + scripting + + + util + + + db + + + shell\generated_from_js + + + shell\generated_from_js + + + shared source files + + + + + + _js files + + + _js files + + + _js files + + + _js files + + + _js files + + + _js files + + + _js files + + + + + + + + + + db + + + + + Resource Files + + + \ No newline at end of file diff --git a/shell/query.js b/shell/query.js index 508fba2..ebd3a22 100644 --- a/shell/query.js +++ b/shell/query.js @@ -17,21 +17,27 @@ if ( typeof DBQuery == "undefined" ){ this._cursor = null; this._numReturned = 0; this._special = false; + this._prettyShell = false; } print( "DBQuery probably won't have array access " ); } -DBQuery.prototype.help = function(){ - print( "DBQuery help" ); - print( "\t.sort( {...} )" ) - print( "\t.limit( n )" ) - print( "\t.skip( n )" ) - print( "\t.count() - total # of objects matching query, ignores skip,limit" ) - print( "\t.size() - total # of objects cursor would return skip,limit effect this" ) - print( "\t.explain()" ) - print( "\t.forEach( func )" ) - print( "\t.map( func )" ) - +DBQuery.prototype.help = function () { + print("find() modifiers") + print("\t.sort( {...} )") + print("\t.limit( n )") + print("\t.skip( n )") + print("\t.count() - total # of objects matching query, ignores skip,limit") + print("\t.size() - total # of objects cursor would return, honors skip,limit") + print("\t.explain([verbose])") + print("\t.hint(...)") + print("\t.showDiskLoc() - adds a $diskLoc field to each returned object") + print("\nCursor methods"); + print("\t.forEach( func )") + print("\t.print() - output to console in full pretty format") + print("\t.map( func )") + print("\t.hasNext()") + print("\t.next()") } DBQuery.prototype.clone = function(){ @@ -110,6 +116,16 @@ DBQuery.prototype.next = function(){ return ret; } +DBQuery.prototype.objsLeftInBatch = function(){ + this._exec(); + + var ret = this._cursor.objsLeftInBatch(); + if ( ret.$err ) + throw "error: " + tojson( ret ); + + return ret; +} + DBQuery.prototype.toArray = function(){ if ( this._arr ) return this._arr; @@ -197,6 +213,10 @@ DBQuery.prototype.max = function( max ) { return this._addSpecial( "$max" , max ); } +DBQuery.prototype.showDiskLoc = function() { + return this._addSpecial( "$showDiskLoc" , true); +} + DBQuery.prototype.forEach = function( func ){ while ( this.hasNext() ) func( this.next() ); @@ -213,12 +233,32 @@ DBQuery.prototype.arrayAccess = function( idx ){ return this.toArray()[idx]; } -DBQuery.prototype.explain = function(){ +DBQuery.prototype.explain = function (verbose) { + /* verbose=true --> include allPlans, oldPlan fields */ var n = this.clone(); n._ensureSpecial(); n._query.$explain = true; n._limit = n._limit * -1; - return n.next(); + var e = n.next(); + if (!verbose) { + delete e.allPlans; + delete e.oldPlan; + if (e.shards){ + for (var key in e.shards){ + var s = e.shards[key]; + if(s.length === undefined){ + delete s.allPlans; + delete s.oldPlan; + } else { + for (var i=0; i < s.length; i++){ + delete s[i].allPlans; + delete s[i].oldPlan; + } + } + } + } + } + return e; } DBQuery.prototype.snapshot = function(){ @@ -227,11 +267,16 @@ DBQuery.prototype.snapshot = function(){ return this; } +DBQuery.prototype.pretty = function(){ + this._prettyShell = true; + return this; +} + DBQuery.prototype.shellPrint = function(){ try { var n = 0; - while ( this.hasNext() && n < 20 ){ - var s = tojson( this.next() , "" , true ); + while ( this.hasNext() && n < DBQuery.shellBatchSize ){ + var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , "" , true ); print( s ); n++; } @@ -252,3 +297,5 @@ DBQuery.prototype.shellPrint = function(){ DBQuery.prototype.toString = function(){ return "DBQuery: " + this._ns + " -> " + tojson( this.query ); } + +DBQuery.shellBatchSize = 20; diff --git a/shell/servers.js b/shell/servers.js index f681263..dc33de6 100644 --- a/shell/servers.js +++ b/shell/servers.js @@ -53,21 +53,31 @@ createMongoArgs = function( binaryName , args ){ return fullArgs; } -startMongodTest = function( port , dirname , restart ){ - var f = startMongod; - if ( restart ) +__nextPort = 27000; +startMongodTest = function (port, dirname, restart, extraOptions ) { + if (!port) + port = __nextPort++; + var f = startMongodEmpty; + if (restart) f = startMongodNoReset; - var conn = f.apply( null , [ - { - port : port , - dbpath : "/data/db/" + dirname , - noprealloc : "" , - smallfiles : "" , - oplogSize : "2" , - nohttpinterface : "" - } - ] - ); + if (!dirname) + dirname = "" + port; // e.g., data/db/27000 + + var options = + { + port: port, + dbpath: "/data/db/" + dirname, + noprealloc: "", + smallfiles: "", + oplogSize: "2", + nohttpinterface: "" + }; + + if ( extraOptions ) + Object.extend( options , extraOptions ); + + var conn = f.apply(null, [ options ] ); + conn.name = "localhost:" + port; return conn; } @@ -75,16 +85,18 @@ startMongodTest = function( port , dirname , restart ){ // Start a mongod instance and return a 'Mongo' object connected to it. // This function's arguments are passed as command line arguments to mongod. // The specified 'dbpath' is cleared if it exists, created if not. -startMongod = function(){ +startMongodEmpty = function () { + var args = createMongoArgs("mongod", arguments); - var args = createMongoArgs( "mongod" , arguments ); - - var dbpath = _parsePath.apply( null, args ); - resetDbpath( dbpath ); + var dbpath = _parsePath.apply(null, args); + resetDbpath(dbpath); - return startMongoProgram.apply( null, args ); + return startMongoProgram.apply(null, args); +} +startMongod = function () { + print("WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING RENAME YOUR INVOCATION"); + return startMongodEmpty.apply(null, arguments); } - startMongodNoReset = function(){ var args = createMongoArgs( "mongod" , arguments ); return startMongoProgram.apply( null, args ); @@ -94,10 +106,11 @@ startMongos = function(){ return startMongoProgram.apply( null, createMongoArgs( "mongos" , arguments ) ); } -// Start a mongo program instance (generally mongod or mongos) and return a -// 'Mongo' object connected to it. This function's first argument is the -// program name, and subsequent arguments to this function are passed as -// command line arguments to the program. +/* Start mongod or mongos and return a Mongo() object connected to there. + This function's first argument is "mongod" or "mongos" program name, \ + and subsequent arguments to this function are passed as + command line arguments to the program. +*/ startMongoProgram = function(){ var port = _parsePort.apply( null, arguments ); @@ -132,35 +145,69 @@ myPort = function() { return 27017; } -ShardingTest = function( testName , numServers , verboseLevel , numMongos , otherParams ){ +ShardingTest = function( testName , numShards , verboseLevel , numMongos , otherParams ){ + this._testName = testName; + if ( ! otherParams ) otherParams = {} this._connections = []; - if ( otherParams.sync && numServers < 3 ) + if ( otherParams.sync && numShards < 3 ) throw "if you want sync, you need at least 3 servers"; - 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; - return Array.tojson( this.config.chunks.find( q ).toArray() , "\n" ); + + 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 ){ @@ -258,10 +403,14 @@ ShardingTest.prototype.printCollectionInfo = function( ns , msg ){ out += " mongos " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n"; } + out += this.getChunksString( ns ); + print( out ); } printShardingStatus = function( configDB ){ + if (configDB === undefined) + configDB = db.getSisterDB('config') var version = configDB.getCollection( "version" ).findOne(); if ( version == null ){ @@ -285,17 +434,81 @@ printShardingStatus = function( configDB ){ 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){ + output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) + + " on : " + chunk.shard + " " + tojson( chunk.lastmod ) ); + } + ); + } + ) + } + } + ); + + 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){ - output( "\t" + tojson(z,"",true) ); + 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) ); - output( "\t\tmy chunks" ); - - configDB.chunks.find( { "ns" : new RegExp( "^" + z.name ) } ).sort( { ns : 1 } ).forEach( - function(z){ - output( "\t\t\t" + z.ns + " " + tojson( z.min ) + " -->> " + tojson( z.max ) + - " on : " + z.shard + " " + tojson( z.lastmod ) ); - } - ); + 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 ) ); + + } + ); + } + ) + } } ); @@ -316,6 +529,38 @@ ShardingTest.prototype.onNumShards = function( collName , dbName ){ 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 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# define SIGKILL 9 +#else +# include +# include +# include +# include +# include +#endif + +#include "../client/dbclient.h" +#include "../util/processinfo.h" +#include "utils.h" +#include "../util/text.h" +#include "../util/md5.hpp" + +extern const char * jsconcatcode_server; + +namespace mongo { +#ifdef _WIN32 + inline int close(int fd) { return _close(fd); } + inline int read(int fd, void* buf, size_t size) { return _read(fd, buf, size); } + inline int pipe(int fds[2]) { return _pipe(fds, 4096, _O_TEXT | _O_NOINHERIT); } +#endif + + namespace shellUtils { + + Scope* theScope = 0; + + std::string _dbConnect; + std::string _dbAuth; + + const char *argv0 = 0; + void RecordMyLocation( const char *_argv0 ) { argv0 = _argv0; } + + // helpers + + BSONObj makeUndefined() { + BSONObjBuilder b; + b.appendUndefined( "" ); + return b.obj(); + } + const BSONObj undefined_ = makeUndefined(); + + BSONObj encapsulate( const BSONObj &obj ) { + return BSON( "" << obj ); + } + + // real methods + + mongo::BSONObj JSSleep(const mongo::BSONObj &args){ + assert( args.nFields() == 1 ); + assert( args.firstElement().isNumber() ); + int ms = int( args.firstElement().number() ); + { + auto_ptr< ScriptEngine::Unlocker > u = globalScriptEngine->newThreadUnlocker(); + sleepmillis( ms ); + } + return undefined_; + } + + void goingAwaySoon(); + BSONObj Quit(const BSONObj& args) { + // If not arguments are given first element will be EOO, which + // converts to the integer value 0. + goingAwaySoon(); + int exit_code = int( args.firstElement().number() ); + ::exit(exit_code); + return undefined_; + } + + BSONObj JSGetMemInfo( const BSONObj& args ){ + ProcessInfo pi; + uassert( 10258 , "processinfo not supported" , pi.supported() ); + + BSONObjBuilder e; + e.append( "virtual" , pi.getVirtualMemorySize() ); + e.append( "resident" , pi.getResidentSize() ); + + BSONObjBuilder b; + b.append( "ret" , e.obj() ); + + return b.obj(); + } + + +#ifndef MONGO_SAFE_SHELL + + BSONObj listFiles(const BSONObj& _args){ + static BSONObj cd = BSON( "0" << "." ); + BSONObj args = _args.isEmpty() ? cd : _args; + + uassert( 10257 , "need to specify 1 argument to listFiles" , args.nFields() == 1 ); + + BSONObjBuilder lst; + + string rootname = args.firstElement().valuestrsafe(); + path root( rootname ); + stringstream ss; + ss << "listFiles: no such directory: " << rootname; + string msg = ss.str(); + uassert( 12581, msg.c_str(), boost::filesystem::exists( root ) ); + + directory_iterator end; + directory_iterator i( root); + + int num =0; + while ( i != end ){ + path p = *i; + BSONObjBuilder b; + b << "name" << p.string(); + b.appendBool( "isDirectory", is_directory( p ) ); + if ( ! is_directory( p ) ){ + try { + b.append( "size" , (double)file_size( p ) ); + } + catch ( ... ){ + i++; + continue; + } + } + + stringstream ss; + ss << num; + string name = ss.str(); + lst.append( name, b.done() ); + num++; + i++; + } + + BSONObjBuilder ret; + ret.appendArray( "", lst.done() ); + return ret.obj(); + } + + BSONObj ls(const BSONObj& args) { + BSONObj o = listFiles(args); + if( !o.isEmpty() ) { + for( BSONObj::iterator i = o.firstElement().Obj().begin(); i.more(); ) { + BSONObj f = i.next().Obj(); + cout << f["name"].String(); + if( f["isDirectory"].trueValue() ) cout << '/'; + cout << '\n'; + } + cout.flush(); + } + return BSONObj(); + } + + BSONObj cd(const BSONObj& args) { +#if defined(_WIN32) + std::wstring dir = toWideString( args.firstElement().String().c_str() ); + if( SetCurrentDirectory(dir.c_str()) ) + return BSONObj(); +#else + string dir = args.firstElement().String(); +/* if( chdir(dir.c_str) ) == 0 ) + return BSONObj(); + */ + if( 1 ) return BSON(""<<"implementation not done for posix"); +#endif + return BSON( "" << "change directory failed" ); + } + + BSONObj pwd(const BSONObj&) { + boost::filesystem::path p = boost::filesystem::current_path(); + return BSON( "" << p.string() ); + } + + BSONObj hostname(const BSONObj&) { + return BSON( "" << getHostName() ); + } + + static BSONElement oneArg(const BSONObj& args) { + uassert( 12597 , "need to specify 1 argument" , args.nFields() == 1 ); + return args.firstElement(); + } + + const int CANT_OPEN_FILE = 13300; + + BSONObj cat(const BSONObj& args){ + BSONElement e = oneArg(args); + stringstream ss; + ifstream f(e.valuestrsafe()); + uassert(CANT_OPEN_FILE, "couldn't open file", f.is_open() ); + + streamsize sz = 0; + while( 1 ) { + char ch = 0; + // slow...maybe change one day + f.get(ch); + if( ch == 0 ) break; + ss << ch; + sz += 1; + uassert(13301, "cat() : file to big to load as a variable", sz < 1024 * 1024 * 16); + } + return BSON( "" << ss.str() ); + } + + BSONObj md5sumFile(const BSONObj& args){ + BSONElement e = oneArg(args); + stringstream ss; + FILE* f = fopen(e.valuestrsafe(), "rb"); + uassert(CANT_OPEN_FILE, "couldn't open file", f ); + + md5digest d; + md5_state_t st; + md5_init(&st); + + enum {BUFLEN = 4*1024}; + char buffer[BUFLEN]; + int bytes_read; + while( (bytes_read = fread(buffer, 1, BUFLEN, f)) ) { + md5_append( &st , (const md5_byte_t*)(buffer) , bytes_read ); + } + + md5_finish(&st, d); + return BSON( "" << digestToString( d ) ); + } + + BSONObj mkdir(const BSONObj& args){ + boost::filesystem::create_directories(args.firstElement().String()); + return BSON( "" << true ); + } + + BSONObj removeFile(const BSONObj& args){ + BSONElement e = oneArg(args); + bool found = false; + + path root( args.firstElement().valuestrsafe() ); + if ( boost::filesystem::exists( root ) ){ + found = true; + boost::filesystem::remove_all( root ); + } + + BSONObjBuilder b; + b.appendBool( "removed" , found ); + return b.obj(); + } + map< int, pair< pid_t, int > > dbs; + map< pid_t, int > shells; +#ifdef _WIN32 + map< pid_t, HANDLE > handles; +#endif + + mongo::mutex mongoProgramOutputMutex("mongoProgramOutputMutex"); + stringstream mongoProgramOutput_; + + void goingAwaySoon() { + mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); + mongo::goingAway = true; + } + + void writeMongoProgramOutputLine( int port, int pid, const char *line ) { + mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); + if( mongo::goingAway ) throw "program is terminating"; + stringstream buf; + if ( port > 0 ) + buf << "m" << port << "| " << line; + else + buf << "sh" << pid << "| " << line; + cout << buf.str() << endl; + mongoProgramOutput_ << buf.str() << endl; + } + + // only returns last 100000 characters + BSONObj RawMongoProgramOutput( const BSONObj &args ) { + mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); + string out = mongoProgramOutput_.str(); + size_t len = out.length(); + if ( len > 100000 ) + out = out.substr( len - 100000, 100000 ); + return BSON( "" << out ); + } + + BSONObj ClearRawMongoProgramOutput( const BSONObj &args ) { + mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); + mongoProgramOutput_.str( "" ); + return undefined_; + } + + class ProgramRunner { + vector argv_; + int port_; + int pipe_; + pid_t pid_; + public: + pid_t pid() const { return pid_; } + int port() const { return port_; } + + boost::filesystem::path find(string prog) { + boost::filesystem::path p = prog; +#ifdef _WIN32 + p = change_extension(p, ".exe"); +#endif + + if( boost::filesystem::exists(p) ){ +#ifndef _WIN32 + p = boost::filesystem::initial_path() / p; +#endif + return p; + } + + { + boost::filesystem::path t = boost::filesystem::current_path() / p; + if( boost::filesystem::exists(t) ) return t; + } + try { + if( theScope->type("_path") == String ) { + string path = theScope->getString("_path"); + if( !path.empty() ) { + boost::filesystem::path t = boost::filesystem::path(path) / p; + if( boost::filesystem::exists(t) ) return t; + } + } + } catch(...) { } + { + boost::filesystem::path t = boost::filesystem::initial_path() / p; + if( boost::filesystem::exists(t) ) return t; + } + return p; // not found; might find via system path + } + + ProgramRunner( const BSONObj &args , bool isMongoProgram=true) + { + assert( !args.isEmpty() ); + + string program( args.firstElement().valuestrsafe() ); + assert( !program.empty() ); + boost::filesystem::path programPath = find(program); + + if (isMongoProgram){ +#if 0 + if (program == "mongos") { + argv_.push_back("valgrind"); + argv_.push_back("--log-file=/tmp/mongos-%p.valgrind"); + argv_.push_back("--leak-check=yes"); + argv_.push_back("--suppressions=valgrind.suppressions"); + //argv_.push_back("--error-exitcode=1"); + argv_.push_back("--"); + } +#endif + } + + argv_.push_back( programPath.native_file_string() ); + + port_ = -1; + + BSONObjIterator j( args ); + j.next(); // skip program name (handled above) + while(j.more()) { + BSONElement e = j.next(); + string str; + if ( e.isNumber() ) { + stringstream ss; + ss << e.number(); + str = ss.str(); + } else { + assert( e.type() == mongo::String ); + str = e.valuestr(); + } + if ( str == "--port" ) + port_ = -2; + else if ( port_ == -2 ) + port_ = strtol( str.c_str(), 0, 10 ); + argv_.push_back(str); + } + + if ( program != "mongod" && program != "mongos" && program != "mongobridge" ) + port_ = 0; + else { + if ( port_ <= 0 ) + cout << "error: a port number is expected when running mongod (etc.) from the shell" << endl; + assert( port_ > 0 ); + } + if ( port_ > 0 && dbs.count( port_ ) != 0 ){ + cerr << "count for port: " << port_ << " is not 0 is: " << dbs.count( port_ ) << endl; + assert( dbs.count( port_ ) == 0 ); + } + } + + void start() { + int pipeEnds[ 2 ]; + assert( pipe( pipeEnds ) != -1 ); + + fflush( 0 ); + launch_process(pipeEnds[1]); //sets pid_ + + { + stringstream ss; + ss << "shell: started program"; + for (unsigned i=0; i < argv_.size(); i++) + ss << " " << argv_[i]; + ss << '\n'; + cout << ss.str(); cout.flush(); + } + + if ( port_ > 0 ) + dbs.insert( make_pair( port_, make_pair( pid_, pipeEnds[ 1 ] ) ) ); + else + shells.insert( make_pair( pid_, pipeEnds[ 1 ] ) ); + pipe_ = pipeEnds[ 0 ]; + } + + // Continue reading output + void operator()() { + try { + // This assumes there aren't any 0's in the mongo program output. + // Hope that's ok. + const unsigned bufSize = 8192; + char buf[ bufSize ]; + char temp[ bufSize ]; + char *start = buf; + while( 1 ) { + int lenToRead = ( bufSize - 1 ) - ( start - buf ); + assert( lenToRead > 0 ); + int ret = read( pipe_, (void *)start, lenToRead ); + if( mongo::goingAway ) + break; + assert( ret != -1 ); + start[ ret ] = '\0'; + if ( strlen( start ) != unsigned( ret ) ) + writeMongoProgramOutputLine( port_, pid_, "WARNING: mongod wrote null bytes to output" ); + char *last = buf; + for( char *i = strchr( buf, '\n' ); i; last = i + 1, i = strchr( last, '\n' ) ) { + *i = '\0'; + writeMongoProgramOutputLine( port_, pid_, last ); + } + if ( ret == 0 ) { + if ( *last ) + writeMongoProgramOutputLine( port_, pid_, last ); + close( pipe_ ); + break; + } + if ( last != buf ) { + strcpy( temp, last ); + strcpy( buf, temp ); + } else { + assert( strlen( buf ) < bufSize ); + } + start = buf + strlen( buf ); + } + } catch(...) { + } + } + void launch_process(int child_stdout){ +#ifdef _WIN32 + stringstream ss; + for( unsigned i=0; i < argv_.size(); i++ ){ + if (i) ss << ' '; + if (argv_[i].find(' ') == string::npos) + ss << argv_[i]; + else + ss << '"' << argv_[i] << '"'; + } + + string args = ss.str(); + + boost::scoped_array args_tchar (new TCHAR[args.size() + 1]); + size_t i; + for(i=0; i < args.size(); i++) + args_tchar[i] = args[i]; + args_tchar[i] = 0; + + HANDLE h = (HANDLE)_get_osfhandle(child_stdout); + assert(h != INVALID_HANDLE_VALUE); + assert(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1)); + + STARTUPINFO si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.hStdError = h; + si.hStdOutput = h; + si.dwFlags |= STARTF_USESTDHANDLES; + + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + + bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0; + { + stringstream ss; + ss << "couldn't start process " << argv_[0]; + uassert(13294, ss.str(), success); + } + + CloseHandle(pi.hThread); + + pid_ = pi.dwProcessId; + handles.insert( make_pair( pid_, pi.hProcess ) ); + +#else + + pid_ = fork(); + assert( pid_ != -1 ); + + if ( pid_ == 0 ) { + // DON'T ASSERT IN THIS BLOCK - very bad things will happen + + const char** argv = new const char* [argv_.size()+1]; // don't need to free - in child + for (unsigned i=0; i < argv_.size(); i++){ + argv[i] = argv_[i].c_str(); + } + argv[argv_.size()] = 0; + + if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || + dup2( child_stdout, STDERR_FILENO ) == -1 ) + { + cout << "Unable to dup2 child output: " << errnoWithDescription() << endl; + ::_Exit(-1); //do not pass go, do not call atexit handlers + } + + execvp( argv[ 0 ], const_cast(argv) ); + + cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl; + ::_Exit(-1); + } + +#endif + } + }; + + //returns true if process exited + bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL){ +#ifdef _WIN32 + assert(handles.count(pid)); + HANDLE h = handles[pid]; + + if (block) + WaitForSingleObject(h, INFINITE); + + DWORD tmp; + if(GetExitCodeProcess(h, &tmp)){ + CloseHandle(h); + handles.erase(pid); + if (exit_code) + *exit_code = tmp; + return true; + }else{ + return false; + } +#else + int tmp; + bool ret = (pid == waitpid(pid, &tmp, (block ? 0 : WNOHANG))); + if (exit_code) + *exit_code = WEXITSTATUS(tmp); + return ret; + +#endif + } + + BSONObj WaitProgram( const BSONObj& a ){ + int pid = a.firstElement().numberInt(); + BSONObj x = BSON( "" << wait_for_pid( pid ) ); + shells.erase( pid ); + return x; + } + + BSONObj StartMongoProgram( const BSONObj &a ) { + _nokillop = true; + ProgramRunner r( a ); + r.start(); + boost::thread t( r ); + return BSON( string( "" ) << int( r.pid() ) ); + } + + BSONObj RunMongoProgram( const BSONObj &a ) { + ProgramRunner r( a ); + r.start(); + boost::thread t( r ); + int exit_code; + wait_for_pid( r.pid(), true, &exit_code ); + if ( r.port() > 0 ) { + dbs.erase( r.port() ); + } else { + shells.erase( r.pid() ); + } + return BSON( string( "" ) << exit_code ); + } + + BSONObj RunProgram(const BSONObj &a) { + ProgramRunner r( a, false ); + r.start(); + boost::thread t( r ); + int exit_code; + wait_for_pid(r.pid(), true, &exit_code); + shells.erase( r.pid() ); + return BSON( string( "" ) << exit_code ); + } + + BSONObj ResetDbpath( const BSONObj &a ) { + assert( a.nFields() == 1 ); + string path = a.firstElement().valuestrsafe(); + assert( !path.empty() ); + if ( boost::filesystem::exists( path ) ) + boost::filesystem::remove_all( path ); + boost::filesystem::create_directory( path ); + return undefined_; + } + + void copyDir( const path &from, const path &to ) { + directory_iterator end; + directory_iterator i( from ); + while( i != end ) { + path p = *i; + if ( p.leaf() != "mongod.lock" ) { + if ( is_directory( p ) ) { + path newDir = to / p.leaf(); + boost::filesystem::create_directory( newDir ); + copyDir( p, newDir ); + } else { + boost::filesystem::copy_file( p, to / p.leaf() ); + } + } + ++i; + } + } + + // NOTE target dbpath will be cleared first + BSONObj CopyDbpath( const BSONObj &a ) { + assert( a.nFields() == 2 ); + BSONObjIterator i( a ); + string from = i.next().str(); + string to = i.next().str(); + assert( !from.empty() ); + assert( !to.empty() ); + if ( boost::filesystem::exists( to ) ) + boost::filesystem::remove_all( to ); + boost::filesystem::create_directory( to ); + copyDir( from, to ); + return undefined_; + } + + inline void kill_wrapper(pid_t pid, int sig, int port){ +#ifdef _WIN32 + if (sig == SIGKILL || port == 0){ + assert( handles.count(pid) ); + TerminateProcess(handles[pid], 1); // returns failure for "zombie" processes. + }else{ + DBClientConnection conn; + conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port)); + try { + conn.simpleCommand("admin", NULL, "shutdown"); + } catch (...) { + //Do nothing. This command never returns data to the client and the driver doesn't like that. + } + } +#else + int x = kill( pid, sig ); + if ( x ){ + if ( errno == ESRCH ){ + } + else { + cout << "killFailed: " << errnoWithDescription() << endl; + assert( x == 0 ); + } + } + +#endif + } + + int killDb( int port, pid_t _pid, int signal ) { + pid_t pid; + int exitCode = 0; + if ( port > 0 ) { + if( dbs.count( port ) != 1 ) { + cout << "No db started on port: " << port << endl; + return 0; + } + pid = dbs[ port ].first; + } else { + pid = _pid; + } + + kill_wrapper( pid, signal, port ); + + int i = 0; + for( ; i < 65; ++i ) { + if ( i == 5 ) { + char now[64]; + time_t_to_String(time(0), now); + now[ 20 ] = 0; + cout << now << " process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl; + kill_wrapper( pid, SIGKILL, port ); + } + if(wait_for_pid(pid, false, &exitCode)) + break; + sleepmillis( 1000 ); + } + if ( i == 65 ) { + char now[64]; + time_t_to_String(time(0), now); + now[ 20 ] = 0; + cout << now << " failed to terminate process on port " << port << ", with pid " << pid << endl; + assert( "Failed to terminate process" == 0 ); + } + + if ( port > 0 ) { + close( dbs[ port ].second ); + dbs.erase( port ); + } else { + close( shells[ pid ] ); + shells.erase( pid ); + } + if ( i > 4 || signal == SIGKILL ) { + sleepmillis( 4000 ); // allow operating system to reclaim resources + } + + return exitCode; + } + + int getSignal( const BSONObj &a ) { + int ret = SIGTERM; + if ( a.nFields() == 2 ) { + BSONObjIterator i( a ); + i.next(); + BSONElement e = i.next(); + assert( e.isNumber() ); + ret = int( e.number() ); + } + return ret; + } + + BSONObj StopMongoProgram( const BSONObj &a ) { + assert( a.nFields() == 1 || a.nFields() == 2 ); + assert( a.firstElement().isNumber() ); + int port = int( a.firstElement().number() ); + int code = killDb( port, 0, getSignal( a ) ); + cout << "shell: stopped mongo program on port " << port << endl; + return BSON( "" << code ); + } + + BSONObj StopMongoProgramByPid( const BSONObj &a ) { + assert( a.nFields() == 1 || a.nFields() == 2 ); + assert( a.firstElement().isNumber() ); + int pid = int( a.firstElement().number() ); + int code = killDb( 0, pid, getSignal( a ) ); + cout << "shell: stopped mongo program on pid " << pid << endl; + return BSON( "" << code ); + } + + void KillMongoProgramInstances() { + vector< int > ports; + for( map< int, pair< pid_t, int > >::iterator i = dbs.begin(); i != dbs.end(); ++i ) + ports.push_back( i->first ); + for( vector< int >::iterator i = ports.begin(); i != ports.end(); ++i ) + killDb( *i, 0, SIGTERM ); + vector< pid_t > pids; + for( map< pid_t, int >::iterator i = shells.begin(); i != shells.end(); ++i ) + pids.push_back( i->first ); + for( vector< pid_t >::iterator i = pids.begin(); i != pids.end(); ++i ) + killDb( 0, *i, SIGTERM ); + } +#else // ndef MONGO_SAFE_SHELL + void KillMongoProgramInstances() {} +#endif + + MongoProgramScope::~MongoProgramScope() { + DESTRUCTOR_GUARD( + KillMongoProgramInstances(); + ClearRawMongoProgramOutput( BSONObj() ); + ) + } + + unsigned _randomSeed; + + BSONObj JSSrand( const BSONObj &a ) { + uassert( 12518, "srand requires a single numeric argument", + a.nFields() == 1 && a.firstElement().isNumber() ); + _randomSeed = (unsigned)a.firstElement().numberLong(); // grab least significant digits + return undefined_; + } + + BSONObj JSRand( const BSONObj &a ) { + uassert( 12519, "rand accepts no arguments", a.nFields() == 0 ); + unsigned r; +#if !defined(_WIN32) + r = rand_r( &_randomSeed ); +#else + r = rand(); // seed not used in this case +#endif + return BSON( "" << double( r ) / ( double( RAND_MAX ) + 1 ) ); + } + + BSONObj isWindows(const BSONObj& a){ + uassert( 13006, "isWindows accepts no arguments", a.nFields() == 0 ); +#ifdef _WIN32 + return BSON( "" << true ); +#else + return BSON( "" << false ); +#endif + } + + BSONObj getHostName(const BSONObj& a){ + uassert( 13411, "getHostName accepts no arguments", a.nFields() == 0 ); + char buf[260]; // HOST_NAME_MAX is usually 255 + assert(gethostname(buf, 260) == 0); + buf[259] = '\0'; + return BSON("" << buf); + + } + + void installShellUtils( Scope& scope ){ + theScope = &scope; + scope.injectNative( "sleep" , JSSleep ); + scope.injectNative( "quit", Quit ); + scope.injectNative( "getMemInfo" , JSGetMemInfo ); + scope.injectNative( "_srand" , JSSrand ); + scope.injectNative( "_rand" , JSRand ); + scope.injectNative( "_isWindows" , isWindows ); + +#ifndef MONGO_SAFE_SHELL + //can't launch programs + scope.injectNative( "_startMongoProgram", StartMongoProgram ); + scope.injectNative( "runProgram", RunProgram ); + scope.injectNative( "run", RunProgram ); + scope.injectNative( "runMongoProgram", RunMongoProgram ); + scope.injectNative( "stopMongod", StopMongoProgram ); + scope.injectNative( "stopMongoProgram", StopMongoProgram ); + scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid ); + scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput ); + scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput ); + scope.injectNative( "waitProgram" , WaitProgram ); + + scope.injectNative( "getHostName" , getHostName ); + scope.injectNative( "removeFile" , removeFile ); + scope.injectNative( "listFiles" , listFiles ); + scope.injectNative( "ls" , ls ); + scope.injectNative( "pwd", pwd ); + scope.injectNative( "cd", cd ); + scope.injectNative( "cat", cat ); + scope.injectNative( "hostname", hostname); + scope.injectNative( "resetDbpath", ResetDbpath ); + scope.injectNative( "copyDbpath", CopyDbpath ); + scope.injectNative( "md5sumFile", md5sumFile ); + scope.injectNative( "mkdir" , mkdir ); +#endif + } + + void initScope( Scope &scope ) { + scope.externalSetup(); + mongo::shellUtils::installShellUtils( scope ); + scope.execSetup( jsconcatcode_server , "setupServerCode" ); + + if ( !_dbConnect.empty() ) { + uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) ); + if ( !_dbAuth.empty() ) { + installGlobalUtils( scope ); + uassert( 12514, "login failed", scope.exec( _dbAuth , "(auth)" , true , true , false ) ); + } + } + } + + map< const void*, string > _allMyUris; + bool _nokillop = false; + void onConnect( DBClientWithCommands &c ) { + if ( _nokillop ) { + return; + } + BSONObj info; + if ( c.runCommand( "admin", BSON( "whatsmyuri" << 1 ), info ) ) { + // There's no way to explicitly disconnect a DBClientConnection, but we might allocate + // a new uri on automatic reconnect. So just store one uri per connection. + _allMyUris[ &c ] = info[ "you" ].str(); + } + } + } +} diff --git a/shell/utils.cpp b/shell/utils.cpp deleted file mode 100644 index b10c93d..0000000 --- a/shell/utils.cpp +++ /dev/null @@ -1,713 +0,0 @@ -// utils.cpp -/* - * Copyright 2010 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "../stdafx.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# include -# define SIGKILL 9 -#else -# include -# include -# include -# include -# include -#endif - -#include "../client/dbclient.h" -#include "../util/processinfo.h" -#include "utils.h" - -extern const char * jsconcatcode_server; - -namespace mongo { -#ifdef _WIN32 - inline int close(int fd) { return _close(fd); } - inline int read(int fd, void* buf, size_t size) { return _read(fd, buf, size); } - - inline int pipe(int fds[2]) { return _pipe(fds, 1024, _O_TEXT | _O_NOINHERIT); } -#endif - - namespace shellUtils { - - std::string _dbConnect; - std::string _dbAuth; - - const char *argv0 = 0; - void RecordMyLocation( const char *_argv0 ) { argv0 = _argv0; } - - // helpers - - BSONObj makeUndefined() { - BSONObjBuilder b; - b.appendUndefined( "" ); - return b.obj(); - } - const BSONObj undefined_ = makeUndefined(); - - BSONObj encapsulate( const BSONObj &obj ) { - return BSON( "" << obj ); - } - - void sleepms( int ms ) { - boost::xtime xt; - boost::xtime_get(&xt, boost::TIME_UTC); - xt.sec += ( ms / 1000 ); - xt.nsec += ( ms % 1000 ) * 1000000; - if ( xt.nsec >= 1000000000 ) { - xt.nsec -= 1000000000; - xt.sec++; - } - boost::thread::sleep(xt); - } - - // real methods - - - - mongo::BSONObj JSSleep(const mongo::BSONObj &args){ - assert( args.nFields() == 1 ); - assert( args.firstElement().isNumber() ); - int ms = int( args.firstElement().number() ); - { - auto_ptr< ScriptEngine::Unlocker > u = globalScriptEngine->newThreadUnlocker(); - sleepms( ms ); - } - return undefined_; - } - - - BSONObj Quit(const BSONObj& args) { - // If not arguments are given first element will be EOO, which - // converts to the integer value 0. - int exit_code = int( args.firstElement().number() ); - ::exit(exit_code); - return undefined_; - } - - BSONObj JSGetMemInfo( const BSONObj& args ){ - ProcessInfo pi; - uassert( 10258 , "processinfo not supported" , pi.supported() ); - - BSONObjBuilder e; - e.append( "virtual" , pi.getVirtualMemorySize() ); - e.append( "resident" , pi.getResidentSize() ); - - BSONObjBuilder b; - b.append( "ret" , e.obj() ); - - return b.obj(); - } - - -#ifndef MONGO_SAFE_SHELL - - BSONObj listFiles(const BSONObj& args){ - uassert( 10257 , "need to specify 1 argument to listFiles" , args.nFields() == 1 ); - - BSONObjBuilder lst; - - string rootname = args.firstElement().valuestrsafe(); - path root( rootname ); - stringstream ss; - ss << "listFiles: no such directory: " << rootname; - string msg = ss.str(); - uassert( 12581, msg.c_str(), boost::filesystem::exists( root ) ); - - directory_iterator end; - directory_iterator i( root); - - int num =0; - while ( i != end ){ - path p = *i; - BSONObjBuilder b; - b << "name" << p.string(); - b.appendBool( "isDirectory", is_directory( p ) ); - if ( ! is_directory( p ) ){ - try { - b.append( "size" , (double)file_size( p ) ); - } - catch ( ... ){ - i++; - continue; - } - } - - stringstream ss; - ss << num; - string name = ss.str(); - lst.append( name.c_str(), b.done() ); - num++; - i++; - } - - BSONObjBuilder ret; - ret.appendArray( "", lst.done() ); - return ret.obj(); - } - - - BSONObj removeFile(const BSONObj& args){ - uassert( 12597 , "need to specify 1 argument to listFiles" , args.nFields() == 1 ); - - bool found = false; - - path root( args.firstElement().valuestrsafe() ); - if ( boost::filesystem::exists( root ) ){ - found = true; - boost::filesystem::remove_all( root ); - } - - BSONObjBuilder b; - b.appendBool( "removed" , found ); - return b.obj(); - } - map< int, pair< pid_t, int > > dbs; - map< pid_t, int > shells; -#ifdef _WIN32 - map< pid_t, HANDLE > handles; -#endif - - mongo::mutex mongoProgramOutputMutex; - stringstream mongoProgramOutput_; - - void writeMongoProgramOutputLine( int port, int pid, const char *line ) { - mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); - stringstream buf; - if ( port > 0 ) - buf << "m" << port << "| " << line; - else - buf << "sh" << pid << "| " << line; - cout << buf.str() << endl; - mongoProgramOutput_ << buf.str() << endl; - } - - // only returns last 100000 characters - BSONObj RawMongoProgramOutput( const BSONObj &args ) { - mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); - string out = mongoProgramOutput_.str(); - size_t len = out.length(); - if ( len > 100000 ) - out = out.substr( len - 100000, 100000 ); - return BSON( "" << out ); - } - - BSONObj ClearRawMongoProgramOutput( const BSONObj &args ) { - mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); - mongoProgramOutput_.str( "" ); - return undefined_; - } - - class ProgramRunner { - vector argv_; - int port_; - int pipe_; - pid_t pid_; - public: - pid_t pid() const { return pid_; } - ProgramRunner( const BSONObj &args , bool isMongoProgram=true) - { - assert( !args.isEmpty() ); - - string program( args.firstElement().valuestrsafe() ); - assert( !program.empty() ); - boost::filesystem::path programPath = program; - - if (isMongoProgram){ - programPath = boost::filesystem::initial_path() / programPath; -#ifdef _WIN32 - programPath = change_extension(programPath, ".exe"); -#endif - massert( 10435 , "couldn't find " + programPath.native_file_string(), boost::filesystem::exists( programPath ) ); - } - - argv_.push_back( programPath.native_file_string() ); - - port_ = -1; - - BSONObjIterator j( args ); - j.next(); // skip program name (handled above) - while(j.more()) { - BSONElement e = j.next(); - string str; - if ( e.isNumber() ) { - stringstream ss; - ss << e.number(); - str = ss.str(); - } else { - assert( e.type() == mongo::String ); - str = e.valuestr(); - } - if ( str == "--port" ) - port_ = -2; - else if ( port_ == -2 ) - port_ = strtol( str.c_str(), 0, 10 ); - argv_.push_back(str); - } - - if ( program != "mongod" && program != "mongos" && program != "mongobridge" ) - port_ = 0; - else - assert( port_ > 0 ); - if ( port_ > 0 && dbs.count( port_ ) != 0 ){ - cerr << "count for port: " << port_ << " is not 0 is: " << dbs.count( port_ ) << endl; - assert( dbs.count( port_ ) == 0 ); - } - } - - void start() { - int pipeEnds[ 2 ]; - assert( pipe( pipeEnds ) != -1 ); - - fflush( 0 ); - launch_process(pipeEnds[1]); //sets pid_ - - cout << "shell: started mongo program"; - for (unsigned i=0; i < argv_.size(); i++) - cout << " " << argv_[i]; - cout << endl; - - if ( port_ > 0 ) - dbs.insert( make_pair( port_, make_pair( pid_, pipeEnds[ 1 ] ) ) ); - else - shells.insert( make_pair( pid_, pipeEnds[ 1 ] ) ); - pipe_ = pipeEnds[ 0 ]; - } - - // Continue reading output - void operator()() { - // This assumes there aren't any 0's in the mongo program output. - // Hope that's ok. - char buf[ 1024 ]; - char temp[ 1024 ]; - char *start = buf; - while( 1 ) { - int lenToRead = 1023 - ( start - buf ); - int ret = read( pipe_, (void *)start, lenToRead ); - assert( ret != -1 ); - start[ ret ] = '\0'; - if ( strlen( start ) != unsigned( ret ) ) - writeMongoProgramOutputLine( port_, pid_, "WARNING: mongod wrote null bytes to output" ); - char *last = buf; - for( char *i = strchr( buf, '\n' ); i; last = i + 1, i = strchr( last, '\n' ) ) { - *i = '\0'; - writeMongoProgramOutputLine( port_, pid_, last ); - } - if ( ret == 0 ) { - if ( *last ) - writeMongoProgramOutputLine( port_, pid_, last ); - close( pipe_ ); - break; - } - if ( last != buf ) { - strcpy( temp, last ); - strcpy( buf, temp ); - } else { - assert( strlen( buf ) <= 1023 ); - } - start = buf + strlen( buf ); - } - } - void launch_process(int child_stdout){ -#ifdef _WIN32 - stringstream ss; - for (int i=0; i < argv_.size(); i++){ - if (i) ss << ' '; - if (argv_[i].find(' ') == string::npos) - ss << argv_[i]; - else - ss << '"' << argv_[i] << '"'; - } - - string args = ss.str(); - - boost::scoped_array args_tchar (new TCHAR[args.size() + 1]); - for (size_t i=0; i < args.size()+1; i++) - args_tchar[i] = args[i]; - - HANDLE h = (HANDLE)_get_osfhandle(child_stdout); - assert(h != INVALID_HANDLE_VALUE); - assert(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1)); - - STARTUPINFO si; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.hStdError = h; - si.hStdOutput = h; - si.dwFlags |= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION pi; - ZeroMemory(&pi, sizeof(pi)); - - bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi); - assert(success); - - CloseHandle(pi.hThread); - - pid_ = pi.dwProcessId; - handles.insert( make_pair( pid_, pi.hProcess ) ); - -#else - - pid_ = fork(); - assert( pid_ != -1 ); - - if ( pid_ == 0 ) { - // DON'T ASSERT IN THIS BLOCK - very bad things will happen - - const char** argv = new const char* [argv_.size()+1]; // don't need to free - in child - for (unsigned i=0; i < argv_.size(); i++){ - argv[i] = argv_[i].c_str(); - } - argv[argv_.size()] = 0; - - if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || - dup2( child_stdout, STDERR_FILENO ) == -1 ) - { - cout << "Unable to dup2 child output: " << OUTPUT_ERRNO << endl; - ::_Exit(-1); //do not pass go, do not call atexit handlers - } - - execvp( argv[ 0 ], const_cast(argv) ); - - cout << "Unable to start program: " << OUTPUT_ERRNO << endl; - ::_Exit(-1); - } - -#endif - } - }; - - //returns true if process exited - bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL){ -#ifdef _WIN32 - assert(handles.count(pid)); - HANDLE h = handles[pid]; - - if (block) - WaitForSingleObject(h, INFINITE); - - DWORD tmp; - if(GetExitCodeProcess(h, &tmp)){ - CloseHandle(h); - handles.erase(pid); - if (exit_code) - *exit_code = tmp; - return true; - }else{ - return false; - } -#else - int tmp; - bool ret = (pid == waitpid(pid, &tmp, (block ? 0 : WNOHANG))); - if (exit_code) - *exit_code = WEXITSTATUS(tmp); - return ret; - -#endif - } - BSONObj StartMongoProgram( const BSONObj &a ) { - _nokillop = true; - ProgramRunner r( a ); - r.start(); - boost::thread t( r ); - return BSON( string( "" ) << int( r.pid() ) ); - } - - BSONObj RunMongoProgram( const BSONObj &a ) { - ProgramRunner r( a ); - r.start(); - boost::thread t( r ); - wait_for_pid(r.pid()); - shells.erase( r.pid() ); - return BSON( string( "" ) << int( r.pid() ) ); - } - - BSONObj RunProgram(const BSONObj &a) { - ProgramRunner r( a, false ); - r.start(); - boost::thread t( r ); - int exit_code; - wait_for_pid(r.pid(), true, &exit_code); - shells.erase( r.pid() ); - return BSON( string( "" ) << exit_code ); - } - - BSONObj ResetDbpath( const BSONObj &a ) { - assert( a.nFields() == 1 ); - string path = a.firstElement().valuestrsafe(); - assert( !path.empty() ); - if ( boost::filesystem::exists( path ) ) - boost::filesystem::remove_all( path ); - boost::filesystem::create_directory( path ); - return undefined_; - } - - void copyDir( const path &from, const path &to ) { - directory_iterator end; - directory_iterator i( from ); - while( i != end ) { - path p = *i; - if ( p.leaf() != "mongod.lock" ) { - if ( is_directory( p ) ) { - path newDir = to / p.leaf(); - boost::filesystem::create_directory( newDir ); - copyDir( p, newDir ); - } else { - boost::filesystem::copy_file( p, to / p.leaf() ); - } - } - ++i; - } - } - - // NOTE target dbpath will be cleared first - BSONObj CopyDbpath( const BSONObj &a ) { - assert( a.nFields() == 2 ); - BSONObjIterator i( a ); - string from = i.next().str(); - string to = i.next().str(); - assert( !from.empty() ); - assert( !to.empty() ); - if ( boost::filesystem::exists( to ) ) - boost::filesystem::remove_all( to ); - boost::filesystem::create_directory( to ); - copyDir( from, to ); - return undefined_; - } - - inline void kill_wrapper(pid_t pid, int sig, int port){ -#ifdef _WIN32 - if (sig == SIGKILL || port == 0){ - assert( handles.count(pid) ); - TerminateProcess(handles[pid], 1); // returns failure for "zombie" processes. - }else{ - DBClientConnection conn; - conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port)); - try { - conn.simpleCommand("admin", NULL, "shutdown"); - } catch (...) { - //Do nothing. This command never returns data to the client and the driver doesn't like that. - } - } -#else - assert( 0 == kill( pid, sig ) ); -#endif - } - - - int killDb( int port, pid_t _pid, int signal ) { - pid_t pid; - int exitCode = 0; - if ( port > 0 ) { - if( dbs.count( port ) != 1 ) { - cout << "No db started on port: " << port << endl; - return 0; - } - pid = dbs[ port ].first; - } else { - pid = _pid; - } - - kill_wrapper( pid, signal, port ); - - int i = 0; - for( ; i < 65; ++i ) { - if ( i == 5 ) { - char now[64]; - time_t_to_String(time(0), now); - now[ 20 ] = 0; - cout << now << " process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl; - kill_wrapper( pid, SIGKILL, port ); - } - if(wait_for_pid(pid, false, &exitCode)) - break; - sleepms( 1000 ); - } - if ( i == 65 ) { - char now[64]; - time_t_to_String(time(0), now); - now[ 20 ] = 0; - cout << now << " failed to terminate process on port " << port << ", with pid " << pid << endl; - assert( "Failed to terminate process" == 0 ); - } - - if ( port > 0 ) { - close( dbs[ port ].second ); - dbs.erase( port ); - } else { - close( shells[ pid ] ); - shells.erase( pid ); - } - if ( i > 4 || signal == SIGKILL ) { - sleepms( 4000 ); // allow operating system to reclaim resources - } - - return exitCode; - } - - int getSignal( const BSONObj &a ) { - int ret = SIGTERM; - if ( a.nFields() == 2 ) { - BSONObjIterator i( a ); - i.next(); - BSONElement e = i.next(); - assert( e.isNumber() ); - ret = int( e.number() ); - } - return ret; - } - - BSONObj StopMongoProgram( const BSONObj &a ) { - assert( a.nFields() == 1 || a.nFields() == 2 ); - assert( a.firstElement().isNumber() ); - int port = int( a.firstElement().number() ); - int code = killDb( port, 0, getSignal( a ) ); - cout << "shell: stopped mongo program on port " << port << endl; - return BSON( "" << code ); - } - - BSONObj StopMongoProgramByPid( const BSONObj &a ) { - assert( a.nFields() == 1 || a.nFields() == 2 ); - assert( a.firstElement().isNumber() ); - int pid = int( a.firstElement().number() ); - int code = killDb( 0, pid, getSignal( a ) ); - cout << "shell: stopped mongo program on pid " << pid << endl; - return BSON( "" << code ); - } - - void KillMongoProgramInstances() { - vector< int > ports; - for( map< int, pair< pid_t, int > >::iterator i = dbs.begin(); i != dbs.end(); ++i ) - ports.push_back( i->first ); - for( vector< int >::iterator i = ports.begin(); i != ports.end(); ++i ) - killDb( *i, 0, SIGTERM ); - vector< pid_t > pids; - for( map< pid_t, int >::iterator i = shells.begin(); i != shells.end(); ++i ) - pids.push_back( i->first ); - for( vector< pid_t >::iterator i = pids.begin(); i != pids.end(); ++i ) - killDb( 0, *i, SIGTERM ); - } -#else // ndef MONGO_SAFE_SHELL - void KillMongoProgramInstances() {} -#endif - - MongoProgramScope::~MongoProgramScope() { - DESTRUCTOR_GUARD( - KillMongoProgramInstances(); - ClearRawMongoProgramOutput( BSONObj() ); - ) - } - - unsigned _randomSeed; - - BSONObj JSSrand( const BSONObj &a ) { - uassert( 12518, "srand requires a single numeric argument", - a.nFields() == 1 && a.firstElement().isNumber() ); - _randomSeed = (unsigned)a.firstElement().numberLong(); // grab least significant digits - return undefined_; - } - - BSONObj JSRand( const BSONObj &a ) { - uassert( 12519, "rand accepts no arguments", a.nFields() == 0 ); - unsigned r; -#if !defined(_WIN32) - r = rand_r( &_randomSeed ); -#else - r = rand(); // seed not used in this case -#endif - return BSON( "" << double( r ) / ( double( RAND_MAX ) + 1 ) ); - } - - BSONObj isWindows(const BSONObj& a){ - uassert( 13006, "isWindows accepts no arguments", a.nFields() == 0 ); -#ifdef _WIN32 - return BSON( "" << true ); -#else - return BSON( "" << false ); -#endif - } - - void installShellUtils( Scope& scope ){ - scope.injectNative( "sleep" , JSSleep ); - scope.injectNative( "quit", Quit ); - scope.injectNative( "getMemInfo" , JSGetMemInfo ); - scope.injectNative( "_srand" , JSSrand ); - scope.injectNative( "_rand" , JSRand ); - scope.injectNative( "_isWindows" , isWindows ); - -#ifndef MONGO_SAFE_SHELL - //can't launch programs - scope.injectNative( "_startMongoProgram", StartMongoProgram ); - scope.injectNative( "runProgram", RunProgram ); - scope.injectNative( "runMongoProgram", RunMongoProgram ); - scope.injectNative( "stopMongod", StopMongoProgram ); - scope.injectNative( "stopMongoProgram", StopMongoProgram ); - scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid ); - scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput ); - scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput ); - - //can't access filesystem - scope.injectNative( "removeFile" , removeFile ); - scope.injectNative( "listFiles" , listFiles ); - scope.injectNative( "resetDbpath", ResetDbpath ); - scope.injectNative( "copyDbpath", CopyDbpath ); -#endif - } - - void initScope( Scope &scope ) { - scope.externalSetup(); - mongo::shellUtils::installShellUtils( scope ); - scope.execSetup( jsconcatcode_server , "setupServerCode" ); - - if ( !_dbConnect.empty() ) { - uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) ); - if ( !_dbAuth.empty() ) { - installGlobalUtils( scope ); - uassert( 12514, "login failed", scope.exec( _dbAuth , "(auth)" , true , true , false ) ); - } - } - } - - map< const void*, string > _allMyUris; - bool _nokillop = false; - void onConnect( DBClientWithCommands &c ) { - if ( _nokillop ) { - return; - } - BSONObj info; - if ( c.runCommand( "admin", BSON( "whatsmyuri" << 1 ), info ) ) { - // There's no way to explicitly disconnect a DBClientConnection, but we might allocate - // a new uri on automatic reconnect. So just store one uri per connection. - _allMyUris[ &c ] = info[ "you" ].str(); - } - } - } -} diff --git a/shell/utils.js b/shell/utils.js index 027ba0d..de26403 100644 --- a/shell/utils.js +++ b/shell/utils.js @@ -1,5 +1,5 @@ - __quiet = false; +__magicNoPrint = { __magicNoPrint : 1111 } chatty = function(s){ if ( ! __quiet ) @@ -16,9 +16,11 @@ friendlyEqual = function( a , b ){ return false; } - -doassert = function( msg ){ - print( "assert: " + msg ); +doassert = function (msg) { + if (msg.indexOf("assert") == 0) + print(msg); + else + print("assert: " + msg); throw msg; } @@ -28,7 +30,11 @@ assert = function( b , msg ){ if ( b ) return; - doassert( "assert failed : " + msg ); + doassert( msg == undefined ? "assert failed" : "assert failed : " + msg ); +} + +assert.automsg = function( b ) { + assert( eval( b ), b ); } assert._debug = false; @@ -45,6 +51,10 @@ assert.eq = function( a , b , msg ){ doassert( "[" + tojson( a ) + "] != [" + tojson( b ) + "] are not equal : " + msg ); } +assert.eq.automsg = function( a, b ) { + assert.eq( eval( a ), eval( b ), "[" + a + "] != [" + b + "]" ); +} + assert.neq = function( a , b , msg ){ if ( assert._debug && msg ) print( "in assert for: " + msg ); if ( a != b ) @@ -53,6 +63,30 @@ assert.neq = function( a , b , msg ){ doassert( "[" + a + "] != [" + b + "] are equal : " + msg ); } +assert.repeat = function( f, msg, timeout, interval ) { + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + var start = new Date(); + timeout = timeout || 30000; + interval = interval || 200; + var last; + while( 1 ) { + + if ( typeof( f ) == "string" ){ + if ( eval( f ) ) + return; + } + else { + if ( f() ) + return; + } + + if ( ( new Date() ).getTime() - start.getTime() > timeout ) + break; + sleep( interval ); + } +} + assert.soon = function( f, msg, timeout, interval ) { if ( assert._debug && msg ) print( "in assert for: " + msg ); @@ -89,6 +123,10 @@ assert.throws = function( func , params , msg ){ doassert( "did not throw exception: " + msg ); } +assert.throws.automsg = function( func, params ) { + assert.throws( func, params, func.toString() ); +} + assert.commandWorked = function( res , msg ){ if ( assert._debug && msg ) print( "in assert for: " + msg ); @@ -132,6 +170,23 @@ assert.gt = function( a , b , msg ){ doassert( a + " is not greater than " + b + " : " + msg ); } +assert.lte = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( a <= b ) + return; + doassert( a + " is not less than or eq " + b + " : " + msg ); +} + +assert.gte = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( a >= b ) + return; + doassert( a + " is not greater than or eq " + b + " : " + msg ); +} + + assert.close = function( a , b , msg , places ){ if (places === undefined) { places = 4; @@ -304,6 +359,14 @@ Object.keySet = function( o ) { return ret; } +if ( ! NumberLong.prototype ) { + NumberLong.prototype = {} +} + +NumberLong.prototype.tojson = function() { + return this.toString(); +} + if ( ! ObjectId.prototype ) ObjectId.prototype = {} @@ -317,6 +380,14 @@ ObjectId.prototype.tojson = function(){ ObjectId.prototype.isObjectId = true; +ObjectId.prototype.getTimestamp = function(){ + return new Date(parseInt(this.toString().slice(0,8), 16)*1000); +} + +ObjectId.prototype.equals = function( other){ + return this.str == other.str; +} + if ( typeof( DBPointer ) != "undefined" ){ DBPointer.prototype.fetch = function(){ assert( this.ns , "need a ns" ); @@ -366,12 +437,19 @@ else { } if ( typeof( BinData ) != "undefined" ){ - BinData.prototype.tojson = function(){ - return "BinData type: " + this.type + " len: " + this.len; + BinData.prototype.tojson = function () { + //return "BinData type: " + this.type + " len: " + this.len; + return this.toString(); } } else { - print( "warning: no BinData" ); + print( "warning: no BinData class" ); +} + +if ( typeof( UUID ) != "undefined" ){ + UUID.prototype.tojson = function () { + return this.toString(); + } } if ( typeof _threadInject != "undefined" ){ @@ -489,7 +567,9 @@ if ( typeof _threadInject != "undefined" ){ "jstests/indexb.js", "jstests/profile1.js", "jstests/mr3.js", - "jstests/apitest_db.js"] ); + "jstests/indexh.js", + "jstests/apitest_db.js", + "jstests/evalb.js"] ); // some tests can't be run in parallel with each other var serialTestsArr = [ "jstests/fsync.js", @@ -505,8 +585,8 @@ if ( typeof _threadInject != "undefined" ){ files.forEach( function(x) { - if ( /_runner/.test(x.name) || - /_lodeRunner/.test(x.name) || + if ( ( /[\/\\]_/.test(x.name) ) || + ( ! /\.js$/.test(x.name ) ) || ( x.name in skipTests ) || ( x.name in serialTests ) || ! /\.js$/.test(x.name ) ){ @@ -587,6 +667,10 @@ if ( typeof _threadInject != "undefined" ){ } } +tojsononeline = function( x ){ + return tojson( x , " " , true ); +} + tojson = function( x, indent , nolint ){ if ( x === null ) return "null"; @@ -597,24 +681,34 @@ tojson = function( x, indent , nolint ){ if (!indent) indent = ""; - switch ( typeof x ){ - + switch ( typeof x ) { case "string": { var s = "\""; for ( var i=0; i= 1ms"); - print( "\t" + "use set curent database to " ); - print( "\t" + "db.help() help on DB methods"); - print( "\t" + "db.foo.help() help on collection methods"); - print( "\t" + "db.foo.find() list objects in collection foo" ); - print( "\t" + "db.foo.find( { a : 1 } ) list objects in foo where a == 1" ); - print( "\t" + "it result of the last line evaluated; use to further iterate"); -} - shellHelper.use = function( dbname ){ db = db.getMongo().getDB( dbname ); print( "switched to db " + db.getName() ); @@ -884,6 +975,7 @@ Map.prototype.values = function(){ if ( typeof( gc ) == "undefined" ){ gc = function(){ + print( "warning: using noop gc()" ); } } @@ -953,3 +1045,108 @@ Geo.distance = function( a , b ){ return Math.sqrt( Math.pow( by - ay , 2 ) + Math.pow( bx - ax , 2 ) ); } + +rs = function () { return "try rs.help()"; } + +rs.help = function () { + print("\trs.status() { replSetGetStatus : 1 } checks repl set status"); + print("\trs.initiate() { replSetInitiate : null } initiates set with default settings"); + print("\trs.initiate(cfg) { replSetInitiate : cfg } initiates set with configuration cfg"); + print("\trs.add(hostportstr) add a new member to the set with default attributes"); + print("\trs.add(membercfgobj) add a new member to the set with extra attributes"); + print("\trs.addArb(hostportstr) add a new member which is arbiterOnly:true"); + print("\trs.stepDown() step down as primary (momentarily)"); + print("\trs.conf() return configuration from local.system.replset"); + print("\trs.slaveOk() shorthand for db.getMongo().setSlaveOk()"); + print(); + print("\tdb.isMaster() check who is primary"); + print(); + print("\tsee also http://:28017/_replSet for additional diagnostic info"); +} +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.add = function (hostport, arb) { + var cfg = hostport; + + var local = db.getSisterDB("local"); + assert(local.system.replset.count() <= 1, "error: local.system.replset has unexpected contents"); + var c = local.system.replset.findOne(); + assert(c, "no config object retrievable from local.system.replset"); + c.version++; + var max = 0; + for (var i in c.members) + if (c.members[i]._id > max) max = c.members[i]._id; + if (isString(hostport)) { + cfg = { _id: max + 1, host: hostport }; + if (arb) + cfg.arbiterOnly = true; + } + c.members.push(cfg); + return db._adminCommand({ replSetReconfig: c }); +} +rs.stepDown = function () { return db._adminCommand({ replSetStepDown:true}); } +rs.addArb = function (hn) { return this.add(hn, true); } +rs.conf = function () { return db.getSisterDB("local").system.replset.findOne(); } + +help = shellHelper.help = function (x) { + if (x == "connect") { + print("\nNormally one specifies the server on the mongo shell command line. Run mongo --help to see those options."); + print("Additional connections may be opened:\n"); + print(" var x = new Mongo('host[:port]');"); + print(" var mydb = x.getDB('mydb');"); + print(" or"); + print(" var mydb = connect('host[:port]/mydb');"); + print("\nNote: the REPL prompt only auto-reports getLastError() for the shell command line connection.\n"); + return; + } + if (x == "misc") { + print("\tb = new BinData(subtype,base64str) create a BSON BinData value"); + print("\tb.subtype() the BinData subtype (0..255)"); + print("\tb.length() length of the BinData data in bytes"); + print("\tb.hex() the data as a hex encoded string"); + print("\tb.base64() the data as a base 64 encoded string"); + print("\tb.toString()"); + return; + } + if (x == "admin") { + print("\tls([path]) list files"); + print("\tpwd() returns current directory"); + print("\tlistFiles([path]) returns file list"); + print("\thostname() returns name of this host"); + print("\tcat(fname) returns contents of text file as a string"); + print("\tremoveFile(f) delete a file"); + print("\tload(jsfilename) load and execute a .js file"); + print("\trun(program[, args...]) spawn a program and wait for its completion"); + print("\tsleep(m) sleep m milliseconds"); + print("\tgetMemInfo() diagnostic"); + return; + } + if (x == "test") { + print("\tstartMongodEmpty(args) DELETES DATA DIR and then starts mongod"); + print("\t returns a connection to the new server"); + print("\tstartMongodTest() DELETES DATA DIR"); + print("\t automatically picks port #s starting at 27000 and increasing"); + print("\t or you can specify the port as the first arg"); + print("\t dir is /data/db// if not specified as the 2nd arg"); + print("\t returns a connection to the new server"); + return; + } + 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 misc misc things to know"); + 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" + "use 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"); + print("\t" + "it result of the last line evaluated; use to further iterate"); + print("\t" + "exit quit the mongo shell"); +} -- cgit v1.2.3