diff options
-rw-r--r-- | db/dbeval.cpp | 2 | ||||
-rw-r--r-- | jstests/quota/quota1.js | 61 | ||||
-rw-r--r-- | mongo.xcodeproj/project.pbxproj | 10 | ||||
-rw-r--r-- | scripting/engine.cpp | 8 | ||||
-rw-r--r-- | scripting/engine.h | 8 | ||||
-rw-r--r-- | scripting/engine_spidermonkey.cpp | 55 |
6 files changed, 98 insertions, 46 deletions
diff --git a/db/dbeval.cpp b/db/dbeval.cpp index 8b69fbafceb..b5a08d7defd 100644 --- a/db/dbeval.cpp +++ b/db/dbeval.cpp @@ -86,7 +86,7 @@ namespace mongo { int res; { Timer t; - res = s->invoke(f,args); + res = s->invoke(f,args, 10 * 60 * 1000); int m = t.millis(); if ( m > 100 ) { out() << "dbeval slow, time: " << dec << m << "ms " << ns << endl; diff --git a/jstests/quota/quota1.js b/jstests/quota/quota1.js index 3bae50ae23e..d8f4c422e62 100644 --- a/jstests/quota/quota1.js +++ b/jstests/quota/quota1.js @@ -9,7 +9,6 @@ assert.throws( var a = 5; while ( true ){ a += 2; - scope.toString(); } } ) @@ -17,33 +16,33 @@ assert.throws( ); print( "done quota1.a" ); -print( "starting quota1.b" ); -assert.throws( - function(z){ - db.eval( - function(){ - db.quota1b.save( { a : 1 } ); - var a = 5; - assert( sleep( 150000 ) ); - } - ) - } -); -print( "done quota1.b" ); - -print( "starting quota1.c" ); -assert.throws( - function(z){ - db.eval( - function(){ - db.quota1c.save( { a : 1 } ); - var a = 1; - while ( true ){ - a += 1; - assert( sleep( 1000 ) ); - } - } - ) - } -); -print( "done quota1.c" ); +//print( "starting quota1.b" ); +//assert.throws( +// function(z){ +// db.eval( +// function(){ +// db.quota1b.save( { a : 1 } ); +// var a = 5; +// assert( sleep( 150000 ) ); +// } +// ) +// } +//); +//print( "done quota1.b" ); +// +//print( "starting quota1.c" ); +//assert.throws( +// function(z){ +// db.eval( +// function(){ +// db.quota1c.save( { a : 1 } ); +// var a = 1; +// while ( true ){ +// a += 1; +// assert( sleep( 1000 ) ); +// } +// } +// ) +// } +//); +//print( "done quota1.c" ); diff --git a/mongo.xcodeproj/project.pbxproj b/mongo.xcodeproj/project.pbxproj index d0464176956..3adc984980e 100644 --- a/mongo.xcodeproj/project.pbxproj +++ b/mongo.xcodeproj/project.pbxproj @@ -53,6 +53,7 @@ 933A4D1D0F55A68600145C4B /* whereExample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = whereExample.cpp; sourceTree = "<group>"; }; 933E22110F4327B2000209E3 /* perftest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = perftest.cpp; sourceTree = "<group>"; }; 933E22120F4327B2000209E3 /* perftest.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = perftest.o; sourceTree = "<group>"; }; + 933EF9C70FC3434000C4B294 /* quota1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = quota1.js; sourceTree = "<group>"; }; 9342232B0EF16D4F00608550 /* connpool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = connpool.cpp; sourceTree = "<group>"; }; 9342232C0EF16D4F00608550 /* connpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = connpool.h; sourceTree = "<group>"; }; 9342232D0EF16D4F00608550 /* dbclient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dbclient.cpp; sourceTree = "<group>"; }; @@ -369,6 +370,14 @@ path = perf; sourceTree = "<group>"; }; + 933EF9C60FC3434000C4B294 /* quota */ = { + isa = PBXGroup; + children = ( + 933EF9C70FC3434000C4B294 /* quota1.js */, + ); + path = quota; + sourceTree = "<group>"; + }; 9342232A0EF16D4F00608550 /* client */ = { isa = PBXGroup; children = ( @@ -579,6 +588,7 @@ 93A8D1D10F37544800C92B85 /* jstests */ = { isa = PBXGroup; children = ( + 933EF9C60FC3434000C4B294 /* quota */, 93DB95170FC1D3D50047F950 /* capped4.js */, 93DB94A40FC1BFA30047F950 /* capped3.js */, 93197CDD0FBDEDD0001FE537 /* shellspawn.js */, diff --git a/scripting/engine.cpp b/scripting/engine.cpp index 58322f45b43..b355e65954a 100644 --- a/scripting/engine.cpp +++ b/scripting/engine.cpp @@ -18,13 +18,13 @@ namespace mongo { ScriptEngine::~ScriptEngine(){ } - int Scope::invoke( const char* code , const BSONObj& args ){ + int Scope::invoke( const char* code , const BSONObj& args, int timeoutMs ){ ScriptingFunction func = createFunction( code ); uassert( "compile failed" , func ); - return invoke( func , args ); + return invoke( func , args, timeoutMs ); } - bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError ){ + bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs ){ path p( filename ); if ( is_directory( p ) ){ @@ -42,7 +42,7 @@ namespace mongo { f.read( 0 , data , f.len() ); - return exec( data , filename , printResult , reportError , assertOnError ); + return exec( data , filename , printResult , reportError , assertOnError, timeoutMs ); } diff --git a/scripting/engine.h b/scripting/engine.h index 497667e0db8..ff3ee10ece7 100644 --- a/scripting/engine.h +++ b/scripting/engine.h @@ -45,13 +45,13 @@ namespace mongo { /** * @return 0 on success */ - virtual int invoke( ScriptingFunction func , const BSONObj& args ) = 0; + virtual int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 ) = 0; virtual string getError() = 0; - int invoke( const char* code , const BSONObj& args ); + int invoke( const char* code , const BSONObj& args, int timeoutMs = 0 ); - virtual bool exec( const string& code , const string& name , bool printResult , bool reportError , bool assertOnError ) = 0; - virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError ); + virtual bool exec( const string& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0; + virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ); virtual void injectNative( const char *field, NativeFunction func ) = 0; }; diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp index 4206099b2f5..3ef2fd9ca30 100644 --- a/scripting/engine_spidermonkey.cpp +++ b/scripting/engine_spidermonkey.cpp @@ -741,18 +741,57 @@ namespace mongo { return (ScriptingFunction)_convertor->compileFunction( code ); } + struct TimeoutSpec { + boost::posix_time::ptime start; + boost::posix_time::time_duration timeout; + int count; + }; + + static JSBool checkTimeout( JSContext *cx, JSScript *script ) { + TimeoutSpec &spec = *(TimeoutSpec *)( JS_GetContextPrivate( cx ) ); + if ( ++spec.count % 1000 != 0 ) + return JS_TRUE; + boost::posix_time::time_duration elapsed = ( boost::posix_time::microsec_clock::local_time() - spec.start ); + if ( elapsed < spec.timeout ) { + return JS_TRUE; + } + JS_ReportError( cx, "Timeout exceeded" ); + return JS_FALSE; + } + + void installCheckTimeout( int timeoutMs ) { + if ( timeoutMs > 0 ) { + TimeoutSpec *spec = new TimeoutSpec; + spec->timeout = boost::posix_time::millisec( timeoutMs ); + spec->start = boost::posix_time::microsec_clock::local_time(); + spec->count = 0; + JS_SetContextPrivate( _context, (void*)spec ); + JS_SetBranchCallback( _context, checkTimeout ); + } + } + + void uninstallCheckTimeout( int timeoutMs ) { + if ( timeoutMs > 0 ) { + JS_SetBranchCallback( _context, 0 ); + delete (TimeoutSpec *)JS_GetContextPrivate( _context ); + JS_SetContextPrivate( _context, 0 ); + } + } + void precall(){ _error = ""; currentScope.reset( this ); } - bool exec( const string& code , const string& name = "(anon)" , bool printResult = false , bool reportError = true , bool assertOnError = true ){ + bool exec( const string& code , const string& name = "(anon)" , bool printResult = false , bool reportError = true , bool assertOnError = true, int timeoutMs = 0 ){ precall(); jsval ret = JSVAL_VOID; + installCheckTimeout( timeoutMs ); JSBool worked = JS_EvaluateScript( _context , _global , code.c_str() , strlen( code.c_str() ) , name.c_str() , 0 , &ret ); - + uninstallCheckTimeout( timeoutMs ); + if ( assertOnError ) uassert( name + " exec failed" , worked ); @@ -767,7 +806,7 @@ namespace mongo { return worked; } - int invoke( JSFunction * func , const BSONObj& args ){ + int invoke( JSFunction * func , const BSONObj& args, int timeoutMs ){ precall(); jsval rval; @@ -781,7 +820,11 @@ namespace mongo { setObject( "args" , args , true ); // this is for backwards compatability - if ( ! JS_CallFunction( _context , _this , func , nargs , smargs , &rval ) ){ + installCheckTimeout( timeoutMs ); + JSBool ret = JS_CallFunction( _context , _this , func , nargs , smargs , &rval ); + uninstallCheckTimeout( timeoutMs ); + + if ( !ret ) { return -3; } @@ -789,8 +832,8 @@ namespace mongo { return 0; } - int invoke( ScriptingFunction funcAddr , const BSONObj& args ){ - return invoke( (JSFunction*)funcAddr , args ); + int invoke( ScriptingFunction funcAddr , const BSONObj& args, int timeoutMs = 0 ){ + return invoke( (JSFunction*)funcAddr , args , timeoutMs ); } void gotError( string s ){ |