summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/collection.js72
-rw-r--r--shell/db.js30
-rw-r--r--shell/dbshell.cpp65
-rw-r--r--shell/mongo.js2
-rw-r--r--shell/mongo_vstudio.cpp2795
-rw-r--r--shell/query.js38
-rw-r--r--shell/servers.js150
-rw-r--r--shell/utils.cpp504
-rw-r--r--shell/utils.h23
-rw-r--r--shell/utils.js54
10 files changed, 1829 insertions, 1904 deletions
diff --git a/shell/collection.js b/shell/collection.js
index d228ba7..edb07ae 100644
--- a/shell/collection.js
+++ b/shell/collection.js
@@ -26,15 +26,16 @@ DBCollection.prototype.getName = function(){
return this._shortName;
}
-DBCollection.prototype.help = function(){
+DBCollection.prototype.help = function() {
print("DBCollection help");
print("\tdb.foo.count()");
print("\tdb.foo.dataSize()");
- print("\tdb.foo.distinct( key ) - eg. db.foo.distinct( 'x' )" );
+ 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()");
@@ -46,9 +47,10 @@ DBCollection.prototype.help = function(){
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 , <optional params> )" );
- print("\tdb.foo.remove(query)" );
+ print("\tdb.foo.mapReduce( mapFunction , reduceFunction , <optional params> )");
+ print("\tdb.foo.remove(query)");
print("\tdb.foo.renameCollection( newName , <dropTarget> ) renames the collection.");
+ print("\tdb.foo.runCommand( name , <options> ) 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");
@@ -56,7 +58,7 @@ DBCollection.prototype.help = function(){
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.foo.getShardVersion() - only for use with sharding");
}
DBCollection.prototype.getFullName = function(){
@@ -66,10 +68,19 @@ DBCollection.prototype.getDB = function(){
return this._db;
}
-DBCollection.prototype._dbCommand = function( cmd ){
- return this._db._dbCommand( cmd );
+DBCollection.prototype._dbCommand = function( cmd , params ){
+ if ( typeof( cmd ) == "object" )
+ return this._db._dbCommand( cmd );
+
+ var c = {};
+ c[cmd] = this.getName();
+ if ( params )
+ Object.extend( c , params );
+ return this._db._dbCommand( c );
}
+DBCollection.prototype.runCommand = DBCollection.prototype._dbCommand;
+
DBCollection.prototype._massageObject = function( q ){
if ( ! q )
return {};
@@ -128,7 +139,7 @@ DBCollection.prototype.find = function( query , fields , limit , skip ){
}
DBCollection.prototype.findOne = function( query , fields ){
- var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , -1 , 0 );
+ var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , -1 , 0 , 0 );
if ( ! cursor.hasNext() )
return null;
var ret = cursor.next();
@@ -144,7 +155,15 @@ DBCollection.prototype.insert = function( obj , _allow_dot ){
if ( ! _allow_dot ) {
this._validateForStorage( obj );
}
- return this._mongo.insert( this._fullName , obj );
+ if ( typeof( obj._id ) == "undefined" ){
+ var tmp = obj; // don't want to modify input
+ obj = {_id: new ObjectId()};
+ for (var key in tmp){
+ obj[key] = tmp[key];
+ }
+ }
+ this._mongo.insert( this._fullName , obj );
+ this._lastID = obj._id;
}
DBCollection.prototype.remove = function( t ){
@@ -275,12 +294,8 @@ DBCollection.prototype.resetIndexCache = function(){
this._indexCache = {};
}
-DBCollection.prototype.reIndex = function(){
- var specs = this.getIndexSpecs();
- this.dropIndexes();
- for ( var i = 0; i < specs.length; ++i ){
- this.ensureIndex( specs[i].key, [ specs[i].unique, specs[i].name ] );
- }
+DBCollection.prototype.reIndex = function() {
+ return this._db.runCommand({ reIndex: this.getName() });
}
DBCollection.prototype.dropIndexes = function(){
@@ -311,7 +326,7 @@ DBCollection.prototype.drop = function(){
DBCollection.prototype.findAndModify = function(args){
var cmd = { findandmodify: this.getName() };
- for (key in args){
+ for (var key in args){
cmd[key] = args[key];
}
@@ -402,7 +417,7 @@ DBCollection.prototype.dropIndex = function(index) {
if ( ! isString( index ) && isObject( index ) )
index = this._genIndexName( index );
- var res = this._dbCommand( { deleteIndexes: this.getName(), index: index } );
+ var res = this._dbCommand( "deleteIndexes" ,{ index: index } );
this.resetIndexCache();
return res;
}
@@ -431,8 +446,8 @@ DBCollection.prototype.getCollection = function( subName ){
return this._db.getCollection( this._shortName + "." + subName );
}
-DBCollection.prototype.stats = function(){
- return this._db.runCommand( { collstats : this._shortName } );
+DBCollection.prototype.stats = function( scale ){
+ return this._db.runCommand( { collstats : this._shortName , scale : scale } );
}
DBCollection.prototype.dataSize = function(){
@@ -444,20 +459,13 @@ DBCollection.prototype.storageSize = function(){
}
DBCollection.prototype.totalIndexSize = function( verbose ){
- var total = 0;
- var mydb = this._db;
- var shortName = this._shortName;
- this.getIndexes().forEach(
- function( spec ){
- var coll = mydb.getCollection( shortName + ".$" + spec.name );
- var mysize = coll.dataSize();
- total += coll.dataSize();
- if ( verbose ) {
- print( coll + "\t" + mysize );
- }
+ var stats = this.stats();
+ if (verbose){
+ for (var ns in stats.indexSizes){
+ print( ns + "\t" + stats.indexSizes[ns] );
}
- );
- return total;
+ }
+ return stats.totalIndexSize;
}
diff --git a/shell/db.js b/shell/db.js
index ab79e22..bdb1153 100644
--- a/shell/db.js
+++ b/shell/db.js
@@ -20,6 +20,10 @@ DB.prototype.getName = function(){
return this._name;
}
+DB.prototype.stats = function(){
+ return this.runCommand( { dbstats : 1 } );
+}
+
DB.prototype.getCollection = function( name ){
return new DBCollection( this._mongo , this , name , this._name + "." + name );
}
@@ -48,10 +52,12 @@ DB.prototype._adminCommand = function( obj ){
return this.getSisterDB( "admin" ).runCommand( obj );
}
-DB.prototype.addUser = function( username , pass ){
+DB.prototype.addUser = function( username , pass, readOnly ){
+ readOnly = readOnly || false;
var c = this.getCollection( "system.users" );
var u = c.findOne( { user : username } ) || { user : username };
+ u.readOnly = readOnly;
u.pwd = hex_md5( username + ":mongo:" + pass );
print( tojson( u ) );
@@ -62,6 +68,10 @@ DB.prototype.removeUser = function( username ){
this.getCollection( "system.users" ).remove( { user : username } );
}
+DB.prototype.__pwHash = function( nonce, username, pass ) {
+ return hex_md5( nonce + username + hex_md5( username + ":mongo:" + pass ) );
+}
+
DB.prototype.auth = function( username , pass ){
var n = this.runCommand( { getnonce : 1 } );
@@ -70,7 +80,7 @@ DB.prototype.auth = function( username , pass ){
authenticate : 1 ,
user : username ,
nonce : n.nonce ,
- key : hex_md5( n.nonce + username + hex_md5( username + ":mongo:" + pass ) )
+ key : this.__pwHash( n.nonce, username, pass )
}
);
@@ -219,12 +229,16 @@ DB.prototype.cloneCollection = function(from, collection, query) {
* @return Object returned has member ok set to true if operation succeeds, false otherwise.
* See also: db.clone()
*/
-DB.prototype.copyDatabase = function(fromdb, todb, fromhost) {
+DB.prototype.copyDatabase = function(fromdb, todb, fromhost, username, password) {
assert( isString(fromdb) && fromdb.length );
assert( isString(todb) && todb.length );
fromhost = fromhost || "";
- //this.resetIndexCache();
- return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );
+ if ( username && password ) {
+ var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );
+ return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );
+ } else {
+ return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );
+ }
}
/**
@@ -239,7 +253,7 @@ DB.prototype.repairDatabase = function() {
DB.prototype.help = function() {
print("DB methods:");
- print("\tdb.addUser(username, password)");
+ print("\tdb.addUser(username, password[, readOnly=false])");
print("\tdb.auth(username, password)");
print("\tdb.cloneDatabase(fromhost)");
print("\tdb.commandHelp(name) returns the help for the command");
@@ -268,8 +282,10 @@ DB.prototype.help = function() {
print("\tdb.repairDatabase()");
print("\tdb.resetError()");
print("\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }");
+ print("\tdb.serverStatus()");
print("\tdb.setProfilingLevel(level,<slowms>) 0=off 1=slow 2=all");
print("\tdb.shutdownServer()");
+ print("\tdb.stats()");
print("\tdb.version() current version of the server" );
}
@@ -490,7 +506,7 @@ DB.prototype.getCollectionNames = function(){
function(z){
var name = z.name;
- if ( name.indexOf( "$" ) >= 0 )
+ if ( name.indexOf( "$" ) >= 0 && name != "local.oplog.$main" )
return;
all.push( name.substring( nsLength ) );
diff --git a/shell/dbshell.cpp b/shell/dbshell.cpp
index 7984383..cad3698 100644
--- a/shell/dbshell.cpp
+++ b/shell/dbshell.cpp
@@ -1,4 +1,20 @@
// dbshell.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 <stdio.h>
@@ -51,7 +67,8 @@ void shellHistoryAdd( const char * line ){
if ( strlen(line) == 0 )
return;
#ifdef USE_READLINE
- add_history( line );
+ if ((strstr(line, ".auth")) == NULL)
+ add_history( line );
#endif
}
@@ -62,6 +79,21 @@ void intr( int sig ){
}
#if !defined(_WIN32)
+void killOps() {
+ if ( mongo::shellUtils::_nokillop || mongo::shellUtils::_allMyUris.size() == 0 )
+ 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 );
+ mongo::BSONObj spec = BSON( "" << uris );
+ try {
+ auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
+ scope->invoke( "function( x ) { killWithUris( x ); }", spec );
+ } catch ( ... ) {
+ mongo::rawOut( "exception while cleaning up any db ops started by this shell\n" );
+ }
+}
+
void quitNicely( int sig ){
if ( sig == SIGINT && inMultiLine ){
gotInterrupted = 1;
@@ -69,6 +101,7 @@ void quitNicely( int sig ){
}
if ( sig == SIGPIPE )
mongo::rawOut( "mongo got signal SIGPIPE\n" );
+ killOps();
shellHistoryDone();
exit(0);
}
@@ -93,7 +126,7 @@ char * shellReadline( const char * prompt , int handlesigint = 0 ){
signal( SIGINT , quitNicely );
return ret;
#else
- printf( prompt );
+ printf("%s", prompt);
char * buf = new char[1024];
char * l = fgets( buf , 1024 , stdin );
int len = strlen( buf );
@@ -289,6 +322,7 @@ int _main(int argc, char* argv[]) {
hidden_options.add_options()
("dbaddress", po::value<string>(), "dbaddress")
("files", po::value< vector<string> >(), "files")
+ ("nokillop", "nokillop") // for testing, kill op will also be disabled automatically if the tests starts a mongo program
;
positional_options.add("dbaddress", 1);
@@ -336,7 +370,10 @@ int _main(int argc, char* argv[]) {
if (params.count("quiet")) {
mongo::cmdLine.quiet = true;
}
-
+ if (params.count("nokillop")) {
+ mongo::shellUtils::_nokillop = true;
+ }
+
/* This is a bit confusing, here are the rules:
*
* if nodb is set then all positional parameters are files
@@ -382,6 +419,7 @@ int _main(int argc, char* argv[]) {
}
+ mongo::ScriptEngine::setConnectCallback( mongo::shellUtils::onConnect );
mongo::ScriptEngine::setup();
mongo::globalScriptEngine->setScopeInitCallback( mongo::shellUtils::initScope );
auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
@@ -433,7 +471,7 @@ int _main(int argc, char* argv[]) {
}
string code = line;
- if ( code == "exit" ){
+ if ( code == "exit" || code == "exit;" ){
break;
}
if ( code.size() == 0 )
@@ -455,9 +493,15 @@ int _main(int argc, char* argv[]) {
cmd = cmd.substr( 0 , cmd.find( " " ) );
if ( cmd.find( "\"" ) == string::npos ){
- scope->exec( (string)"__iscmd__ = shellHelper[\"" + cmd + "\"];" , "(shellhelp1)" , false , true , true );
- if ( scope->getBoolean( "__iscmd__" ) ){
- scope->exec( (string)"shellHelper( \"" + cmd + "\" , \"" + code.substr( cmd.size() ) + "\");" , "(shellhelp2)" , false , true , false );
+ try {
+ scope->exec( (string)"__iscmd__ = shellHelper[\"" + cmd + "\"];" , "(shellhelp1)" , false , true , true );
+ if ( scope->getBoolean( "__iscmd__" ) ){
+ scope->exec( (string)"shellHelper( \"" + cmd + "\" , \"" + code.substr( cmd.size() ) + "\");" , "(shellhelp2)" , false , true , false );
+ wascmd = true;
+ }
+ }
+ catch ( std::exception& e ){
+ cout << "error2:" << e.what() << endl;
wascmd = true;
}
}
@@ -485,6 +529,7 @@ int _main(int argc, char* argv[]) {
}
int main(int argc, char* argv[]) {
+ static mongo::StaticObserver staticObserver;
try {
return _main( argc , argv );
}
@@ -494,10 +539,4 @@ int main(int argc, char* argv[]) {
}
}
-namespace mongo {
- DBClientBase * createDirectClient(){
- uassert( 10256 , "no createDirectClient in shell" , 0 );
- return 0;
- }
-}
diff --git a/shell/mongo.js b/shell/mongo.js
index dc7fcd9..acd028b 100644
--- a/shell/mongo.js
+++ b/shell/mongo.js
@@ -34,7 +34,7 @@ Mongo.prototype.getDB = function( name ){
Mongo.prototype.getDBs = function(){
var res = this.getDB( "admin" ).runCommand( { "listDatabases" : 1 } );
- assert( res.ok == 1 , "listDatabases failed" );
+ assert( res.ok == 1 , "listDatabases failed:" + tojson( res ) );
return res;
}
diff --git a/shell/mongo_vstudio.cpp b/shell/mongo_vstudio.cpp
index d0f1b48..f88b3c2 100644
--- a/shell/mongo_vstudio.cpp
+++ b/shell/mongo_vstudio.cpp
@@ -1,446 +1,616 @@
const char * jsconcatcode =
-"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"
- "}\n"
- "}\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"
- "}\n"
- "DBCollection.prototype.getName = function(){\n"
- "return this._shortName;\n"
- "}\n"
- "DBCollection.prototype.help = function(){\n"
- "print(\"DBCollection help\");\n"
- "print(\"\\tdb.foo.getDB() get DB object associated with collection\");\n"
- "print(\"\\tdb.foo.findOne([query])\");\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(...).sort(...)\");\n"
- "print(\"\\tdb.foo.find(...).limit(n)\");\n"
- "print(\"\\tdb.foo.find(...).skip(n)\");\n"
- "print(\"\\tdb.foo.find(...).count()\");\n"
- "print(\"\\tdb.foo.count()\");\n"
- "print(\"\\tdb.foo.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )\");\n"
- "print(\"\\tdb.foo.save(obj)\");\n"
- "print(\"\\tdb.foo.update(query, object[, upsert_bool])\");\n"
- "print(\"\\tdb.foo.remove(query)\" );\n"
- "print(\"\\tdb.foo.ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups\");\n"
- "print(\"\\tdb.foo.dropIndexes()\");\n"
- "print(\"\\tdb.foo.dropIndex(name)\");\n"
- "print(\"\\tdb.foo.getIndexes()\");\n"
- "print(\"\\tdb.foo.drop() drop the collection\");\n"
- "print(\"\\tdb.foo.renameCollection( newName ) renames the collection\");\n"
- "print(\"\\tdb.foo.validate() - SLOW\");\n"
- "print(\"\\tdb.foo.stats()\");\n"
- "print(\"\\tdb.foo.dataSize()\");\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"
- "}\n"
- "DBCollection.prototype.getFullName = function(){\n"
- "return this._fullName;\n"
- "}\n"
- "DBCollection.prototype.getDB = function(){\n"
- "return this._db;\n"
- "}\n"
- "DBCollection.prototype._dbCommand = function( cmd ){\n"
- "return this._db._dbCommand( cmd );\n"
- "}\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"
- "}\n"
- "throw \"don't know how to massage : \" + type;\n"
- "}\n"
- "DBCollection.prototype._validateObject = function( o ){\n"
- "if ( o._ensureSpecial && o._checkModify )\n"
- "throw \"can't save a DBQuery object\";\n"
- "}\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"
- "}\n"
- "if ( k.indexOf( \"$\" ) == 0 && ! DBCollection._allowedFields[k] ) {\n"
- "throw \"field names cannot start with $ [\" + k + \"]\";\n"
- "}\n"
- "if ( o[k] !== null && typeof( o[k] ) === \"object\" ) {\n"
- "this._validateForStorage( o[k] );\n"
- "}\n"
- "}\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"
- "}\n"
- "DBCollection.prototype.findOne = function( query , fields ){\n"
- "var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , -1 , 0 );\n"
- "if ( ! cursor.hasNext() )\n"
+"__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<a.length; i++ )\n"
+ "arr[i] = a[i];\n"
+ "return arr;}\n"
+ "isString = function( x ){\n"
+ "return typeof( x ) == \"string\";}\n"
+ "isNumber = function(x){\n"
+ "return typeof( x ) == \"number\";}\n"
+ "isObject = function( x ){\n"
+ "return typeof( x ) == \"object\";}\n"
+ "String.prototype.trim = function() {\n"
+ "return this.replace(/^\\s+|\\s+$/g,\"\");}\n"
+ "String.prototype.ltrim = function() {\n"
+ "return this.replace(/^\\s+/,\"\");}\n"
+ "String.prototype.rtrim = function() {\n"
+ "return this.replace(/\\s+$/,\"\");}\n"
+ "Date.timeFunc = function( theFunc , numTimes ){\n"
+ "var start = new Date();\n"
+ "numTimes = numTimes || 1;\n"
+ "for ( var i=0; i<numTimes; i++ ){\n"
+ "theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) );}\n"
+ "return (new Date()).getTime() - start.getTime();}\n"
+ "Date.prototype.tojson = function(){\n"
+ "return \"\\\"\" + this.toString() + \"\\\"\";}\n"
+ "RegExp.prototype.tojson = RegExp.prototype.toString;\n"
+ "Array.contains = function( a , x ){\n"
+ "for ( var i=0; i<a.length; i++ ){\n"
+ "if ( a[i] == x )\n"
+ "return true;}\n"
+ "return false;}\n"
+ "Array.unique = function( a ){\n"
+ "var u = [];\n"
+ "for ( var i=0; i<a.length; i++){\n"
+ "var o = a[i];\n"
+ "if ( ! Array.contains( u , o ) ){\n"
+ "u.push( o );}}\n"
+ "return u;}\n"
+ "Array.shuffle = function( arr ){\n"
+ "for ( var i=0; i<arr.length-1; i++ ){\n"
+ "var pos = i+Random.randInt(arr.length-i);\n"
+ "var save = arr[i];\n"
+ "arr[i] = arr[pos];\n"
+ "arr[pos] = save;}\n"
+ "return arr;}\n"
+ "Array.tojson = function( a , indent ){\n"
+ "if (!indent)\n"
+ "indent = \"\";\n"
+ "if (a.length == 0) {\n"
+ "return \"[ ]\";}\n"
+ "var s = \"[\\n\";\n"
+ "indent += \"\\t\";\n"
+ "for ( var i=0; i<a.length; i++){\n"
+ "s += indent + tojson( a[i], indent );\n"
+ "if ( i < a.length - 1 ){\n"
+ "s += \",\\n\";}}\n"
+ "if ( a.length == 0 ) {\n"
+ "s += indent;}\n"
+ "indent = indent.substring(1);\n"
+ "s += \"\\n\"+indent+\"]\";\n"
+ "return s;}\n"
+ "Array.fetchRefs = function( arr , coll ){\n"
+ "var n = [];\n"
+ "for ( var i=0; i<arr.length; i ++){\n"
+ "var z = arr[i];\n"
+ "if ( coll && coll != z.getCollection() )\n"
+ "continue;\n"
+ "n.push( z.fetch() );}\n"
+ "return n;}\n"
+ "Array.sum = function( arr ){\n"
+ "if ( arr.length == 0 )\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"
- "}\n"
- "DBCollection.prototype.insert = function( obj , _allow_dot ){\n"
- "if ( ! obj )\n"
- "throw \"no object!\";\n"
- "if ( ! _allow_dot ) {\n"
- "this._validateForStorage( obj );\n"
- "}\n"
- "return this._mongo.insert( this._fullName , obj );\n"
- "}\n"
- "DBCollection.prototype.remove = function( t ){\n"
- "this._mongo.remove( this._fullName , this._massageObject( t ) );\n"
- "}\n"
- "DBCollection.prototype.update = function( query , obj , upsert ){\n"
- "assert( query , \"need a query\" );\n"
- "assert( obj , \"need an object\" );\n"
- "this._validateObject( obj );\n"
- "return this._mongo.update( this._fullName , query , obj , upsert ? true : false );\n"
- "}\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"
- "}\n"
+ "var s = arr[0];\n"
+ "for ( var i=1; i<arr.length; i++ )\n"
+ "s += arr[i];\n"
+ "return s;}\n"
+ "Array.avg = function( arr ){\n"
+ "if ( arr.length == 0 )\n"
+ "return null;\n"
+ "return Array.sum( arr ) / arr.length;}\n"
+ "Array.stdDev = function( arr ){\n"
+ "var avg = Array.avg( arr );\n"
+ "var sum = 0;\n"
+ "for ( var i=0; i<arr.length; i++ ){\n"
+ "sum += Math.pow( arr[i] - avg , 2 );}\n"
+ "return Math.sqrt( sum / arr.length );}\n"
+ "Object.keySet = function( o ) {\n"
+ "var ret = new Array();\n"
+ "for( i in o ) {\n"
+ "if ( !( i in o.__proto__ && o[ i ] === o.__proto__[ i ] ) ) {\n"
+ "ret.push( i );}}\n"
+ "return ret;}\n"
+ "if ( ! ObjectId.prototype )\n"
+ "ObjectId.prototype = {}\n"
+ "ObjectId.prototype.toString = function(){\n"
+ "return this.str;}\n"
+ "ObjectId.prototype.tojson = function(){\n"
+ "return \"ObjectId(\\\"\" + this.str + \"\\\")\";}\n"
+ "ObjectId.prototype.isObjectId = true;\n"
+ "if ( typeof( DBPointer ) != \"undefined\" ){\n"
+ "DBPointer.prototype.fetch = function(){\n"
+ "assert( this.ns , \"need a ns\" );\n"
+ "assert( this.id , \"need an id\" );\n"
+ "return db[ this.ns ].findOne( { _id : this.id } );}\n"
+ "DBPointer.prototype.tojson = function(indent){\n"
+ "return tojson({\"ns\" : this.ns, \"id\" : this.id}, indent);}\n"
+ "DBPointer.prototype.getCollection = function(){\n"
+ "return this.ns;}\n"
+ "DBPointer.prototype.toString = function(){\n"
+ "return \"DBPointer \" + this.ns + \":\" + this.id;}}\n"
"else {\n"
- "return this.update( { _id : obj._id } , obj , true );\n"
- "}\n"
- "}\n"
- "DBCollection.prototype._genIndexName = function( keys ){\n"
- "var name = \"\";\n"
- "for ( var k in keys ){\n"
- "if ( name.length > 0 )\n"
- "name += \"_\";\n"
- "name += k + \"_\";\n"
- "var v = keys[k];\n"
- "if ( typeof v == \"number\" )\n"
- "name += v;\n"
- "}\n"
- "return name;\n"
- "}\n"
- "DBCollection.prototype._indexSpec = function( keys, options ) {\n"
- "var ret = { ns : this._fullName , key : keys , name : this._genIndexName( keys ) };\n"
- "if ( ! options ){\n"
- "}\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<options.length; i++ ){\n"
- "if ( typeof ( options[i] ) == \"string\" )\n"
- "ret.name = options[i];\n"
- "else if ( typeof( options[i] ) == \"boolean\" ){\n"
- "if ( options[i] ){\n"
- "if ( nb == 0 )\n"
- "ret.unique = true;\n"
- "if ( nb == 1 )\n"
- "ret.dropDups = true;\n"
- "}\n"
- "nb++;\n"
- "}\n"
- "}\n"
- "}\n"
+ "print( \"warning: no DBPointer\" );}\n"
+ "if ( typeof( DBRef ) != \"undefined\" ){\n"
+ "DBRef.prototype.fetch = function(){\n"
+ "assert( this.$ref , \"need a ns\" );\n"
+ "assert( this.$id , \"need an id\" );\n"
+ "return db[ this.$ref ].findOne( { _id : this.$id } );}\n"
+ "DBRef.prototype.tojson = function(indent){\n"
+ "return tojson({\"$ref\" : this.$ref, \"$id\" : this.$id}, indent);}\n"
+ "DBRef.prototype.getCollection = function(){\n"
+ "return this.$ref;}\n"
+ "DBRef.prototype.toString = function(){\n"
+ "return this.tojson();}}\n"
"else {\n"
- "Object.extend( ret , options );\n"
- "}\n"
- "}\n"
+ "print( \"warning: no DBRef\" );}\n"
+ "if ( typeof( BinData ) != \"undefined\" ){\n"
+ "BinData.prototype.tojson = function(){\n"
+ "return \"BinData type: \" + this.type + \" len: \" + this.len;}}\n"
"else {\n"
- "throw \"can't handle: \" + typeof( options );\n"
- "}\n"
- "/*\n"
- "return ret;\n"
- "var name;\n"
- "var nTrue = 0;\n"
- "if ( ! isObject( options ) ) {\n"
- "options = [ options ];\n"
- "}\n"
- "if ( options.length ){\n"
- "for( var i = 0; i < options.length; ++i ) {\n"
- "var o = options[ i ];\n"
- "if ( isString( o ) ) {\n"
- "ret.name = o;\n"
- "} else if ( typeof( o ) == \"boolean\" ) {\n"
- "if ( o ) {\n"
- "++nTrue;\n"
- "}\n"
- "}\n"
- "}\n"
- "if ( nTrue > 0 ) {\n"
- "ret.unique = true;\n"
- "}\n"
- "if ( nTrue > 1 ) {\n"
- "ret.dropDups = true;\n"
- "}\n"
- "}\n"
- "*/\n"
- "return ret;\n"
- "}\n"
- "DBCollection.prototype.createIndex = function( keys , options ){\n"
- "var o = this._indexSpec( keys, options );\n"
- "this._db.getCollection( \"system.indexes\" ).insert( o , true );\n"
- "}\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 false;\n"
- "}\n"
- "this.createIndex( keys , options );\n"
- "if ( this.getDB().getLastError() == \"\" ) {\n"
- "this._indexCache[name] = true;\n"
- "}\n"
- "return true;\n"
- "}\n"
- "DBCollection.prototype.resetIndexCache = function(){\n"
- "this._indexCache = {};\n"
- "}\n"
- "DBCollection.prototype.reIndex = function(){\n"
- "var specs = this.getIndexSpecs();\n"
- "this.dropIndexes();\n"
- "for ( var i = 0; i < specs.length; ++i ){\n"
- "this.ensureIndex( specs[i].key, [ specs[i].unique, specs[i].name ] );\n"
- "}\n"
- "}\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"
- "}\n"
- "DBCollection.prototype.drop = function(){\n"
- "this.resetIndexCache();\n"
- "return this._db.runCommand( { drop: this.getName() } );\n"
- "}\n"
- "DBCollection.prototype.renameCollection = function( newName ){\n"
- "return this._db._adminCommand( { renameCollection : this._fullName , to : this._db._name + \".\" + newName } ).ok;\n"
- "}\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"
- "}\n"
- "}\n"
- "return res;\n"
- "}\n"
- "DBCollection.prototype.getIndexes = function(){\n"
- "return this.getDB().getCollection( \"system.indexes\" ).find( { ns : this.getFullName() } ).toArray();\n"
- "}\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"
+ "print( \"warning: no BinData\" );}\n"
+ "if ( typeof _threadInject != \"undefined\" ){\n"
+ "print( \"fork() available!\" );\n"
+ "Thread = function(){\n"
+ "this.init.apply( this, arguments );}\n"
+ "_threadInject( Thread.prototype );\n"
+ "ScopedThread = function() {\n"
+ "this.init.apply( this, arguments );}\n"
+ "ScopedThread.prototype = new Thread( function() {} );\n"
+ "_scopedThreadInject( ScopedThread.prototype );\n"
+ "fork = function() {\n"
+ "var t = new Thread( function() {} );\n"
+ "Thread.apply( t, arguments );\n"
+ "return t;}\n"
+ "EventGenerator = function( me, collectionName, mean ) {\n"
+ "this.mean = mean;\n"
+ "this.events = new Array( me, collectionName );}\n"
+ "EventGenerator.prototype._add = function( action ) {\n"
+ "this.events.push( [ Random.genExp( this.mean ), action ] );}\n"
+ "EventGenerator.prototype.addInsert = function( obj ) {\n"
+ "this._add( \"t.insert( \" + tojson( obj ) + \" )\" );}\n"
+ "EventGenerator.prototype.addRemove = function( obj ) {\n"
+ "this._add( \"t.remove( \" + tojson( obj ) + \" )\" );}\n"
+ "EventGenerator.prototype.addUpdate = function( objOld, objNew ) {\n"
+ "this._add( \"t.update( \" + tojson( objOld ) + \", \" + tojson( objNew ) + \" )\" );}\n"
+ "EventGenerator.prototype.addCheckCount = function( count, query, shouldPrint, checkQuery ) {\n"
+ "query = query || {};\n"
+ "shouldPrint = shouldPrint || false;\n"
+ "checkQuery = checkQuery || false;\n"
+ "var action = \"assert.eq( \" + count + \", t.count( \" + tojson( query ) + \" ) );\"\n"
+ "if ( checkQuery ) {\n"
+ "action += \" assert.eq( \" + count + \", t.find( \" + tojson( query ) + \" ).toArray().length );\"}\n"
+ "if ( shouldPrint ) {\n"
+ "action += \" print( me + ' ' + \" + count + \" );\";}\n"
+ "this._add( action );}\n"
+ "EventGenerator.prototype.getEvents = function() {\n"
+ "return this.events;}\n"
+ "EventGenerator.dispatch = function() {\n"
+ "var args = argumentsToArray( arguments );\n"
+ "var me = args.shift();\n"
+ "var collectionName = args.shift();\n"
+ "var m = new Mongo( db.getMongo().host );\n"
+ "var t = m.getDB( \"test\" )[ collectionName ];\n"
+ "for( var i in args ) {\n"
+ "sleep( args[ i ][ 0 ] );\n"
+ "eval( args[ i ][ 1 ] );}}\n"
+ "ParallelTester = function() {\n"
+ "this.params = new Array();}\n"
+ "ParallelTester.prototype.add = function( fun, args ) {\n"
+ "args = args || [];\n"
+ "args.unshift( fun );\n"
+ "this.params.push( args );}\n"
+ "ParallelTester.prototype.run = function( msg, newScopes ) {\n"
+ "newScopes = newScopes || false;\n"
+ "assert.parallelTests( this.params, msg, newScopes );}\n"
+ "ParallelTester.createJstestsLists = function( n ) {\n"
+ "var params = new Array();\n"
+ "for( var i = 0; i < n; ++i ) {\n"
+ "params.push( [] );}\n"
+ "var makeKeys = function( a ) {\n"
+ "var ret = {};\n"
+ "for( var i in a ) {\n"
+ "ret[ a[ i ] ] = 1;}\n"
+ "return ret;}\n"
+ "var skipTests = makeKeys( [ \"jstests/dbadmin.js\",\n"
+ "\"jstests/repair.js\",\n"
+ "\"jstests/cursor8.js\",\n"
+ "\"jstests/recstore.js\",\n"
+ "\"jstests/extent.js\",\n"
+ "\"jstests/indexb.js\",\n"
+ "\"jstests/profile1.js\",\n"
+ "\"jstests/mr3.js\",\n"
+ "\"jstests/apitest_db.js\"] );\n"
+ "var serialTestsArr = [ \"jstests/fsync.js\",\n"
+ "\"jstests/fsync2.js\" ];\n"
+ "var serialTests = makeKeys( serialTestsArr );\n"
+ "params[ 0 ] = serialTestsArr;\n"
+ "var files = listFiles(\"jstests\");\n"
+ "files = Array.shuffle( files );\n"
+ "var i = 0;\n"
+ "files.forEach(\n"
+ "function(x) {\n"
+ "if ( /_runner/.test(x.name) ||\n"
+ "/_lodeRunner/.test(x.name) ||\n"
+ "( x.name in skipTests ) ||\n"
+ "( x.name in serialTests ) ||\n"
+ "! /\\.js$/.test(x.name ) ){\n"
+ "print(\" >>>>>>>>>>>>>>> skipping \" + x.name);\n"
+ "return;}\n"
+ "params[ i % n ].push( x.name );\n"
+ "++i;}\n"
");\n"
- "}\n"
- "DBCollection.prototype.count = function( x ){\n"
- "return this.find( x ).count();\n"
- "}\n"
- "/**\n"
- "* Drop free lists. Normally not used.\n"
- "* Note this only does the collection itself, not the namespaces of its indexes (see cleanAll).\n"
- "*/\n"
- "DBCollection.prototype.clean = function() {\n"
- "return this._dbCommand( { clean: this.getName() } );\n"
- "}\n"
- "/**\n"
- "* <p>Drop a specified index.</p>\n"
- "*\n"
- "* <p>\n"
- "* Name is the name of the index in the system.indexes name field. (Run db.system.indexes.find() to\n"
- "* see example data.)\n"
- "* </p>\n"
- "*\n"
- "* <p>Note : alpha: space is not reclaimed </p>\n"
- "* @param {String} name of index to delete.\n"
- "* @return A result object. result.ok will be true if successful.\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: this.getName(), index: index } );\n"
- "this.resetIndexCache();\n"
- "return res;\n"
- "}\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"
- "}\n"
- "return count;\n"
- "} , this.getName() , newName\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"
- "}\n"
- "DBCollection.prototype.getCollection = function( subName ){\n"
- "return this._db.getCollection( this._shortName + \".\" + subName );\n"
- "}\n"
- "DBCollection.prototype.stats = function(){\n"
- "return this._db.runCommand( { collstats : this._shortName } );\n"
- "}\n"
- "DBCollection.prototype.dataSize = function(){\n"
- "return this.stats().size;\n"
- "}\n"
- "DBCollection.prototype.storageSize = function(){\n"
- "return this.stats().storageSize;\n"
- "}\n"
- "DBCollection.prototype.totalIndexSize = function( verbose ){\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<x.length; i++ ){\n"
+ "if ( x[i] == '\"' ){\n"
+ "s += \"\\\\\\\"\";}\n"
+ "else\n"
+ "s += x[i];}\n"
+ "return s + \"\\\"\";}\n"
+ "case \"number\":\n"
+ "case \"boolean\":\n"
+ "return \"\" + x;\n"
+ "case \"object\":{\n"
+ "var s = tojsonObject( x, indent , nolint );\n"
+ "if ( ( nolint == null || nolint == true ) && s.length < 80 && ( indent == null || indent.length == 0 ) ){\n"
+ "s = s.replace( /[\\s\\r\\n ]+/gm , \" \" );}\n"
+ "return s;}\n"
+ "case \"function\":\n"
+ "return x.toString();\n"
+ "default:\n"
+ "throw \"tojson can't handle type \" + ( typeof x );}}\n"
+ "tojsonObject = function( x, indent , nolint ){\n"
+ "var lineEnding = nolint ? \" \" : \"\\n\";\n"
+ "var tabSpace = nolint ? \"\" : \"\\t\";\n"
+ "assert.eq( ( typeof x ) , \"object\" , \"tojsonObject needs object, not [\" + ( typeof x ) + \"]\" );\n"
+ "if (!indent)\n"
+ "indent = \"\";\n"
+ "if ( typeof( x.tojson ) == \"function\" && x.tojson != tojson ) {\n"
+ "return x.tojson(indent,nolint);}\n"
+ "if ( typeof( x.constructor.tojson ) == \"function\" && x.constructor.tojson != tojson ) {\n"
+ "return x.constructor.tojson( x, indent , nolint );}\n"
+ "if ( x.toString() == \"[object MaxKey]\" )\n"
+ "return \"{ $maxKey : 1 }\";\n"
+ "if ( x.toString() == \"[object MinKey]\" )\n"
+ "return \"{ $minKey : 1 }\";\n"
+ "var s = \"{\" + lineEnding;\n"
+ "indent += tabSpace;\n"
"var total = 0;\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.dataSize();\n"
- "total += coll.dataSize();\n"
- "if ( verbose ) {\n"
- "print( coll + \"\\t\" + mysize );\n"
- "}\n"
- "}\n"
- ");\n"
- "return total;\n"
- "}\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"
- ");\n"
- "return total;\n"
- "}\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"
- "}\n"
- "DBCollection.prototype.exists = function(){\n"
- "return this._db.system.namespaces.findOne( { name : this._fullName } );\n"
- "}\n"
- "DBCollection.prototype.isCapped = function(){\n"
- "var e = this.exists();\n"
- "return ( e && e.options && e.options.capped ) ? true : false;\n"
- "}\n"
- "DBCollection.prototype.distinct = function( keyString ){\n"
- "var res = this._dbCommand( { distinct : this._shortName , key : keyString } );\n"
- "if ( ! res.ok )\n"
- "throw \"distinct failed: \" + tojson( res );\n"
- "return res.values;\n"
- "}\n"
- "DBCollection.prototype.group = function( params ){\n"
- "params.ns = this._shortName;\n"
- "return this._db.group( params );\n"
- "}\n"
- "DBCollection.prototype.groupcmd = function( params ){\n"
- "params.ns = this._shortName;\n"
- "return this._db.groupcmd( params );\n"
- "}\n"
- "DBCollection.prototype.toString = function(){\n"
- "return this.getFullName();\n"
- "}\n"
- "DBCollection.prototype.shellPrint = DBCollection.prototype.toString;\n"
+ "for ( var k in x ) total++;\n"
+ "if ( total == 0 ) {\n"
+ "s += indent + lineEnding;}\n"
+ "var keys = x;\n"
+ "if ( typeof( x._simpleKeys ) == \"function\" )\n"
+ "keys = x._simpleKeys();\n"
+ "var num = 1;\n"
+ "for ( var k in keys ){\n"
+ "var val = x[k];\n"
+ "if ( val == DB.prototype || val == DBCollection.prototype )\n"
+ "continue;\n"
+ "s += indent + \"\\\"\" + k + \"\\\" : \" + tojson( val, indent , nolint );\n"
+ "if (num != total) {\n"
+ "s += \",\";\n"
+ "num++;}\n"
+ "s += lineEnding;}\n"
+ "indent = indent.substring(1);\n"
+ "return s + indent + \"}\";}\n"
+ "shellPrint = function( x ){\n"
+ "it = x;\n"
+ "if ( x != undefined )\n"
+ "shellPrintHelper( x );\n"
+ "if ( db ){\n"
+ "var e = db.getPrevError();\n"
+ "if ( e.err ) {\n"
+ "if( e.nPrev <= 1 )\n"
+ "print( \"error on last call: \" + tojson( e.err ) );\n"
+ "else\n"
+ "print( \"an error \" + tojson(e.err) + \" occurred \" + e.nPrev + \" operations back in the command invocation\" );}\n"
+ "db.resetError();}}\n"
+ "printjson = function(x){\n"
+ "print( tojson( x ) );}\n"
+ "shellPrintHelper = function( x ){\n"
+ "if ( typeof( x ) == \"undefined\" ){\n"
+ "if ( typeof( db ) != \"undefined\" && db.getLastError ){\n"
+ "var e = db.getLastError();\n"
+ "if ( e != null )\n"
+ "print( e );}\n"
+ "return;}\n"
+ "if ( x == null ){\n"
+ "print( \"null\" );\n"
+ "return;}\n"
+ "if ( typeof x != \"object\" )\n"
+ "return print( x );\n"
+ "var p = x.shellPrint;\n"
+ "if ( typeof p == \"function\" )\n"
+ "return x.shellPrint();\n"
+ "var p = x.tojson;\n"
+ "if ( typeof p == \"function\" )\n"
+ "print( x.tojson() );\n"
+ "else\n"
+ "print( tojson( x ) );}\n"
+ "shellHelper = function( command , rest , shouldPrint ){\n"
+ "command = command.trim();\n"
+ "var args = rest.trim().replace(/;$/,\"\").split( \"\\s+\" );\n"
+ "if ( ! shellHelper[command] )\n"
+ "throw \"no command [\" + command + \"]\";\n"
+ "var res = shellHelper[command].apply( null , args );\n"
+ "if ( shouldPrint ){\n"
+ "shellPrintHelper( res );}\n"
+ "return res;}\n"
+ "help = shellHelper.help = function(){\n"
+ "print( \"HELP\" );\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 <db name> set curent database to <db name>\" );\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<a.length; i++ ){\n"
+ "if ( friendlyEqual( key , a[i].key ) ){\n"
+ "return a[i];}}\n"
+ "var o = { key : key , value : null };\n"
+ "a.push( o );\n"
+ "return o;}\n"
+ "Map.prototype.values = function(){\n"
+ "var all = [];\n"
+ "for ( var k in this._data ){\n"
+ "this._data[k].forEach( function(z){ all.push( z.value ); } );}\n"
+ "return all;}\n"
+ "if ( typeof( gc ) == \"undefined\" ){\n"
+ "gc = function(){}}\n"
+ "Math.sigFig = function( x , N ){\n"
+ "if ( ! N ){\n"
+ "N = 3;}\n"
+ "var p = Math.pow( 10, N - Math.ceil( Math.log( Math.abs(x) ) / Math.log( 10 )) );\n"
+ "return Math.round(x*p)/p;}\n"
+ "Random = function() {}\n"
+ "Random.srand = function( s ) { _srand( s ); }\n"
+ "Random.rand = function() { return _rand(); }\n"
+ "Random.randInt = function( n ) { return Math.floor( Random.rand() * n ); }\n"
+ "Random.setRandomSeed = function( s ) {\n"
+ "s = s || new Date().getTime();\n"
+ "print( \"setting random seed: \" + s );\n"
+ "Random.srand( s );}\n"
+ "Random.genExp = function( mean ) {\n"
+ "return -Math.log( Random.rand() ) * mean;}\n"
+ "killWithUris = function( uris ) {\n"
+ "var inprog = db.currentOp().inprog;\n"
+ "for( var u in uris ) {\n"
+ "for ( var i in inprog ) {\n"
+ "if ( uris[ u ] == inprog[ i ].client ) {\n"
+ "db.killOp( inprog[ i ].opid );}}}}\n"
"if ( typeof DB == \"undefined\" ){\n"
"DB = function( mongo , name ){\n"
"this._mongo = mongo;\n"
- "this._name = name;\n"
- "}\n"
- "}\n"
+ "this._name = name;}}\n"
"DB.prototype.getMongo = function(){\n"
"assert( this._mongo , \"why no mongo!\" );\n"
- "return this._mongo;\n"
- "}\n"
+ "return this._mongo;}\n"
"DB.prototype.getSisterDB = function( name ){\n"
- "return this.getMongo().getDB( name );\n"
- "}\n"
+ "return this.getMongo().getDB( name );}\n"
"DB.prototype.getName = function(){\n"
- "return this._name;\n"
- "}\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"
- "}\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"
- "}\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"
- "}\n"
- "return this.getCollection( \"$cmd\" ).findOne( obj );\n"
- "}\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"
- "}\n"
- "DB.prototype.addUser = function( username , pass ){\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"
- "}\n"
+ "c.save( u );}\n"
"DB.prototype.removeUser = function( username ){\n"
- "this.getCollection( \"system.users\" ).remove( { user : username } );\n"
- "}\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"
@@ -448,277 +618,127 @@ const char * jsconcatcode =
"authenticate : 1 ,\n"
"user : username ,\n"
"nonce : n.nonce ,\n"
- "key : hex_md5( n.nonce + username + hex_md5( username + \":mongo:\" + pass ) )\n"
- "}\n"
+ "key : this.__pwHash( n.nonce, username, pass )}\n"
");\n"
- "return a.ok;\n"
- "}\n"
- "/**\n"
- "Create a new collection in the database. Normally, collection creation is automatic. You would\n"
- "use this function if you wish to specify special options on creation.\n"
- "If the collection already exists, no action occurs.\n"
- "<p>Options:</p>\n"
- "<ul>\n"
- "<li>\n"
- "size: desired initial extent size for the collection. Must be <= 1000000000.\n"
- "for fixed size (capped) collections, this size is the total/max size of the\n"
- "collection.\n"
- "</li>\n"
- "<li>\n"
- "capped: if true, this is a capped collection (where old data rolls out).\n"
- "</li>\n"
- "<li> max: maximum number of objects if capped (optional).</li>\n"
- "</ul>\n"
- "<p>Example: </p>\n"
- "<code>db.createCollection(\"movies\", { size: 10 * 1024 * 1024, capped:true } );</code>\n"
- "* @param {String} name Name of new collection to create\n"
- "* @param {Object} options Object with options for call. Options are listed above.\n"
- "* @return SOMETHING_FIXME\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"
- "/**\n"
- "* Returns the current profiling level of this database\n"
- "* @return SOMETHING_FIXME or null on error\n"
- "*/\n"
+ "return res;}\n"
+ "\n"
"DB.prototype.getProfilingLevel = function() {\n"
"var res = this._dbCommand( { profile: -1 } );\n"
- "return res ? res.was : null;\n"
- "}\n"
- "/**\n"
- "Erase the entire database. (!)\n"
- "* @return Object returned has member ok set to true if operation succeeds, false otherwise.\n"
- "*/\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"
- "}\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"
- "}\n"
+ "return \"shutdown command only works with the admin database; try 'use admin'\";}\n"
"try {\n"
- "this._dbCommand(\"shutdown\");\n"
- "throw \"shutdownServer failed\";\n"
- "}\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"
- "}\n"
- "/**\n"
- "Clone database on another server to here.\n"
- "<p>\n"
- "Generally, you should dropDatabase() first as otherwise the cloned information will MERGE\n"
- "into whatever data is already present in this database. (That is however a valid way to use\n"
- "clone if you are trying to do something intentionally, such as union three non-overlapping\n"
- "databases into one.)\n"
- "<p>\n"
- "This is a low level administrative function will is not typically used.\n"
- "* @param {String} from Where to clone from (dbhostname[:port]). May not be this database\n"
- "(self) as you cannot clone to yourself.\n"
- "* @return Object returned has member ok set to true if operation succeeds, false otherwise.\n"
- "* See also: db.copyDatabase()\n"
- "*/\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"
- "/**\n"
- "Clone collection on another server to here.\n"
- "<p>\n"
- "Generally, you should drop() first as otherwise the cloned information will MERGE\n"
- "into whatever data is already present in this collection. (That is however a valid way to use\n"
- "clone if you are trying to do something intentionally, such as union three non-overlapping\n"
- "collections into one.)\n"
- "<p>\n"
- "This is a low level administrative function is not typically used.\n"
- "* @param {String} from mongod instance from which to clnoe (dbhostname:port). May\n"
- "not be this mongod instance, as clone from self is not allowed.\n"
- "* @param {String} collection name of collection to clone.\n"
- "* @param {Object} query query specifying which elements of collection are to be cloned.\n"
- "* @return Object returned has member ok set to true if operation succeeds, false otherwise.\n"
- "* See also: db.cloneDatabase()\n"
- "*/\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"
- "/**\n"
- "Copy database from one server or name to another server or name.\n"
- "Generally, you should dropDatabase() first as otherwise the copied information will MERGE\n"
- "into whatever data is already present in this database (and you will get duplicate objects\n"
- "in collections potentially.)\n"
- "For security reasons this function only works when executed on the \"admin\" db. However,\n"
- "if you have access to said db, you can copy any database from one place to another.\n"
- "This method provides a way to \"rename\" a database by copying it to a new db name and\n"
- "location. Additionally, it effectively provides a repair facility.\n"
- "* @param {String} fromdb database name from which to copy.\n"
- "* @param {String} todb database name to copy to.\n"
- "* @param {String} fromhost hostname of the database (and optionally, \":port\") from which to\n"
- "copy the data. default if unspecified is to copy from self.\n"
- "* @return Object returned has member ok set to true if operation succeeds, false otherwise.\n"
- "* See also: db.clone()\n"
- "*/\n"
- "DB.prototype.copyDatabase = function(fromdb, todb, fromhost) {\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"
- "return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );\n"
- "}\n"
- "/**\n"
- "Repair database.\n"
- "* @return Object returned has member ok set to true if operation succeeds, false otherwise.\n"
- "*/\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"
- "}\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.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.getSisterDB(name) get the db at the same server as this onew\");\n"
- "print(\"\\tdb.getName()\");\n"
- "print(\"\\tdb.getCollection(cname) same as db['cname'] or db.cname\");\n"
- "print(\"\\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }\");\n"
- "print(\"\\tdb.commandHelp(name) returns the help for the command\");\n"
- "print(\"\\tdb.addUser(username, password)\");\n"
- "print(\"\\tdb.removeUser(username)\");\n"
- "print(\"\\tdb.createCollection(name, { size : ..., capped : ..., max : ... } )\");\n"
- "print(\"\\tdb.getReplicationInfo()\");\n"
- "print(\"\\tdb.printReplicationInfo()\");\n"
- "print(\"\\tdb.printSlaveReplicationInfo()\");\n"
- "print(\"\\tdb.getProfilingLevel()\");\n"
- "print(\"\\tdb.setProfilingLevel(level) 0=off 1=slow 2=all\");\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.shutdownServer()\");\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.repairDatabase()\");\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.resetError()\");\n"
- "print(\"\\tdb.getCollectionNames()\");\n"
- "print(\"\\tdb.currentOp() displays the current operation in the db\" );\n"
- "print(\"\\tdb.killOp() kills the current operation in the db\" );\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.version() current version of the server\" );\n"
- "}\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,<slowms>) 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( db[z].stats() );\n"
- "print( \"---\" );\n"
- "}\n"
- ");\n"
- "}\n"
- "/**\n"
- "* <p> Set profiling level for your db. Profiling gathers stats on query performance. </p>\n"
- "*\n"
- "* <p>Default is off, and resets to off on a database restart -- so if you want it on,\n"
- "* turn it on periodically. </p>\n"
- "*\n"
- "* <p>Levels :</p>\n"
- "* <ul>\n"
- "* <li>0=off</li>\n"
- "* <li>1=log very slow (>100ms) operations</li>\n"
- "* <li>2=log all</li>\n"
- "* @param {String} level Desired level of profiling\n"
- "* @return SOMETHING_FIXME or null on error\n"
- "*/\n"
- "DB.prototype.setProfilingLevel = function(level) {\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"
- "}\n"
- "if (level) {\n"
- "this.createCollection(\"system.profile\", { capped: true, size: 128 * 1024 } );\n"
- "}\n"
- "return this._dbCommand( { profile: level } );\n"
- "}\n"
- "/**\n"
- "* <p> Evaluate a js expression at the database server.</p>\n"
- "*\n"
- "* <p>Useful if you need to touch a lot of data lightly; in such a scenario\n"
- "* the network transfer of the data could be a bottleneck. A good example\n"
- "* is \"select count(*)\" -- can be done server side via this mechanism.\n"
- "* </p>\n"
- "*\n"
- "* <p>\n"
- "* If the eval fails, an exception is thrown of the form:\n"
- "* </p>\n"
- "* <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg: str] } }</code>\n"
- "*\n"
- "* <p>Example: </p>\n"
- "* <code>print( \"mycount: \" + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();} );</code>\n"
- "*\n"
- "* @param {Function} jsfunction Javascript function to run on server. Note this it not a closure, but rather just \"code\".\n"
- "* @return result of your function, or null if error\n"
- "*\n"
- "*/\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"
- "}\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"
- "}\n"
+ "return res.retval;}\n"
"DB.prototype.dbEval = DB.prototype.eval;\n"
- "/**\n"
- "*\n"
- "* <p>\n"
- "* Similar to SQL group by. For example: </p>\n"
- "*\n"
- "* <code>select a,b,sum(c) csum from coll where active=1 group by a,b</code>\n"
- "*\n"
- "* <p>\n"
- "* corresponds to the following in 10gen:\n"
- "* </p>\n"
- "*\n"
- "* <code>\n"
- "db.group(\n"
- "{\n"
- "ns: \"coll\",\n"
- "key: { a:true, b:true },\n"
- "cond: { active:1 },\n"
- "reduce: function(obj,prev) { prev.csum += obj.c; } ,\n"
- "initial: { csum: 0 }\n"
- "});\n"
- "</code>\n"
- "*\n"
- "*\n"
- "* <p>\n"
- "* An array of grouped items is returned. The array must fit in RAM, thus this function is not\n"
- "* suitable when the return set is extremely large.\n"
- "* </p>\n"
- "* <p>\n"
- "* To order the grouped data, simply sort it client side upon return.\n"
- "* <p>\n"
- "Defaults\n"
- "cond may be null if you want to run against all rows in the collection\n"
- "keyf is a function which takes an object and returns the desired key. set either key or keyf (not both).\n"
- "* </p>\n"
- "*/\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 ? parms.key.keySet() : null;\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"
@@ -726,114 +746,82 @@ const char * jsconcatcode =
"if ( pks ) {\n"
"for( var i=0; i<pkl; i++ ){\n"
"var k = pks[i];\n"
- "key[k] = obj[k];\n"
- "}\n"
- "}\n"
+ "key[k] = obj[k];}}\n"
"else {\n"
- "key = parms.$keyf(obj);\n"
- "}\n"
+ "key = parms.$keyf(obj);}\n"
"var aggObj = map.get(key);\n"
"if( aggObj == null ) {\n"
"var newObj = Object.extend({}, key);\n"
"aggObj = Object.extend(newObj, parms.initial)\n"
- "map.put( key , aggObj );\n"
- "}\n"
- "parms.$reduce(obj, aggObj);\n"
- "}\n"
- "return map.values();\n"
- "}\n"
- "return this.eval(groupFunction, this._groupFixParms( parmsObj ));\n"
- "}\n"
+ "map.put( key , aggObj );}\n"
+ "parms.$reduce(obj, aggObj);}\n"
+ "return map.values();}\n"
+ "return this.eval(groupFunction, this._groupFixParms( parmsObj ));}\n"
"DB.prototype.groupcmd = function( parmsObj ){\n"
"var ret = this.runCommand( { \"group\" : this._groupFixParms( parmsObj ) } );\n"
"if ( ! ret.ok ){\n"
- "throw \"group command failed: \" + tojson( ret );\n"
- "}\n"
- "return ret.retval;\n"
- "}\n"
+ "throw \"group command failed: \" + tojson( ret );}\n"
+ "return ret.retval;}\n"
"DB.prototype.group = DB.prototype.groupcmd;\n"
"DB.prototype._groupFixParms = function( parmsObj ){\n"
"var parms = Object.extend({}, parmsObj);\n"
"if( parms.reduce ) {\n"
"parms.$reduce = parms.reduce;\n"
- "delete parms.reduce;\n"
- "}\n"
+ "delete parms.reduce;}\n"
"if( parms.keyf ) {\n"
"parms.$keyf = parms.keyf;\n"
- "delete parms.keyf;\n"
- "}\n"
- "return parms;\n"
- "}\n"
+ "delete parms.keyf;}\n"
+ "return parms;}\n"
"DB.prototype.resetError = function(){\n"
- "return this.runCommand( { reseterror : 1 } );\n"
- "}\n"
+ "return this.runCommand( { reseterror : 1 } );}\n"
"DB.prototype.forceError = function(){\n"
- "return this.runCommand( { forceerror : 1 } );\n"
- "}\n"
+ "return this.runCommand( { forceerror : 1 } );}\n"
"DB.prototype.getLastError = function(){\n"
"var res = this.runCommand( { getlasterror : 1 } );\n"
"if ( ! res.ok )\n"
"throw \"getlasterror failed: \" + tojson( res );\n"
- "return res.err;\n"
- "}\n"
+ "return res.err;}\n"
"DB.prototype.getLastErrorObj = function(){\n"
"var res = this.runCommand( { getlasterror : 1 } );\n"
"if ( ! res.ok )\n"
"throw \"getlasterror failed: \" + tojson( res );\n"
- "return res;\n"
- "}\n"
+ "return res;}\n"
+ "DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj;\n"
"/* Return the last error which has occurred, even if not the very last error.\n"
"Returns:\n"
"{ err : <error message>, nPrev : <how_many_ops_back_occurred>, 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"
- "}\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 )\n"
+ "if ( name.indexOf( \"$\" ) >= 0 && name != \"local.oplog.$main\" )\n"
"return;\n"
- "all.push( name.substring( nsLength ) );\n"
- "}\n"
+ "all.push( name.substring( nsLength ) );}\n"
");\n"
- "return all;\n"
- "}\n"
+ "return all;}\n"
"DB.prototype.tojson = function(){\n"
- "return this._name;\n"
- "}\n"
+ "return this._name;}\n"
"DB.prototype.toString = function(){\n"
- "return this._name;\n"
- "}\n"
+ "return this._name;}\n"
"DB.prototype.currentOp = function(){\n"
- "return db.$cmd.sys.inprog.findOne();\n"
- "}\n"
+ "return db.$cmd.sys.inprog.findOne();}\n"
"DB.prototype.currentOP = DB.prototype.currentOp;\n"
- "DB.prototype.killOp = function(){\n"
- "return db.$cmd.sys.killop.findOne();\n"
- "}\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"
- "/**\n"
- "Get a replication log information summary.\n"
- "<p>\n"
- "This command is for the database/cloud administer and not applicable to most databases.\n"
- "It is only used with the local database. One might invoke from the JS shell:\n"
- "<pre>\n"
- "use local\n"
- "db.getReplicationInfo();\n"
- "</pre>\n"
- "It is assumed that this database is a replication master -- the information returned is\n"
- "about the operation log stored at local.oplog.$main on the replication master. (It also\n"
- "works on a machine in a replica pair: for replica pairs, both machines are \"masters\" from\n"
- "an internal database perspective.\n"
- "<p>\n"
- "* @return Object timeSpan: time span of the oplog from start to end if slave is more out\n"
- "* of date than that, it can't recover without a complete resync\n"
- "*/\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"
@@ -842,81 +830,66 @@ const char * jsconcatcode =
"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"
- "}\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"
- "}\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 = tfirst / 4294967296;\n"
- "tlast = tlast / 4294967296;\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"
- "}\n"
+ "result.now = Date();}\n"
"else {\n"
- "result.errmsg = \"ts element not found in oplog objects\";\n"
- "}\n"
- "}\n"
- "return result;\n"
- "}\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"
- "}\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"
- "}\n"
+ "print(\"now: \" + result.now);}\n"
"DB.prototype.printSlaveReplicationInfo = function() {\n"
"function g(x) {\n"
"print(\"source: \" + x.host);\n"
- "var st = new Date(x.syncedTo/4294967296*1000);\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"
- "}\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"
- "}\n"
- "L.sources.find().forEach(g);\n"
- "}\n"
+ "return;}\n"
+ "L.sources.find().forEach(g);}\n"
"DB.prototype.serverBuildInfo = function(){\n"
- "return this._adminCommand( \"buildinfo\" );\n"
- "}\n"
+ "return this._adminCommand( \"buildinfo\" );}\n"
"DB.prototype.serverStatus = function(){\n"
- "return this._adminCommand( \"serverStatus\" );\n"
- "}\n"
+ "return this._adminCommand( \"serverStatus\" );}\n"
"DB.prototype.version = function(){\n"
- "return this.serverBuildInfo().version;\n"
- "}\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"
- "}\n"
- "}\n"
+ "this.init( host );}}\n"
"if ( ! Mongo.prototype ){\n"
- "throw \"Mongo.prototype not defined\";\n"
- "}\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"
@@ -926,31 +899,31 @@ const char * jsconcatcode =
"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"
- "}\n"
+ "mongoInject( Mongo.prototype );}\n"
"Mongo.prototype.setSlaveOk = function() {\n"
- "this.slaveOk = true;\n"
- "}\n"
+ "this.slaveOk = true;}\n"
"Mongo.prototype.getDB = function( name ){\n"
- "return new DB( this , name );\n"
- "}\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\" );\n"
- "return res;\n"
- "}\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"
- ");\n"
- "}\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"
- "}\n"
+ "return \"mongo connection to \" + this.host;}\n"
"connect = function( url , user , pass ){\n"
- "print( \"connecting to: \" + url )\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"
@@ -961,33 +934,33 @@ const char * jsconcatcode =
"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"
- "}\n"
- "}\n"
- "return db;\n"
- "}\n"
+ "throw \"couldn't login\";}}\n"
+ "return db;}\n"
"MR = {};\n"
"MR.init = function(){\n"
"$max = 0;\n"
"$arr = [];\n"
"emit = MR.emit;\n"
- "gc();\n"
- "}\n"
+ "$numEmits = 0;\n"
+ "$numReduces = 0;\n"
+ "$numReducesToDB = 0;\n"
+ "gc();}\n"
"MR.cleanup = function(){\n"
"MR.init();\n"
- "gc();\n"
- "}\n"
+ "gc();}\n"
"MR.emit = function(k,v){\n"
- "var num = get_num( k );\n"
+ "$numEmits++;\n"
+ "var num = nativeHelper.apply( get_num_ , [ k ] );\n"
"var data = $arr[num];\n"
"if ( ! data ){\n"
- "data = { key : k , values : [] };\n"
- "$arr[num] = data;\n"
- "}\n"
- "data.values.push( v );\n"
- "$max = Math.max( $max , data.values.length );\n"
- "}\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"
@@ -996,44 +969,40 @@ const char * jsconcatcode =
"if ( useDB ){\n"
"var x = tempcoll.findOne( { _id : data.key } );\n"
"if ( x ){\n"
- "data.values.push( x.value );\n"
- "}\n"
- "}\n"
- "var r = $reduce( data.key , data.values );\n"
- "if ( r.length && r[0] ){\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"
- "}\n"
+ "data.count = r.length;}\n"
"else{\n"
- "data.values = [ r ];\n"
- "}\n"
- "$max = Math.max( $max , data.values.length );\n"
+ "data.values[0] = r;\n"
+ "data.count = 1;}\n"
+ "$max = Math.max( $max , data.count );\n"
"if ( useDB ){\n"
- "if ( data.values.length == 1 ){\n"
- "tempcoll.save( { _id : data.key , value : data.values[0] } );\n"
- "}\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 } );\n"
- "}\n"
- "}\n"
- "}\n"
- "}\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"
- "}\n"
+ "return 0;}\n"
"MR.doReduce();\n"
"if ( $max < 2000 && $arr.length < 1000 ){\n"
- "return 1;\n"
- "}\n"
+ "return 1;}\n"
"MR.doReduce( true );\n"
"$arr = [];\n"
"$max = 0;\n"
"reset_num();\n"
"gc();\n"
- "return 2;\n"
- "}\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 ){\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"
@@ -1042,65 +1011,60 @@ const char * jsconcatcode =
"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"
- "}\n"
- "print( \"DBQuery probably won't have array access \" );\n"
- "}\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()\" )\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"
- "}\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 );\n"
+ "this._limit , this._skip , this._batchSize );\n"
"q._special = this._special;\n"
- "return q;\n"
- "}\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"
- "}\n"
+ "this._special = true;}\n"
"DBQuery.prototype._checkModify = function(){\n"
"if ( this._cursor )\n"
- "throw \"query already executed\";\n"
- "}\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 );\n"
- "this._cursorSeen = 0;\n"
- "}\n"
- "return this._cursor;\n"
- "}\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"
- "}\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"
- "}\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"
- "}\n"
+ "return o;}\n"
"DBQuery.prototype.next = function(){\n"
"this._exec();\n"
"var o = this._cursor.hasNext();\n"
@@ -1112,8 +1076,7 @@ const char * jsconcatcode =
"if ( ret.$err && this._numReturned == 0 && ! this.hasNext() )\n"
"throw \"error: \" + tojson( ret );\n"
"this._numReturned++;\n"
- "return ret;\n"
- "}\n"
+ "return ret;}\n"
"DBQuery.prototype.toArray = function(){\n"
"if ( this._arr )\n"
"return this._arr;\n"
@@ -1121,886 +1084,446 @@ const char * jsconcatcode =
"while ( this.hasNext() )\n"
"a.push( this.next() );\n"
"this._arr = a;\n"
- "return a;\n"
- "}\n"
- "DBQuery.prototype.count = function(){\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"
- "}\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"
- "}\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"
- "/**\n"
- "* iterative count - only for testing\n"
- "*/\n"
+ "return c;}\n"
+ "\n"
"DBQuery.prototype.itcount = function(){\n"
"var num = 0;\n"
"while ( this.hasNext() ){\n"
"num++;\n"
- "this.next();\n"
- "}\n"
- "return num;\n"
- "}\n"
+ "this.next();}\n"
+ "return num;}\n"
"DBQuery.prototype.length = function(){\n"
- "return this.toArray().length;\n"
- "}\n"
- "DBQuery.prototype.sort = function( sortBy ){\n"
+ "return this.toArray().length;}\n"
+ "DBQuery.prototype._addSpecial = function( name , value ){\n"
"this._ensureSpecial();\n"
- "this._query.orderby = sortBy;\n"
- "return this;\n"
- "}\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"
- "this._ensureSpecial();\n"
- "this._query[\"$hint\"] = hint;\n"
- "return this;\n"
- "}\n"
+ "return this._addSpecial( \"$hint\" , hint );}\n"
"DBQuery.prototype.min = function( min ) {\n"
- "this._ensureSpecial();\n"
- "this._query[\"$min\"] = min;\n"
- "return this;\n"
- "}\n"
+ "return this._addSpecial( \"$min\" , min );}\n"
"DBQuery.prototype.max = function( max ) {\n"
- "this._ensureSpecial();\n"
- "this._query[\"$max\"] = max;\n"
- "return this;\n"
- "}\n"
+ "return this._addSpecial( \"$max\" , max );}\n"
"DBQuery.prototype.forEach = function( func ){\n"
"while ( this.hasNext() )\n"
- "func( this.next() );\n"
- "}\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"
- "}\n"
+ "return a;}\n"
"DBQuery.prototype.arrayAccess = function( idx ){\n"
- "return this.toArray()[idx];\n"
- "}\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"
- "}\n"
+ "return n.next();}\n"
"DBQuery.prototype.snapshot = function(){\n"
"this._ensureSpecial();\n"
"this._query.$snapshot = true;\n"
- "return this;\n"
- "}\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() );\n"
+ "var s = tojson( this.next() , \"\" , true );\n"
"print( s );\n"
- "n++;\n"
- "}\n"
+ "n++;}\n"
"if ( this.hasNext() ){\n"
"print( \"has more\" );\n"
- "___it___ = this;\n"
- "}\n"
+ "___it___ = this;}\n"
"else {\n"
- "___it___ = null;\n"
- "}\n"
- "}\n"
+ "___it___ = null;}}\n"
"catch ( e ){\n"
- "print( e );\n"
- "}\n"
- "}\n"
+ "print( e );}}\n"
"DBQuery.prototype.toString = function(){\n"
- "return \"DBQuery: \" + this._ns + \" -> \" + tojson( this.query );\n"
- "}\n"
- "_parsePath = function() {\n"
- "var dbpath = \"\";\n"
- "for( var i = 0; i < arguments.length; ++i )\n"
- "if ( arguments[ i ] == \"--dbpath\" )\n"
- "dbpath = arguments[ i + 1 ];\n"
- "if ( dbpath == \"\" )\n"
- "throw \"No dbpath specified\";\n"
- "return dbpath;\n"
- "}\n"
- "_parsePort = function() {\n"
- "var port = \"\";\n"
- "for( var i = 0; i < arguments.length; ++i )\n"
- "if ( arguments[ i ] == \"--port\" )\n"
- "port = arguments[ i + 1 ];\n"
- "if ( port == \"\" )\n"
- "throw \"No port specified\";\n"
- "return port;\n"
- "}\n"
- "createMongoArgs = function( binaryName , args ){\n"
- "var fullArgs = [ binaryName ];\n"
- "if ( args.length == 1 && isObject( args[0] ) ){\n"
- "var o = args[0];\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 , <optional params> )\");\n"
+ "print(\"\\tdb.foo.remove(query)\");\n"
+ "print(\"\\tdb.foo.renameCollection( newName , <dropTarget> ) renames the collection.\");\n"
+ "print(\"\\tdb.foo.runCommand( name , <options> ) 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 == \"v\" && isNumber( o[k] ) ){\n"
- "var n = o[k];\n"
- "if ( n > 0 ){\n"
- "var temp = \"-\";\n"
- "while ( n-- > 0 ) temp += \"v\";\n"
- "fullArgs.push( temp );\n"
- "}\n"
- "}\n"
- "else {\n"
- "fullArgs.push( \"--\" + k );\n"
- "if ( o[k] != \"\" )\n"
- "fullArgs.push( \"\" + o[k] );\n"
- "}\n"
- "}\n"
- "}\n"
- "else {\n"
- "for ( var i=0; i<args.length; i++ )\n"
- "fullArgs.push( args[i] )\n"
- "}\n"
- "return fullArgs;\n"
- "}\n"
- "startMongod = function(){\n"
- "var args = createMongoArgs( \"mongod\" , arguments );\n"
- "var dbpath = _parsePath.apply( null, args );\n"
- "resetDbpath( dbpath );\n"
- "return startMongoProgram.apply( null, args );\n"
- "}\n"
- "startMongos = function(){\n"
- "return startMongoProgram.apply( null, createMongoArgs( \"mongos\" , arguments ) );\n"
- "}\n"
- "startMongoProgram = function(){\n"
- "var port = _parsePort.apply( null, arguments );\n"
- "_startMongoProgram.apply( null, arguments );\n"
- "var m;\n"
- "assert.soon\n"
- "( function() {\n"
- "try {\n"
- "m = new Mongo( \"127.0.0.1:\" + port );\n"
- "return true;\n"
- "} catch( e ) {\n"
- "}\n"
- "return false;\n"
- "}, \"unable to connect to mongo program on port \" + port, 30000 );\n"
- "return m;\n"
- "}\n"
- "startMongoProgramNoConnect = function() {\n"
- "return _startMongoProgram.apply( null, arguments );\n"
- "}\n"
- "myPort = function() {\n"
- "var m = db.getMongo();\n"
- "if ( m.host.match( /:/ ) )\n"
- "return m.host.match( /:(.*)/ )[ 1 ];\n"
- "else\n"
- "return 27017;\n"
- "}\n"
- "ShardingTest = function( testName , numServers , verboseLevel , numMongos ){\n"
- "this._connections = [];\n"
- "this._serverNames = [];\n"
- "for ( var i=0; i<numServers; i++){\n"
- "var conn = startMongod( { port : 30000 + i , dbpath : \"/data/db/\" + testName + i , noprealloc : \"\" } );\n"
- "conn.name = \"localhost:\" + ( 30000 + i );\n"
- "this._connections.push( conn );\n"
- "this._serverNames.push( conn.name );\n"
- "}\n"
- "this._configDB = \"localhost:30000\";\n"
- "this._mongos = [];\n"
- "var startMongosPort = 39999;\n"
- "for ( var i=0; i<(numMongos||1); i++ ){\n"
- "var myPort = startMongosPort - i;\n"
- "var conn = startMongos( { port : startMongosPort - i , v : verboseLevel || 0 , configdb : this._configDB } );\n"
- "conn.name = \"localhost:\" + myPort;\n"
- "this._mongos.push( conn );\n"
- "if ( i == 0 )\n"
- "this.s = conn;\n"
- "}\n"
- "var admin = this.admin = this.s.getDB( \"admin\" );\n"
- "this.config = this.s.getDB( \"config\" );\n"
- "this._serverNames.forEach(\n"
- "function(z){\n"
- "admin.runCommand( { addshard : z } );\n"
- "}\n"
- ");\n"
- "}\n"
- "ShardingTest.prototype.getDB = function( name ){\n"
- "return this.s.getDB( name );\n"
- "}\n"
- "ShardingTest.prototype.getServerName = function( dbname ){\n"
- "return this.config.databases.findOne( { name : dbname } ).primary;\n"
- "}\n"
- "ShardingTest.prototype.getServer = function( dbname ){\n"
- "var name = this.getServerName( dbname );\n"
- "for ( var i=0; i<this._serverNames.length; i++ ){\n"
- "if ( name == this._serverNames[i] )\n"
- "return this._connections[i];\n"
- "}\n"
- "throw \"can't find server for: \" + dbname + \" name:\" + name;\n"
- "}\n"
- "ShardingTest.prototype.getOther = function( one ){\n"
- "if ( this._connections.length != 2 )\n"
- "throw \"getOther only works with 2 servers\";\n"
- "if ( this._connections[0] == one )\n"
- "return this._connections[1];\n"
- "return this._connections[0];\n"
- "}\n"
- "ShardingTest.prototype.stop = function(){\n"
- "for ( var i=0; i<this._mongos.length; i++ ){\n"
- "stopMongoProgram( 39999 - i );\n"
- "}\n"
- "for ( var i=0; i<this._connections.length; i++){\n"
- "stopMongod( 30000 + i );\n"
- "}\n"
- "}\n"
- "ShardingTest.prototype.adminCommand = function(cmd){\n"
- "var res = this.admin.runCommand( cmd );\n"
- "if ( res && res.ok == 1 )\n"
- "return true;\n"
- "throw \"command \" + tojson( cmd ) + \" failed: \" + tojson( res );\n"
- "}\n"
- "ShardingTest.prototype.getChunksString = function( ns ){\n"
- "var q = {}\n"
- "if ( ns )\n"
- "q.ns = ns;\n"
- "return Array.tojson( this.config.chunks.find( q ).toArray() , \"\\n\" );\n"
- "}\n"
- "ShardingTest.prototype.printChunks = function( ns ){\n"
- "print( this.getChunksString( ns ) );\n"
- "}\n"
- "ShardingTest.prototype.sync = function(){\n"
- "this.adminCommand( \"connpoolsync\" );\n"
- "}\n"
- "MongodRunner = function( port, dbpath, peer, arbiter, extraArgs ) {\n"
- "this.port_ = port;\n"
- "this.dbpath_ = dbpath;\n"
- "this.peer_ = peer;\n"
- "this.arbiter_ = arbiter;\n"
- "this.extraArgs_ = extraArgs;\n"
- "}\n"
- "MongodRunner.prototype.start = function( reuseData ) {\n"
- "var args = [];\n"
- "if ( reuseData ) {\n"
- "args.push( \"mongod\" );\n"
- "}\n"
- "args.push( \"--port\" );\n"
- "args.push( this.port_ );\n"
- "args.push( \"--dbpath\" );\n"
- "args.push( this.dbpath_ );\n"
- "if ( this.peer_ && this.arbiter_ ) {\n"
- "args.push( \"--pairwith\" );\n"
- "args.push( this.peer_ );\n"
- "args.push( \"--arbiter\" );\n"
- "args.push( this.arbiter_ );\n"
- "args.push( \"--oplogSize\" );\n"
- "args.push( \"1\" );\n"
- "}\n"
- "args.push( \"--nohttpinterface\" );\n"
- "args.push( \"--noprealloc\" );\n"
- "args.push( \"--bind_ip\" );\n"
- "args.push( \"127.0.0.1\" );\n"
- "if ( this.extraArgs_ ) {\n"
- "args = args.concat( this.extraArgs_ );\n"
- "}\n"
- "if ( reuseData ) {\n"
- "return startMongoProgram.apply( null, args );\n"
- "} else {\n"
- "return startMongod.apply( null, args );\n"
- "}\n"
- "}\n"
- "MongodRunner.prototype.port = function() { return this.port_; }\n"
- "MongodRunner.prototype.toString = function() { return [ this.port_, this.dbpath_, this.peer_, this.arbiter_ ].toString(); }\n"
- "ReplPair = function( left, right, arbiter ) {\n"
- "this.left_ = left;\n"
- "this.leftC_ = null;\n"
- "this.right_ = right;\n"
- "this.rightC_ = null;\n"
- "this.arbiter_ = arbiter;\n"
- "this.arbiterC_ = null;\n"
- "this.master_ = null;\n"
- "this.slave_ = null;\n"
- "}\n"
- "ReplPair.prototype.start = function( reuseData ) {\n"
- "if ( this.arbiterC_ == null ) {\n"
- "this.arbiterC_ = this.arbiter_.start();\n"
- "}\n"
- "if ( this.leftC_ == null ) {\n"
- "this.leftC_ = this.left_.start( reuseData );\n"
- "}\n"
- "if ( this.rightC_ == null ) {\n"
- "this.rightC_ = this.right_.start( reuseData );\n"
- "}\n"
- "}\n"
- "ReplPair.prototype.isMaster = function( mongo, debug ) {\n"
- "var im = mongo.getDB( \"admin\" ).runCommand( { ismaster : 1 } );\n"
- "assert( im && im.ok, \"command ismaster failed\" );\n"
- "if ( debug ) {\n"
- "printjson( im );\n"
- "}\n"
- "return im.ismaster;\n"
- "}\n"
- "ReplPair.prototype.isInitialSyncComplete = function( mongo, debug ) {\n"
- "var isc = mongo.getDB( \"admin\" ).runCommand( { isinitialsynccomplete : 1 } );\n"
- "assert( isc && isc.ok, \"command isinitialsynccomplete failed\" );\n"
- "if ( debug ) {\n"
- "printjson( isc );\n"
- "}\n"
- "return isc.initialsynccomplete;\n"
- "}\n"
- "ReplPair.prototype.checkSteadyState = function( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ) {\n"
- "leftValues = leftValues || {};\n"
- "rightValues = rightValues || {};\n"
- "var lm = null;\n"
- "var lisc = null;\n"
- "if ( this.leftC_ != null ) {\n"
- "lm = this.isMaster( this.leftC_, debug );\n"
- "leftValues[ lm ] = true;\n"
- "lisc = this.isInitialSyncComplete( this.leftC_, debug );\n"
- "}\n"
- "var rm = null;\n"
- "var risc = null;\n"
- "if ( this.rightC_ != null ) {\n"
- "rm = this.isMaster( this.rightC_, debug );\n"
- "rightValues[ rm ] = true;\n"
- "risc = this.isInitialSyncComplete( this.rightC_, debug );\n"
- "}\n"
- "var stateSet = {}\n"
- "state.forEach( function( i ) { stateSet[ i ] = true; } );\n"
- "if ( !( 1 in stateSet ) || ( ( risc || risc == null ) && ( lisc || lisc == null ) ) ) {\n"
- "if ( rm == 1 && lm != 1 ) {\n"
- "assert( twoMasterOk || !( 1 in leftValues ) );\n"
- "this.master_ = this.rightC_;\n"
- "this.slave_ = this.leftC_;\n"
- "} else if ( lm == 1 && rm != 1 ) {\n"
- "assert( twoMasterOk || !( 1 in rightValues ) );\n"
- "this.master_ = this.leftC_;\n"
- "this.slave_ = this.rightC_;\n"
- "}\n"
- "if ( !twoMasterOk ) {\n"
- "assert( lm != 1 || rm != 1, \"two masters\" );\n"
- "}\n"
- "if ( state.sort().toString() == [ lm, rm ].sort().toString() ) {\n"
- "if ( expectedMasterHost != null ) {\n"
- "if( expectedMasterHost == this.master_.host ) {\n"
- "return true;\n"
- "}\n"
- "} else {\n"
- "return true;\n"
- "}\n"
- "}\n"
- "}\n"
- "this.master_ = null;\n"
- "this.slave_ = null;\n"
- "return false;\n"
- "}\n"
- "ReplPair.prototype.waitForSteadyState = function( state, expectedMasterHost, twoMasterOk, debug ) {\n"
- "state = state || [ 1, 0 ];\n"
- "twoMasterOk = twoMasterOk || false;\n"
- "var rp = this;\n"
- "var leftValues = {};\n"
- "var rightValues = {};\n"
- "assert.soon( function() { return rp.checkSteadyState( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ); },\n"
- "\"rp (\" + rp + \") failed to reach expected steady state (\" + state + \")\" );\n"
- "}\n"
- "ReplPair.prototype.master = function() { return this.master_; }\n"
- "ReplPair.prototype.slave = function() { return this.slave_; }\n"
- "ReplPair.prototype.right = function() { return this.rightC_; }\n"
- "ReplPair.prototype.left = function() { return this.leftC_; }\n"
- "ReplPair.prototype.killNode = function( mongo, signal ) {\n"
- "signal = signal || 15;\n"
- "if ( this.leftC_ != null && this.leftC_.host == mongo.host ) {\n"
- "stopMongod( this.left_.port_ );\n"
- "this.leftC_ = null;\n"
- "}\n"
- "if ( this.rightC_ != null && this.rightC_.host == mongo.host ) {\n"
- "stopMongod( this.right_.port_ );\n"
- "this.rightC_ = null;\n"
- "}\n"
- "}\n"
- "ReplPair.prototype._annotatedNode = function( mongo ) {\n"
- "var ret = \"\";\n"
- "if ( mongo != null ) {\n"
- "ret += \" (connected)\";\n"
- "if ( this.master_ != null && mongo.host == this.master_.host ) {\n"
- "ret += \"(master)\";\n"
- "}\n"
- "if ( this.slave_ != null && mongo.host == this.slave_.host ) {\n"
- "ret += \"(slave)\";\n"
- "}\n"
- "}\n"
- "return ret;\n"
- "}\n"
- "ReplPair.prototype.toString = function() {\n"
- "var ret = \"\";\n"
- "ret += \"left: \" + this.left_;\n"
- "ret += \" \" + this._annotatedNode( this.leftC_ );\n"
- "ret += \" right: \" + this.right_;\n"
- "ret += \" \" + this._annotatedNode( this.rightC_ );\n"
- "return ret;\n"
- "}\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"
- "}\n"
- "doassert = function( msg ){\n"
- "print( \"assert: \" + msg );\n"
- "throw msg;\n"
- "}\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"
- "}\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"
- "}\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"
- "}\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"
- "}\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"
- "if ( f() )\n"
- "return;\n"
- "}\n"
- "if ( ( new Date() ).getTime() - start.getTime() > timeout )\n"
- "doassert( \"assert.soon failed: \" + f + \", msg:\" + msg );\n"
- "sleep( interval );\n"
- "}\n"
- "}\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"
- "}\n"
- "catch ( e ){\n"
- "return e;\n"
- "}\n"
- "doassert( \"did not throw exception: \" + msg );\n"
- "}\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"
- "}\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"
- "}\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"
- "}\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"
- "}\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"
- "}\n"
- "Object.extend = function( dst , src ){\n"
- "for ( var k in src ){\n"
- "dst[k] = src[k];\n"
- "}\n"
- "return dst;\n"
- "}\n"
- "argumentsToArray = function( a ){\n"
- "var arr = [];\n"
- "for ( var i=0; i<a.length; i++ )\n"
- "arr[i] = a[i];\n"
- "return arr;\n"
- "}\n"
- "isString = function( x ){\n"
- "return typeof( x ) == \"string\";\n"
- "}\n"
- "isNumber = function(x){\n"
- "return typeof( x ) == \"number\";\n"
- "}\n"
- "isObject = function( x ){\n"
- "return typeof( x ) == \"object\";\n"
- "}\n"
- "String.prototype.trim = function() {\n"
- "return this.replace(/^\\s+|\\s+$/g,\"\");\n"
- "}\n"
- "String.prototype.ltrim = function() {\n"
- "return this.replace(/^\\s+/,\"\");\n"
- "}\n"
- "String.prototype.rtrim = function() {\n"
- "return this.replace(/\\s+$/,\"\");\n"
- "}\n"
- "Date.timeFunc = function( theFunc , numTimes ){\n"
- "var start = new Date();\n"
- "numTimes = numTimes || 1;\n"
- "for ( var i=0; i<numTimes; i++ ){\n"
- "theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) );\n"
- "}\n"
- "return (new Date()).getTime() - start.getTime();\n"
- "}\n"
- "Date.prototype.tojson = function(){\n"
- "return \"\\\"\" + this.toString() + \"\\\"\";\n"
- "}\n"
- "RegExp.prototype.tojson = RegExp.prototype.toString;\n"
- "Array.contains = function( a , x ){\n"
- "for ( var i=0; i<a.length; i++ ){\n"
- "if ( a[i] == x )\n"
- "return true;\n"
- "}\n"
- "return false;\n"
- "}\n"
- "Array.unique = function( a ){\n"
- "var u = [];\n"
- "for ( var i=0; i<a.length; i++){\n"
- "var o = a[i];\n"
- "if ( ! Array.contains( u , o ) ){\n"
- "u.push( o );\n"
- "}\n"
- "}\n"
- "return u;\n"
- "}\n"
- "Array.shuffle = function( arr ){\n"
- "for ( var i=0; i<arr.length-1; i++ ){\n"
- "var pos = i+Math.floor(Math.random()*(arr.length-i));\n"
- "var save = arr[i];\n"
- "arr[i] = arr[pos];\n"
- "arr[pos] = save;\n"
- "}\n"
- "return arr;\n"
- "}\n"
- "Array.tojson = function( a , sepLines ){\n"
- "var s = \"[\";\n"
- "if ( sepLines ) s += \"\\n\";\n"
- "for ( var i=0; i<a.length; i++){\n"
- "if ( i > 0 ){\n"
- "s += \",\";\n"
- "if ( sepLines ) s += \"\\n\";\n"
- "}\n"
- "s += tojson( a[i] );\n"
- "}\n"
- "s += \"]\";\n"
- "if ( sepLines ) s += \"\\n\";\n"
- "return s;\n"
- "}\n"
- "Array.fetchRefs = function( arr , coll ){\n"
- "var n = [];\n"
- "for ( var i=0; i<arr.length; i ++){\n"
- "var z = arr[i];\n"
- "if ( coll && coll != z.getCollection() )\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"
- "n.push( z.fetch() );\n"
- "}\n"
- "return n;\n"
- "}\n"
- "if ( ! ObjectId.prototype )\n"
- "ObjectId.prototype = {}\n"
- "ObjectId.prototype.toString = function(){\n"
- "return this.str;\n"
- "}\n"
- "ObjectId.prototype.tojson = function(){\n"
- "return \" ObjectId( \\\"\" + this.str + \"\\\") \";\n"
- "}\n"
- "ObjectId.prototype.isObjectId = true;\n"
- "if ( typeof( DBPointer ) != \"undefined\" ){\n"
- "DBPointer.prototype.fetch = function(){\n"
- "assert( this.ns , \"need a ns\" );\n"
- "assert( this.id , \"need an id\" );\n"
- "return db[ this.ns ].findOne( { _id : this.id } );\n"
- "}\n"
- "DBPointer.prototype.tojson = function(){\n"
- "return \"{ 'ns' : \\\"\" + this.ns + \"\\\" , 'id' : \\\"\" + this.id + \"\\\" } \";\n"
- "}\n"
- "DBPointer.prototype.getCollection = function(){\n"
- "return this.ns;\n"
- "}\n"
- "DBPointer.prototype.toString = function(){\n"
- "return \"DBPointer \" + this.ns + \":\" + this.id;\n"
- "}\n"
- "}\n"
- "else {\n"
- "print( \"warning: no DBPointer\" );\n"
- "}\n"
- "if ( typeof( DBRef ) != \"undefined\" ){\n"
- "DBRef.prototype.fetch = function(){\n"
- "assert( this.$ref , \"need a ns\" );\n"
- "assert( this.$id , \"need an id\" );\n"
- "return db[ this.$ref ].findOne( { _id : this.$id } );\n"
- "}\n"
- "DBRef.prototype.tojson = function(){\n"
- "return \"{ '$ref' : \\\"\" + this.$ref + \"\\\" , '$id' : \\\"\" + this.$id + \"\\\" } \";\n"
- "}\n"
- "DBRef.prototype.getCollection = function(){\n"
- "return this.$ref;\n"
- "}\n"
- "DBRef.prototype.toString = function(){\n"
- "return this.tojson();\n"
- "}\n"
- "}\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<options.length; i++ ){\n"
+ "if ( typeof ( options[i] ) == \"string\" )\n"
+ "ret.name = options[i];\n"
+ "else if ( typeof( options[i] ) == \"boolean\" ){\n"
+ "if ( options[i] ){\n"
+ "if ( nb == 0 )\n"
+ "ret.unique = true;\n"
+ "if ( nb == 1 )\n"
+ "ret.dropDups = true;}\n"
+ "nb++;}}}\n"
"else {\n"
- "print( \"warning: no DBRef\" );\n"
- "}\n"
- "if ( typeof( BinData ) != \"undefined\" ){\n"
- "BinData.prototype.tojson = function(){\n"
- "return \"BinData type: \" + this.type + \" len: \" + this.len;\n"
- "}\n"
- "}\n"
+ "Object.extend( ret , options );}}\n"
"else {\n"
- "print( \"warning: no BinData\" );\n"
- "}\n"
- "tojson = function( x ){\n"
- "if ( x == null )\n"
- "return \"null\";\n"
- "if ( x == undefined )\n"
- "return \"\";\n"
- "switch ( typeof x ){\n"
- "case \"string\": {\n"
- "var s = \"\\\"\";\n"
- "for ( var i=0; i<x.length; i++ ){\n"
- "if ( x[i] == '\"' ){\n"
- "s += \"\\\\\\\"\";\n"
- "}\n"
- "else\n"
- "s += x[i];\n"
- "}\n"
- "return s + \"\\\"\";\n"
- "}\n"
- "case \"number\":\n"
- "case \"boolean\":\n"
- "return \"\" + x;\n"
- "case \"object\":\n"
- "return tojsonObject( x );\n"
- "case \"function\":\n"
- "return x.toString();\n"
- "default:\n"
- "throw \"tojson can't handle type \" + ( typeof x );\n"
- "}\n"
- "}\n"
- "tojsonObject = function( x ){\n"
- "assert.eq( ( typeof x ) , \"object\" , \"tojsonObject needs object, not [\" + ( typeof x ) + \"]\" );\n"
- "if ( typeof( x.tojson ) == \"function\" && x.tojson != tojson )\n"
- "return x.tojson();\n"
- "if ( typeof( x.constructor.tojson ) == \"function\" && x.constructor.tojson != tojson )\n"
- "return x.constructor.tojson( x );\n"
- "if ( x.toString() == \"[object MaxKey]\" )\n"
- "return \"{ $maxKey : 1 }\";\n"
- "if ( x.toString() == \"[object MinKey]\" )\n"
- "return \"{ $minKey : 1 }\";\n"
- "var s = \"{\";\n"
- "var first = true;\n"
- "for ( var k in x ){\n"
- "var val = x[k];\n"
- "if ( val == DB.prototype || val == DBCollection.prototype )\n"
- "continue;\n"
- "if ( first ) first = false;\n"
- "else s += \" , \";\n"
- "s += \"\\\"\" + k + \"\\\" : \" + tojson( val );\n"
- "}\n"
- "return s + \"}\";\n"
- "}\n"
- "shellPrint = function( x ){\n"
- "it = x;\n"
- "if ( x != undefined )\n"
- "shellPrintHelper( x );\n"
- "if ( db ){\n"
- "var e = db.getPrevError();\n"
- "if ( e.err ) {\n"
- "if( e.nPrev <= 1 )\n"
- "print( \"error on last call: \" + tojson( e.err ) );\n"
- "else\n"
- "print( \"an error \" + tojson(e.err) + \" occurred \" + e.nPrev + \" operations back in the command invocation\" );\n"
- "}\n"
- "db.resetError();\n"
- "}\n"
- "}\n"
- "printjson = function(x){\n"
- "print( tojson( x ) );\n"
- "}\n"
- "shellPrintHelper = function( x ){\n"
- "if ( typeof( x ) == \"undefined\" ){\n"
- "if ( typeof( db ) != \"undefined\" && db.getLastError ){\n"
- "var e = db.getLastError();\n"
- "if ( e != null )\n"
- "print( e );\n"
- "}\n"
- "return;\n"
- "}\n"
- "if ( x == null ){\n"
- "print( \"null\" );\n"
- "return;\n"
- "}\n"
- "if ( typeof x != \"object\" )\n"
- "return print( x );\n"
- "var p = x.shellPrint;\n"
- "if ( typeof p == \"function\" )\n"
- "return x.shellPrint();\n"
- "var p = x.tojson;\n"
- "if ( typeof p == \"function\" )\n"
- "print( x.tojson() );\n"
- "else\n"
- "print( tojson( x ) );\n"
- "}\n"
- "shellHelper = function( command , rest , shouldPrint ){\n"
- "command = command.trim();\n"
- "var args = rest.trim().replace(/;$/,\"\").split( \"\\s+\" );\n"
- "if ( ! shellHelper[command] )\n"
- "throw \"no command [\" + command + \"]\";\n"
- "var res = shellHelper[command].apply( null , args );\n"
- "if ( shouldPrint ){\n"
- "shellPrintHelper( res );\n"
- "}\n"
+ "throw \"can't handle: \" + typeof( options );}\n"
+ "/*\n"
+ "return ret;\n"
+ "var name;\n"
+ "var nTrue = 0;\n"
+ "if ( ! isObject( options ) ) {\n"
+ "options = [ options ];}\n"
+ "if ( options.length ){\n"
+ "for( var i = 0; i < options.length; ++i ) {\n"
+ "var o = options[ i ];\n"
+ "if ( isString( o ) ) {\n"
+ "ret.name = o;\n"
+ "} else if ( typeof( o ) == \"boolean\" ) {\n"
+ "if ( o ) {\n"
+ "++nTrue;}}}\n"
+ "if ( nTrue > 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"
- "}\n"
- "help = shellHelper.help = function(){\n"
- "print( \"HELP\" );\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 <db name> set curent database to <db name>\" );\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"
- "}\n"
- "shellHelper.use = function( dbname ){\n"
- "db = db.getMongo().getDB( dbname );\n"
- "print( \"switched to db \" + db.getName() );\n"
- "}\n"
- "shellHelper.it = function(){\n"
- "if ( typeof( ___it___ ) == \"undefined\" || ___it___ == null ){\n"
- "print( \"no cursor\" );\n"
- "return;\n"
- "}\n"
- "shellPrintHelper( ___it___ );\n"
- "}\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"
- "}\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"
- "}\n"
- "return \"\";\n"
- "}\n"
- "if ( what == \"users\" ){\n"
- "db.system.users.find().forEach( printjson );\n"
- "return \"\";\n"
- "}\n"
- "if ( what == \"collections\" || what == \"tables\" ) {\n"
- "db.getCollectionNames().forEach( function(x){print(x)} );\n"
- "return \"\";\n"
- "}\n"
- "if ( what == \"dbs\" ) {\n"
- "db.getMongo().getDBNames().sort().forEach( function(x){print(x)} );\n"
- "return \"\";\n"
- "}\n"
- "throw \"don't know how to show [\" + what + \"]\";\n"
- "}\n"
- "if ( typeof( Map ) == \"undefined\" ){\n"
- "Map = function(){\n"
- "this._data = {};\n"
- "}\n"
- "}\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"
- "}\n"
- "return s;\n"
- "}\n"
- "throw \"can't hash : \" + typeof( val );\n"
- "}\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"
- "}\n"
- "Map.prototype.get = function( key ){\n"
- "return this._get( key ).value;\n"
- "}\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"
- "}\n"
- "for ( var i=0; i<a.length; i++ ){\n"
- "if ( friendlyEqual( key , a[i].key ) ){\n"
- "return a[i];\n"
- "}\n"
- "}\n"
- "var o = { key : key , value : null };\n"
- "a.push( o );\n"
- "return o;\n"
- "}\n"
- "Map.prototype.values = function(){\n"
- "var all = [];\n"
- "for ( var k in this._data ){\n"
- "this._data[k].forEach( function(z){ all.push( z.value ); } );\n"
- "}\n"
- "return all;\n"
- "}\n"
- "Math.sigFig = function( x , N ){\n"
- "if ( ! N ){\n"
- "N = 3;\n"
- "}\n"
- "var p = Math.pow( 10, N - Math.ceil( Math.log( Math.abs(x) ) / Math.log( 10 )) );\n"
- "return Math.round(x*p)/p;\n"
- "}\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"
;
diff --git a/shell/query.js b/shell/query.js
index aabd12e..508fba2 100644
--- a/shell/query.js
+++ b/shell/query.js
@@ -1,7 +1,7 @@
// query.js
if ( typeof DBQuery == "undefined" ){
- DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip ){
+ DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip , batchSize ){
this._mongo = mongo; // 0
this._db = db; // 1
@@ -12,7 +12,8 @@ if ( typeof DBQuery == "undefined" ){
this._fields = fields; // 5
this._limit = limit || 0; // 6
this._skip = skip || 0; // 7
-
+ this._batchSize = batchSize || 0;
+
this._cursor = null;
this._numReturned = 0;
this._special = false;
@@ -36,7 +37,7 @@ DBQuery.prototype.help = function(){
DBQuery.prototype.clone = function(){
var q = new DBQuery( this._mongo , this._db , this._collection , this._ns ,
this._query , this._fields ,
- this._limit , this._skip );
+ this._limit , this._skip , this._batchSize );
q._special = this._special;
return q;
}
@@ -58,7 +59,7 @@ DBQuery.prototype._checkModify = function(){
DBQuery.prototype._exec = function(){
if ( ! this._cursor ){
assert.eq( 0 , this._numReturned );
- this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip );
+ this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip , this._batchSize );
this._cursorSeen = 0;
}
return this._cursor;
@@ -70,6 +71,13 @@ DBQuery.prototype.limit = function( limit ){
return this;
}
+DBQuery.prototype.batchSize = function( batchSize ){
+ this._checkModify();
+ this._batchSize = batchSize;
+ return this;
+}
+
+
DBQuery.prototype.skip = function( skip ){
this._checkModify();
this._skip = skip;
@@ -167,28 +175,26 @@ DBQuery.prototype.length = function(){
return this.toArray().length;
}
-DBQuery.prototype.sort = function( sortBy ){
+DBQuery.prototype._addSpecial = function( name , value ){
this._ensureSpecial();
- this._query.orderby = sortBy;
+ this._query[name] = value;
return this;
}
+DBQuery.prototype.sort = function( sortBy ){
+ return this._addSpecial( "orderby" , sortBy );
+}
+
DBQuery.prototype.hint = function( hint ){
- this._ensureSpecial();
- this._query["$hint"] = hint;
- return this;
+ return this._addSpecial( "$hint" , hint );
}
DBQuery.prototype.min = function( min ) {
- this._ensureSpecial();
- this._query["$min"] = min;
- return this;
+ return this._addSpecial( "$min" , min );
}
DBQuery.prototype.max = function( max ) {
- this._ensureSpecial();
- this._query["$max"] = max;
- return this;
+ return this._addSpecial( "$max" , max );
}
DBQuery.prototype.forEach = function( func ){
@@ -219,7 +225,7 @@ DBQuery.prototype.snapshot = function(){
this._ensureSpecial();
this._query.$snapshot = true;
return this;
- }
+}
DBQuery.prototype.shellPrint = function(){
try {
diff --git a/shell/servers.js b/shell/servers.js
index 109f871..f681263 100644
--- a/shell/servers.js
+++ b/shell/servers.js
@@ -32,6 +32,7 @@ createMongoArgs = function( binaryName , args ){
if ( k == "v" && isNumber( o[k] ) ){
var n = o[k];
if ( n > 0 ){
+ if ( n > 10 ) n = 10;
var temp = "-";
while ( n-- > 0 ) temp += "v";
fullArgs.push( temp );
@@ -52,6 +53,25 @@ createMongoArgs = function( binaryName , args ){
return fullArgs;
}
+startMongodTest = function( port , dirname , restart ){
+ var f = startMongod;
+ if ( restart )
+ f = startMongodNoReset;
+ var conn = f.apply( null , [
+ {
+ port : port ,
+ dbpath : "/data/db/" + dirname ,
+ noprealloc : "" ,
+ smallfiles : "" ,
+ oplogSize : "2" ,
+ nohttpinterface : ""
+ }
+ ]
+ );
+ conn.name = "localhost:" + port;
+ return conn;
+}
+
// 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.
@@ -65,6 +85,11 @@ startMongod = function(){
return startMongoProgram.apply( null, args );
}
+startMongodNoReset = function(){
+ var args = createMongoArgs( "mongod" , arguments );
+ return startMongoProgram.apply( null, args );
+}
+
startMongos = function(){
return startMongoProgram.apply( null, createMongoArgs( "mongos" , arguments ) );
}
@@ -87,7 +112,7 @@ startMongoProgram = function(){
} catch( e ) {
}
return false;
- }, "unable to connect to mongo program on port " + port, 30000 );
+ }, "unable to connect to mongo program on port " + port, 60000 );
return m;
}
@@ -107,24 +132,31 @@ myPort = function() {
return 27017;
}
-ShardingTest = function( testName , numServers , verboseLevel , numMongos ){
+ShardingTest = function( testName , numServers , verboseLevel , numMongos , otherParams ){
+ if ( ! otherParams )
+ otherParams = {}
this._connections = [];
- this._serverNames = [];
+
+ if ( otherParams.sync && numServers < 3 )
+ throw "if you want sync, you need at least 3 servers";
for ( var i=0; i<numServers; i++){
- var conn = startMongod( { port : 30000 + i , dbpath : "/data/db/" + testName + i ,
- noprealloc : "" , smallfiles : "" , oplogSize : "2" } );
- conn.name = "localhost:" + ( 30000 + i );
-
+ var conn = startMongodTest( 30000 + i , testName + i );
this._connections.push( conn );
- this._serverNames.push( conn.name );
}
- this._configDB = "localhost:30000";
-
+ if ( otherParams.sync ){
+ this._configDB = "localhost:30000,localhost:30001,localhost:30002";
+ this._configConnection = new Mongo( this._configDB );
+ this._configConnection.getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );
+ }
+ else {
+ this._configDB = "localhost:30000";
+ this._connections[0].getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );
+ }
this._mongos = [];
- var startMongosPort = 39999;
+ var startMongosPort = 31000;
for ( var i=0; i<(numMongos||1); i++ ){
var myPort = startMongosPort - i;
var conn = startMongos( { port : startMongosPort - i , v : verboseLevel || 0 , configdb : this._configDB } );
@@ -137,9 +169,9 @@ ShardingTest = function( testName , numServers , verboseLevel , numMongos ){
var admin = this.admin = this.s.getDB( "admin" );
this.config = this.s.getDB( "config" );
- this._serverNames.forEach(
+ this._connections.forEach(
function(z){
- admin.runCommand( { addshard : z , allowLocal : true } );
+ admin.runCommand( { addshard : z.name , allowLocal : true } );
}
);
}
@@ -154,9 +186,10 @@ ShardingTest.prototype.getServerName = function( dbname ){
ShardingTest.prototype.getServer = function( dbname ){
var name = this.getServerName( dbname );
- for ( var i=0; i<this._serverNames.length; i++ ){
- if ( name == this._serverNames[i] )
- return this._connections[i];
+ for ( var i=0; i<this._connections.length; i++ ){
+ var c = this._connections[i];
+ if ( name == c.name )
+ return c;
}
throw "can't find server for: " + dbname + " name:" + name;
@@ -171,9 +204,17 @@ ShardingTest.prototype.getOther = function( one ){
return this._connections[0];
}
+ShardingTest.prototype.getFirstOther = function( one ){
+ for ( var i=0; i<this._connections.length; i++ ){
+ if ( this._connections[i] != one )
+ return this._connections[i];
+ }
+ throw "impossible";
+}
+
ShardingTest.prototype.stop = function(){
for ( var i=0; i<this._mongos.length; i++ ){
- stopMongoProgram( 39999 - i );
+ stopMongoProgram( 31000 - i );
}
for ( var i=0; i<this._connections.length; i++){
stopMongod( 30000 + i );
@@ -322,6 +363,7 @@ MongodRunner.prototype.start = function( reuseData ) {
if ( this.extraArgs_ ) {
args = args.concat( this.extraArgs_ );
}
+ removeFile( this.dbpath_ + "/mongod.lock" );
if ( reuseData ) {
return startMongoProgram.apply( null, args );
} else {
@@ -551,7 +593,7 @@ ReplTest.prototype.getPath = function( master ){
}
-ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst ){
+ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst, norepl ){
if ( ! extra )
extra = {};
@@ -571,13 +613,15 @@ ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst ){
a.push( this.getPath( master ) );
- if ( master ){
- a.push( "--master" );
- }
- else {
- a.push( "--slave" );
- a.push( "--source" );
- a.push( "127.0.0.1:" + this.ports[0] );
+ if ( !norepl ) {
+ if ( master ){
+ a.push( "--master" );
+ }
+ else {
+ a.push( "--slave" );
+ a.push( "--source" );
+ a.push( "127.0.0.1:" + this.ports[0] );
+ }
}
for ( var k in extra ){
@@ -590,8 +634,10 @@ ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst ){
return a;
}
-ReplTest.prototype.start = function( master , options , restart ){
- var o = this.getOptions( master , options , restart );
+ReplTest.prototype.start = function( master , options , restart, norepl ){
+ var lockFile = this.getPath( master ) + "/mongod.lock";
+ removeFile( lockFile );
+ var o = this.getOptions( master , options , restart, norepl );
if ( restart )
return startMongoProgram.apply( null , o );
else
@@ -604,5 +650,53 @@ ReplTest.prototype.stop = function( master , signal ){
this.stop( false );
return;
}
- stopMongod( this.getPort( master ) , signal || 15 );
+ return stopMongod( this.getPort( master ) , signal || 15 );
+}
+
+allocatePorts = function( n ) {
+ var ret = [];
+ for( var i = 31000; i < 31000 + n; ++i )
+ ret.push( i );
+ return ret;
+}
+
+
+SyncCCTest = function( testName ){
+ this._testName = testName;
+ this._connections = [];
+
+ for ( var i=0; i<3; i++ ){
+ this._connections.push( startMongodTest( 30000 + i , testName + i ) );
+ }
+
+ this.url = this._connections.map( function(z){ return z.name; } ).join( "," );
+ this.conn = new Mongo( this.url );
+}
+
+SyncCCTest.prototype.stop = function(){
+ for ( var i=0; i<this._connections.length; i++){
+ stopMongod( 30000 + i );
+ }
+}
+
+SyncCCTest.prototype.checkHashes = function( dbname , msg ){
+ var hashes = this._connections.map(
+ function(z){
+ return z.getDB( dbname ).runCommand( "dbhash" );
+ }
+ );
+
+ for ( var i=1; i<hashes.length; i++ ){
+ assert.eq( hashes[0].md5 , hashes[i].md5 , "checkHash on " + dbname + " " + msg + "\n" + tojson( hashes ) )
+ }
+}
+
+SyncCCTest.prototype.tempKill = function( num ){
+ num = num || 0;
+ stopMongod( 30000 + num );
+}
+
+SyncCCTest.prototype.tempStart = function( num ){
+ num = num || 0;
+ this._connections[num] = startMongodTest( 30000 + num , this._testName + num , true );
}
diff --git a/shell/utils.cpp b/shell/utils.cpp
index c4735ee..b10c93d 100644
--- a/shell/utils.cpp
+++ b/shell/utils.cpp
@@ -1,4 +1,22 @@
// 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 <boost/thread/xtime.hpp>
@@ -10,20 +28,32 @@
#include <map>
#include <sstream>
#include <vector>
+#include <fcntl.h>
-#ifndef _WIN32
-#include <sys/socket.h>
-#include <netinet/in.h>
+#ifdef _WIN32
+# include <io.h>
+# define SIGKILL 9
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <signal.h>
+# include <sys/stat.h>
+# include <sys/wait.h>
#endif
#include "../client/dbclient.h"
#include "../util/processinfo.h"
-#include "../util/md5.hpp"
#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 {
@@ -73,6 +103,32 @@ namespace mongo {
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 );
@@ -80,7 +136,10 @@ namespace mongo {
string rootname = args.firstElement().valuestrsafe();
path root( rootname );
- uassert( 12581, "listFiles: no such directory", boost::filesystem::exists( root ) );
+ 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);
@@ -113,92 +172,34 @@ namespace mongo {
ret.appendArray( "", lst.done() );
return ret.obj();
}
-
- 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();
- }
- BSONObj JSVersion( const BSONObj& args ){
- cout << "version: " << versionString << endl;
- if ( strstr( versionString , "+" ) )
- printGitVersion();
- return BSONObj();
- }
-
-#ifndef _WIN32
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
- BSONObj AllocatePorts( const BSONObj &args ) {
- uassert( 10259 , "allocatePorts takes exactly 1 argument", args.nFields() == 1 );
- uassert( 10260 , "allocatePorts needs to be passed an integer", args.firstElement().isNumber() );
+ BSONObj removeFile(const BSONObj& args){
+ uassert( 12597 , "need to specify 1 argument to listFiles" , args.nFields() == 1 );
- int n = int( args.firstElement().number() );
+ bool found = false;
- vector< int > ports;
- vector< int > sockets;
- for( int i = 0; i < n; ++i ) {
- int s = socket( AF_INET, SOCK_STREAM, 0 );
- assert( s );
-
- sockaddr_in address;
- memset(address.sin_zero, 0, sizeof(address.sin_zero));
- address.sin_family = AF_INET;
- address.sin_port = 0;
- address.sin_addr.s_addr = inet_addr( "127.0.0.1" );
- assert( 0 == ::bind( s, (sockaddr*)&address, sizeof( address ) ) );
-
- sockaddr_in newAddress;
- socklen_t len = sizeof( newAddress );
- assert( 0 == getsockname( s, (sockaddr*)&newAddress, &len ) );
- ports.push_back( ntohs( newAddress.sin_port ) );
- sockets.push_back( s );
+ path root( args.firstElement().valuestrsafe() );
+ if ( boost::filesystem::exists( root ) ){
+ found = true;
+ boost::filesystem::remove_all( root );
}
- for( vector< int >::const_iterator i = sockets.begin(); i != sockets.end(); ++i )
- assert( 0 == close( *i ) );
-
- sort( ports.begin(), ports.end() );
- for( unsigned i = 1; i < ports.size(); ++i )
- massert( 10434 , "duplicate ports allocated", ports[ i - 1 ] != ports[ i ] );
+
BSONObjBuilder b;
- b.append( "", ports );
+ 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
- char *copyString( const char *original ) {
- char *ret = reinterpret_cast< char * >( malloc( strlen( original ) + 1 ) );
- strcpy( ret, original );
- return ret;
- }
-
- boost::mutex &mongoProgramOutputMutex( *( new boost::mutex ) );
+ mongo::mutex mongoProgramOutputMutex;
stringstream mongoProgramOutput_;
-
+
void writeMongoProgramOutputLine( int port, int pid, const char *line ) {
- boost::mutex::scoped_lock lk( mongoProgramOutputMutex );
+ mongo::mutex::scoped_lock lk( mongoProgramOutputMutex );
stringstream buf;
if ( port > 0 )
buf << "m" << port << "| " << line;
@@ -208,38 +209,52 @@ namespace mongo {
mongoProgramOutput_ << buf.str() << endl;
}
+ // only returns last 100000 characters
BSONObj RawMongoProgramOutput( const BSONObj &args ) {
- boost::mutex::scoped_lock lk( mongoProgramOutputMutex );
- return BSON( "" << mongoProgramOutput_.str() );
+ 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 );
}
-
- class MongoProgramRunner {
- char **argv_;
+
+ BSONObj ClearRawMongoProgramOutput( const BSONObj &args ) {
+ mongo::mutex::scoped_lock lk( mongoProgramOutputMutex );
+ mongoProgramOutput_.str( "" );
+ return undefined_;
+ }
+
+ class ProgramRunner {
+ vector<string> argv_;
int port_;
int pipe_;
pid_t pid_;
public:
pid_t pid() const { return pid_; }
- MongoProgramRunner( const BSONObj &args ) {
- assert( args.nFields() > 0 );
+ ProgramRunner( const BSONObj &args , bool isMongoProgram=true)
+ {
+ assert( !args.isEmpty() );
+
string program( args.firstElement().valuestrsafe() );
-
assert( !program.empty() );
- boost::filesystem::path programPath = ( boost::filesystem::path( argv0 ) ).branch_path() / program;
- massert( 10435 , "couldn't find " + programPath.native_file_string(), boost::filesystem::exists( programPath ) );
+ 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;
- argv_ = new char *[ args.nFields() + 1 ];
- {
- string s = programPath.native_file_string();
- if ( s == program )
- s = "./" + s;
- argv_[ 0 ] = copyString( s.c_str() );
- }
BSONObjIterator j( args );
- j.next();
- for( int i = 1; i < args.nFields(); ++i ) {
+ j.next(); // skip program name (handled above)
+ while(j.more()) {
BSONElement e = j.next();
string str;
if ( e.isNumber() ) {
@@ -250,14 +265,12 @@ namespace mongo {
assert( e.type() == mongo::String );
str = e.valuestr();
}
- char *s = copyString( str.c_str() );
- if ( string( "--port" ) == s )
+ if ( str == "--port" )
port_ = -2;
else if ( port_ == -2 )
- port_ = strtol( s, 0, 10 );
- argv_[ i ] = s;
+ port_ = strtol( str.c_str(), 0, 10 );
+ argv_.push_back(str);
}
- argv_[ args.nFields() ] = 0;
if ( program != "mongod" && program != "mongos" && program != "mongobridge" )
port_ = 0;
@@ -274,27 +287,12 @@ namespace mongo {
assert( pipe( pipeEnds ) != -1 );
fflush( 0 );
- pid_ = fork();
- assert( pid_ != -1 );
-
- if ( pid_ == 0 ) {
-
- assert( dup2( pipeEnds[ 1 ], STDOUT_FILENO ) != -1 );
- assert( dup2( pipeEnds[ 1 ], STDERR_FILENO ) != -1 );
- execvp( argv_[ 0 ], argv_ );
- massert( 10436 , "Unable to start program" , 0 );
- }
+ launch_process(pipeEnds[1]); //sets pid_
cout << "shell: started mongo program";
- int i = 0;
- while( argv_[ i ] )
- cout << " " << argv_[ i++ ];
+ for (unsigned i=0; i < argv_.size(); i++)
+ cout << " " << argv_[i];
cout << endl;
-
- i = 0;
- while( argv_[ i ] )
- free( argv_[ i++ ] );
- free( argv_ );
if ( port_ > 0 )
dbs.insert( make_pair( port_, make_pair( pid_, pipeEnds[ 1 ] ) ) );
@@ -332,30 +330,136 @@ namespace mongo {
strcpy( temp, last );
strcpy( buf, temp );
} else {
- assert( strlen( buf ) < 1023 );
+ 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<TCHAR> 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<char**>(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 ) {
- MongoProgramRunner r( a );
+ _nokillop = true;
+ ProgramRunner r( a );
r.start();
boost::thread t( r );
return BSON( string( "" ) << int( r.pid() ) );
}
BSONObj RunMongoProgram( const BSONObj &a ) {
- MongoProgramRunner r( a );
+ ProgramRunner r( a );
r.start();
boost::thread t( r );
- int temp;
- waitpid( r.pid() , &temp , 0 );
+ 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();
@@ -366,19 +470,73 @@ namespace mongo {
return undefined_;
}
- void killDb( int port, pid_t _pid, int signal ) {
+ 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;
+ return 0;
}
pid = dbs[ port ].first;
} else {
pid = _pid;
}
- assert( 0 == kill( pid, signal ) );
+ kill_wrapper( pid, signal, port );
int i = 0;
for( ; i < 65; ++i ) {
@@ -387,11 +545,9 @@ namespace mongo {
time_t_to_String(time(0), now);
now[ 20 ] = 0;
cout << now << " process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl;
- assert( 0 == kill( pid, SIGKILL ) );
+ kill_wrapper( pid, SIGKILL, port );
}
- int temp;
- int ret = waitpid( pid, &temp, WNOHANG );
- if ( ret == pid )
+ if(wait_for_pid(pid, false, &exitCode))
break;
sleepms( 1000 );
}
@@ -402,7 +558,7 @@ namespace mongo {
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 );
@@ -413,6 +569,8 @@ namespace mongo {
if ( i > 4 || signal == SIGKILL ) {
sleepms( 4000 ); // allow operating system to reclaim resources
}
+
+ return exitCode;
}
int getSignal( const BSONObj &a ) {
@@ -431,18 +589,18 @@ namespace mongo {
assert( a.nFields() == 1 || a.nFields() == 2 );
assert( a.firstElement().isNumber() );
int port = int( a.firstElement().number() );
- killDb( port, 0, getSignal( a ) );
+ int code = killDb( port, 0, getSignal( a ) );
cout << "shell: stopped mongo program on port " << port << endl;
- return undefined_;
+ 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() );
- killDb( 0, pid, getSignal( a ) );
+ int code = killDb( 0, pid, getSignal( a ) );
cout << "shell: stopped mongo program on pid " << pid << endl;
- return undefined_;
+ return BSON( "" << code );
}
void KillMongoProgramInstances() {
@@ -457,39 +615,23 @@ namespace mongo {
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() {
- try {
+ DESTRUCTOR_GUARD(
KillMongoProgramInstances();
- } catch ( ... ) {
- assert( false );
- }
+ ClearRawMongoProgramOutput( BSONObj() );
+ )
}
-#else
- MongoProgramScope::~MongoProgramScope() {}
- void KillMongoProgramInstances() {}
-#endif
-
- BSONObj jsmd5( const BSONObj &a ){
- uassert( 10261 , "js md5 needs a string" , a.firstElement().type() == String );
- const char * s = a.firstElement().valuestrsafe();
-
- md5digest d;
- md5_state_t st;
- md5_init(&st);
- md5_append( &st , (const md5_byte_t*)s , strlen( s ) );
- md5_finish(&st, d);
-
- return BSON( "" << digestToString( d ) );
- }
-
unsigned _randomSeed;
BSONObj JSSrand( const BSONObj &a ) {
uassert( 12518, "srand requires a single numeric argument",
a.nFields() == 1 && a.firstElement().isNumber() );
- _randomSeed = a.firstElement().numberLong(); // grab least significant digits
+ _randomSeed = (unsigned)a.firstElement().numberLong(); // grab least significant digits
return undefined_;
}
@@ -503,25 +645,40 @@ namespace mongo {
#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( "listFiles" , listFiles );
scope.injectNative( "sleep" , JSSleep );
scope.injectNative( "quit", Quit );
scope.injectNative( "getMemInfo" , JSGetMemInfo );
- scope.injectNative( "version" , JSVersion );
- scope.injectNative( "hex_md5" , jsmd5 );
scope.injectNative( "_srand" , JSSrand );
scope.injectNative( "_rand" , JSRand );
-#if !defined(_WIN32)
- scope.injectNative( "allocatePorts", AllocatePorts );
+ 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( "resetDbpath", ResetDbpath );
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
}
@@ -533,9 +690,24 @@ namespace mongo {
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.h b/shell/utils.h
index 7c98e2c..a2d420d 100644
--- a/shell/utils.h
+++ b/shell/utils.h
@@ -1,19 +1,37 @@
// utils.h
+/*
+ * 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.
+ */
+
#pragma once
#include "../scripting/engine.h"
namespace mongo {
-
+
namespace shellUtils {
extern std::string _dbConnect;
extern std::string _dbAuth;
+ extern map< const void*, string > _allMyUris;
+ extern bool _nokillop;
void RecordMyLocation( const char *_argv0 );
void installShellUtils( Scope& scope );
-
+
// Scoped management of mongo program instances. Simple implementation:
// destructor kills all mongod instances created by the shell.
struct MongoProgramScope {
@@ -23,5 +41,6 @@ namespace mongo {
void KillMongoProgramInstances();
void initScope( Scope &scope );
+ void onConnect( DBClientWithCommands &c );
}
}
diff --git a/shell/utils.js b/shell/utils.js
index 2d59b80..027ba0d 100644
--- a/shell/utils.js
+++ b/shell/utils.js
@@ -132,6 +132,17 @@ assert.gt = function( a , b , msg ){
doassert( a + " is not greater than " + b + " : " + msg );
}
+assert.close = function( a , b , msg , places ){
+ if (places === undefined) {
+ places = 4;
+ }
+ if (Math.round((a - b) * Math.pow(10, places)) === 0) {
+ return;
+ }
+ doassert( a + " is not equal to " + b + " within " + places +
+ " places, diff: " + (a-b) + " : " + msg );
+};
+
Object.extend = function( dst , src , deep ){
for ( var k in src ){
var v = src[k];
@@ -477,7 +488,8 @@ if ( typeof _threadInject != "undefined" ){
"jstests/extent.js",
"jstests/indexb.js",
"jstests/profile1.js",
- "jstests/mr3.js"] );
+ "jstests/mr3.js",
+ "jstests/apitest_db.js"] );
// some tests can't be run in parallel with each other
var serialTestsArr = [ "jstests/fsync.js",
@@ -576,10 +588,10 @@ if ( typeof _threadInject != "undefined" ){
}
tojson = function( x, indent , nolint ){
- if ( x == null )
+ if ( x === null )
return "null";
- if ( x == undefined )
+ if ( x === undefined )
return "undefined";
if (!indent)
@@ -905,3 +917,39 @@ Random.setRandomSeed = function( s ) {
Random.genExp = function( mean ) {
return -Math.log( Random.rand() ) * mean;
}
+
+killWithUris = function( uris ) {
+ var inprog = db.currentOp().inprog;
+ for( var u in uris ) {
+ for ( var i in inprog ) {
+ if ( uris[ u ] == inprog[ i ].client ) {
+ db.killOp( inprog[ i ].opid );
+ }
+ }
+ }
+}
+
+Geo = {};
+Geo.distance = function( a , b ){
+ var ax = null;
+ var ay = null;
+ var bx = null;
+ var by = null;
+
+ for ( var key in a ){
+ if ( ax == null )
+ ax = a[key];
+ else if ( ay == null )
+ ay = a[key];
+ }
+
+ for ( var key in b ){
+ if ( bx == null )
+ bx = b[key];
+ else if ( by == null )
+ by = b[key];
+ }
+
+ return Math.sqrt( Math.pow( by - ay , 2 ) +
+ Math.pow( bx - ax , 2 ) );
+}