From f7288ef41020bcafdb7b1d7ad4da28e8421ecccf Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Mon, 5 Jul 2010 00:54:17 -0400 Subject: [PATCH] fix v8 cursor closing --- jstests/sharding/auto2.js | 4 +++- scripting/engine_v8.cpp | 8 +++++-- scripting/v8_db.cpp | 47 +++++++++++++++++++++++++-------------- scripting/v8_utils.cpp | 7 ++++++ scripting/v8_utils.h | 1 + shell/utils.js | 1 + 6 files changed, 48 insertions(+), 20 deletions(-) diff --git a/jstests/sharding/auto2.js b/jstests/sharding/auto2.js index 3da7fb04abf..bb2ffb9c213 100644 --- a/jstests/sharding/auto2.js +++ b/jstests/sharding/auto2.js @@ -99,7 +99,9 @@ for ( i=0; i<100; i++ ){ gc(); } -gc(); gc(); +for ( i=0; i<100; i++ ){ + gc(); +} assert.eq( 0 , db.runCommand( "cursorInfo" ).total , "cursor2" ); print( "checkpoint E") diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp index d62726834de..08826b1964c 100644 --- a/scripting/engine_v8.cpp +++ b/scripting/engine_v8.cpp @@ -57,9 +57,12 @@ namespace mongo { _global->Set(v8::String::New("load"), v8::FunctionTemplate::New(loadCallback, v8::External::New(this))->GetFunction() ); - - _wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate()->GetFunction() ); + _wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate()->GetFunction() ); + + _global->Set(v8::String::New("gc"), v8::FunctionTemplate::New(GCV8)->GetFunction() ); + + installDBTypes( _global ); } @@ -383,6 +386,7 @@ namespace mongo { } void V8Scope::gc() { + cout << "in gc" << endl; Locker l; while( V8::IdleNotification() ); } diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp index 57dbe32c2a0..361d5ea8a80 100644 --- a/scripting/v8_db.cpp +++ b/scripting/v8_db.cpp @@ -29,12 +29,11 @@ using namespace v8; namespace mongo { -#define CONN_STRING (v8::String::New( "_conn" )) - #define DDD(x) v8::Handle getMongoFunctionTemplate( bool local ){ v8::Local mongo = FunctionTemplate::New( local ? mongoConsLocal : mongoConsExternal ); + mongo->InstanceTemplate()->SetInternalFieldCount( 1 ); v8::Local proto = mongo->PrototypeTemplate(); @@ -44,9 +43,12 @@ namespace mongo { proto->Set( v8::String::New( "update" ) , FunctionTemplate::New( mongoUpdate ) ); Local ic = FunctionTemplate::New( internalCursorCons ); + ic->InstanceTemplate()->SetInternalFieldCount( 1 ); ic->PrototypeTemplate()->Set( v8::String::New("next") , FunctionTemplate::New( internalCursorNext ) ); ic->PrototypeTemplate()->Set( v8::String::New("hasNext") , FunctionTemplate::New( internalCursorHasNext ) ); proto->Set( v8::String::New( "internalCursor" ) , ic ); + + return mongo; } @@ -132,9 +134,10 @@ namespace mongo { global->Get( v8::String::New( "Object" ) )->ToObject()->Set( v8::String::New("bsonsize") , FunctionTemplate::New( bsonsize )->GetFunction() ); } - void destroyConnection( Persistent object, void* parameter){ - // TODO - cout << "warning: destroyConnection not implemented" << endl; + void destroyConnection( Persistent self, void* parameter){ + delete static_cast(parameter); + self.Dispose(); + self.Clear(); } Handle mongoConsExternal(const Arguments& args){ @@ -183,13 +186,13 @@ namespace mongo { else { return v8::ThrowException( v8::String::New( "too many commas" ) ); } - - Persistent self = Persistent::New( args.This() ); + + Persistent self = Persistent::New( args.Holder() ); self.MakeWeak( conn , destroyConnection ); ScriptEngine::runConnectCallback( *conn ); - // NOTE I don't believe the conn object will ever be freed. - args.This()->Set( CONN_STRING , External::New( conn ) ); + + args.This()->SetInternalField( 0 , External::New( conn ) ); args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); args.This()->Set( v8::String::New( "host" ) , v8::String::New( host ) ); @@ -207,7 +210,7 @@ namespace mongo { self.MakeWeak( conn , destroyConnection ); // NOTE I don't believe the conn object will ever be freed. - args.This()->Set( CONN_STRING , External::New( conn ) ); + args.This()->SetInternalField( 0 , External::New( conn ) ); args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); args.This()->Set( v8::String::New( "host" ) , v8::String::New( "EMBEDDED" ) ); @@ -224,7 +227,7 @@ namespace mongo { #endif DBClientBase * getConnection( const Arguments& args ){ - Local c = External::Cast( *(args.This()->Get( CONN_STRING )) ); + Local c = External::Cast( *(args.This()->GetInternalField( 0 )) ); DBClientBase * conn = (DBClientBase*)(c->Value()); assert( conn ); return conn; @@ -232,6 +235,12 @@ namespace mongo { // ---- real methods + void destroyCursor( Persistent self, void* parameter){ + delete static_cast(parameter); + self.Dispose(); + self.Clear(); + } + /** 0 - namespace 1 - query @@ -240,6 +249,8 @@ namespace mongo { 4 - skip */ Handle mongoFind(const Arguments& args){ + HandleScope handle_scope; + jsassert( args.Length() == 6 , "find needs 6 args" ); jsassert( args[1]->IsObject() , "needs to be an object" ); DBClientBase * conn = getConnection( args ); @@ -269,11 +280,12 @@ namespace mongo { } v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) ); assert( cons ); - Local c = cons->NewInstance(); - - // NOTE I don't believe the cursor object will ever be freed. - c->Set( v8::String::New( "cursor" ) , External::New( cursor.release() ) ); - return c; + + Persistent c = Persistent::New( cons->NewInstance() ); + c.MakeWeak( cursor.get() , destroyCursor ); + + c->SetInternalField( 0 , External::New( cursor.release() ) ); + return handle_scope.Close(c); } catch ( ... ){ return v8::ThrowException( v8::String::New( "socket error on query" ) ); @@ -363,7 +375,8 @@ namespace mongo { // --- cursor --- mongo::DBClientCursor * getCursor( const Arguments& args ){ - Local c = External::Cast( *(args.This()->Get( v8::String::New( "cursor" ) ) ) ); + Local c = External::Cast( *(args.This()->GetInternalField( 0 ) ) ); + mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value()); return cursor; } diff --git a/scripting/v8_utils.cpp b/scripting/v8_utils.cpp index 5e56245ba7d..5a07a802dc1 100644 --- a/scripting/v8_utils.cpp +++ b/scripting/v8_utils.cpp @@ -302,4 +302,11 @@ namespace mongo { global->Set( v8::String::New( "_scopedThreadInject" ), FunctionTemplate::New( ScopedThreadInject )->GetFunction() ); } + Handle GCV8(const Arguments& args) { + Locker l; + while( V8::IdleNotification() ); + return v8::Undefined(); + } + + } diff --git a/scripting/v8_utils.h b/scripting/v8_utils.h index 82184556864..bc4b5244184 100644 --- a/scripting/v8_utils.h +++ b/scripting/v8_utils.h @@ -29,6 +29,7 @@ namespace mongo { v8::Handle Print(const v8::Arguments& args); v8::Handle Version(const v8::Arguments& args); + v8::Handle GCV8(const v8::Arguments& args); void ReportException(v8::TryCatch* handler); diff --git a/shell/utils.js b/shell/utils.js index 431454ce15b..cb5828423ac 100644 --- a/shell/utils.js +++ b/shell/utils.js @@ -1001,6 +1001,7 @@ Map.prototype.values = function(){ if ( typeof( gc ) == "undefined" ){ gc = function(){ + print( "warning: using noop gc()" ); } }