summaryrefslogtreecommitdiff
path: root/scripting
diff options
context:
space:
mode:
authoragirbal <antoine@10gen.com>2011-05-10 15:23:45 -0700
committeragirbal <antoine@10gen.com>2011-05-10 15:30:02 -0700
commit13e71279c964fc3f84e682901f37152935557f70 (patch)
tree4882c553e0d1769f82dd6260b0bcc54fe7e6af33 /scripting
parent8d13203c40150d93b5747adf4430a8b6edd21ac9 (diff)
downloadmongo-13e71279c964fc3f84e682901f37152935557f70.tar.gz
SERVER-2579: added readonly object for lazy v8 objects, which makes them much faster to access
SERVER-2976: further implementation of jsMode for M/R. Can be turned on using temp flag jsMode:true
Diffstat (limited to 'scripting')
-rw-r--r--scripting/engine_v8.cpp135
-rw-r--r--scripting/engine_v8.h63
2 files changed, 136 insertions, 62 deletions
diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp
index b0286dd3fd3..548401bab69 100644
--- a/scripting/engine_v8.cpp
+++ b/scripting/engine_v8.cpp
@@ -33,10 +33,10 @@ namespace mongo {
*/
static BSONObj* unwrapBSONObj(const Handle<v8::Object>& obj) {
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
- if (field.IsEmpty() || !field->IsExternal())
- return 0;
+// if (field.IsEmpty() || !field->IsExternal())
+// return 0;
void* ptr = field->Value();
- return static_cast<BSONObj*>(ptr);
+ return (BSONObj*)ptr;
}
static void weakRefCallback(v8::Persistent<v8::Value> p, void* scope) {
@@ -62,16 +62,28 @@ namespace mongo {
string key = toSTLString(name);
BSONObj *obj = unwrapBSONObj(info.Holder());
- if (!obj || !obj->hasElement(key.c_str()))
- return Handle<Value>();
BSONElement elmt = obj->getField(key.c_str());
+ if (elmt.eoo())
+ return Handle<Value>();
Local< External > scp = External::Cast( *info.Data() );
V8Scope* scope = (V8Scope*)(scp->Value());
- val = scope->mongoToV8Element(elmt);
+ val = scope->mongoToV8Element(elmt, false);
info.This()->ForceSet(name, val);
return val;
}
+ static Handle<v8::Value> namedGetRO(Local<v8::String> name, const v8::AccessorInfo &info) {
+ string key = toSTLString(name);
+ BSONObj *obj = unwrapBSONObj(info.Holder());
+ BSONElement elmt = obj->getField(key.c_str());
+ if (elmt.eoo())
+ return Handle<Value>();
+ Local< External > scp = External::Cast( *info.Data() );
+ V8Scope* scope = (V8Scope*)(scp->Value());
+ Handle<v8::Value> val = scope->mongoToV8Element(elmt, true);
+ return val;
+ }
+
// static Handle<v8::Value> namedSet(Local<v8::String> name, Local<v8::Value> value_obj, const v8::AccessorInfo& info) {
// return Handle<Value>();
// }
@@ -116,10 +128,33 @@ namespace mongo {
// return val;
// }
BSONObj *obj = unwrapBSONObj(info.Holder());
- if (!obj || !obj->hasElement(key.c_str()))
- return Handle<Value>();
BSONElement elmt = obj->getField(key);
- Handle<Value> val = scope->mongoToV8Element(elmt);
+ if (elmt.eoo())
+ return Handle<Value>();
+ Handle<Value> val = scope->mongoToV8Element(elmt, false);
+// info.This()->ForceSet(name, val);
+ return val;
+ }
+
+ static Handle<v8::Value> indexedGetRO(uint32_t index, const v8::AccessorInfo &info) {
+ StringBuilder ss;
+ ss << index;
+ string key = ss.str();
+ Local< External > scp = External::Cast( *info.Data() );
+ V8Scope* scope = (V8Scope*)(scp->Value());
+ // cannot get v8 to properly cache the indexed val in the js object
+// Handle<v8::String> name = scope->getV8Str(key);
+// // v8 API really confusing here, must check existence on index, but then fetch with name
+// if (info.This()->HasRealIndexedProperty(index)) {
+// Handle<v8::Value> val = info.This()->GetRealNamedProperty(name);
+// if (!val.IsEmpty() && !val->IsNull())
+// return val;
+// }
+ BSONObj *obj = unwrapBSONObj(info.Holder());
+ BSONElement elmt = obj->getField(key);
+ if (elmt.eoo())
+ return Handle<Value>();
+ Handle<Value> val = scope->mongoToV8Element(elmt, true);
// info.This()->ForceSet(name, val);
return val;
}
@@ -192,6 +227,12 @@ namespace mongo {
lzObjectTemplate->SetNamedPropertyHandler(namedGet, 0, 0, 0, 0, v8::External::New(this));
lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0, v8::External::New(this));
+ roObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+ roObjectTemplate->SetInternalFieldCount( 1 );
+ roObjectTemplate->SetNamedPropertyHandler(0);
+ roObjectTemplate->SetNamedPropertyHandler(namedGetRO, 0, 0, 0, 0, v8::External::New(this));
+ roObjectTemplate->SetIndexedPropertyHandler(indexedGetRO, 0, 0, 0, 0, v8::External::New(this));
+
// initialize lazy array template
// unfortunately it is not possible to create true v8 array from a template
// this means we use an object template and copy methods over
@@ -200,6 +241,9 @@ namespace mongo {
lzArrayTemplate->SetInternalFieldCount( 1 );
lzArrayTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0, v8::External::New(this));
+ internalFieldObjects = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+ internalFieldObjects->SetInternalFieldCount( 1 );
+
V8STR_CONN = getV8Str( "_conn" );
V8STR_ID = getV8Str( "_id" );
V8STR_LENGTH = getV8Str( "length" );
@@ -247,6 +291,8 @@ namespace mongo {
}
lzObjectTemplate.Dispose();
lzArrayTemplate.Dispose();
+ roObjectTemplate.Dispose();
+ internalFieldObjects.Dispose();
}
/**
@@ -370,7 +416,7 @@ namespace mongo {
V8_SIMPLE_HEADER
// Set() accepts a ReadOnly parameter, but this just prevents the field itself
// from being overwritten and doesn't protect the object stored in 'field'.
- _global->Set( getV8Str( field ) , mongoToLZV8( obj, false, readOnly) );
+ _global->Set( getV8Str( field ) , mongoToV8( obj, false, readOnly) );
}
int V8Scope::type( const char *field ) {
@@ -544,7 +590,7 @@ namespace mongo {
BSONObjIterator it( *argsObject );
for ( int i=0; i<nargs; i++ ) {
BSONElement next = it.next();
- args[i] = mongoToV8Element( next );
+ args[i] = mongoToV8Element( next, true );
}
setObject( "args", *argsObject, true ); // for backwards compatibility
}
@@ -560,7 +606,7 @@ namespace mongo {
}
Handle<v8::Object> v8recv;
if (recv != 0)
- v8recv = mongoToLZV8(*recv, false);
+ v8recv = mongoToLZV8(*recv, false, true);
else
v8recv = _emptyObj;
@@ -797,9 +843,6 @@ namespace mongo {
}
Local< v8::ObjectTemplate > readOnlyObjects;
- // Hoping template construction is fast...
- Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
- internalFieldObjects->SetInternalFieldCount( 1 );
if ( !o.IsEmpty() ) {
readOnly = false;
@@ -1002,42 +1045,47 @@ namespace mongo {
Handle<v8::Object> V8Scope::mongoToLZV8( const BSONObj& m , bool array, bool readOnly ) {
Local<v8::Object> o;
- if (array) {
- o = lzArrayTemplate->NewInstance();
- o->SetPrototype(v8::Array::New(1)->GetPrototype());
- o->Set(V8STR_LENGTH, v8::Integer::New(m.nFields()), DontEnum);
-// o->Set(ARRAY_STRING, v8::Boolean::New(true), DontEnum);
+ if (readOnly) {
+ o = roObjectTemplate->NewInstance();
} else {
- o = lzObjectTemplate->NewInstance();
-
- static string ref = "$ref";
- if ( ref == m.firstElement().fieldName() ) {
- const BSONElement& id = m["$id"];
- if (!id.eoo()) {
- v8::Function* dbRef = getNamedCons( "DBRef" );
- o->SetPrototype(dbRef->NewInstance()->GetPrototype());
- }
+ if (array) {
+ o = lzArrayTemplate->NewInstance();
+ o->SetPrototype(v8::Array::New(1)->GetPrototype());
+ o->Set(V8STR_LENGTH, v8::Integer::New(m.nFields()), DontEnum);
+ // o->Set(ARRAY_STRING, v8::Boolean::New(true), DontEnum);
+ } else {
+ o = lzObjectTemplate->NewInstance();
+
+ static string ref = "$ref";
+ if ( ref == m.firstElement().fieldName() ) {
+ const BSONElement& id = m["$id"];
+ if (!id.eoo()) {
+ v8::Function* dbRef = getNamedCons( "DBRef" );
+ o->SetPrototype(dbRef->NewInstance()->GetPrototype());
+ }
+ }
+ }
+
+ // need to set all keys with dummy values, so that order of keys is correct during enumeration
+ // otherwise v8 will list any newly set property in JS before the ones of underlying BSON obj.
+ for (BSONObjIterator it(m); it.more();) {
+ const BSONElement& f = it.next();
+ o->ForceSet(getV8Str(f.fieldName()), v8::Undefined());
}
}
BSONObj* own = new BSONObj(m.getOwned());
// BSONObj* own = new BSONObj(m);
o->SetInternalField(0, v8::External::New(own));
- // need to set all keys with dummy values, so that order of keys is correct during enumeration
- // otherwise v8 will list any newly set property in JS before the ones of underlying BSON obj.
- for (BSONObjIterator it(m); it.more();) {
- const BSONElement& f = it.next();
- o->ForceSet(getV8Str(f.fieldName()), v8::Undefined());
- }
Persistent<v8::Object> p = Persistent<v8::Object>::New(o);
p.MakeWeak(this, weakRefCallback);
return p;
}
- Handle<v8::Value> V8Scope::mongoToV8Element( const BSONElement &f ) {
- Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
- internalFieldObjects->SetInternalFieldCount( 1 );
+ Handle<v8::Value> V8Scope::mongoToV8Element( const BSONElement &f, bool readOnly ) {
+// Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
+// internalFieldObjects->SetInternalFieldCount( 1 );
switch ( f.type() ) {
@@ -1050,7 +1098,9 @@ namespace mongo {
return newFunction( f.codeWScopeCode() );
case mongo::String:
+// return v8::String::NewExternal( new ExternalString( f.valuestr() ));
return v8::String::New( f.valuestr() );
+// return getV8Str( f.valuestr() );
case mongo::jstOID:
return newId( f.__oid() );
@@ -1064,9 +1114,9 @@ namespace mongo {
// - the lazy array is not a true v8 array and requires some v8 src change for all methods to work
// - it made several tests about 1.5x slower
// - most times when an array is accessed, all its values will be used
- return mongoToV8( f.embeddedObject() , true );
+ return mongoToV8( f.embeddedObject() , true, readOnly );
case mongo::Object:
- return mongoToLZV8( f.embeddedObject() , false);
+ return mongoToLZV8( f.embeddedObject() , false, readOnly);
case mongo::Date:
return v8::Date::New( f.date() );
@@ -1173,6 +1223,9 @@ namespace mongo {
void V8Scope::v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value , int depth ) {
if ( value->IsString() ) {
+// Handle<v8::String> str = Handle<v8::String>::Cast(value);
+// ExternalString* es = (ExternalString*) (str->GetExternalAsciiStringResource());
+// b.append( sname , es->data() );
b.append( sname , toSTLString( value ).c_str() );
return;
}
@@ -1366,7 +1419,7 @@ namespace mongo {
/**
* Gets a V8 strings from the scope's cache, creating one if needed
*/
- v8::Persistent<v8::String> V8Scope::getV8Str(string str) {
+ v8::Handle<v8::String> V8Scope::getV8Str(string str) {
Persistent<v8::String> ptr = _strCache[str];
if (ptr.IsEmpty()) {
ptr = Persistent<v8::String>::New(v8::String::New(str.c_str()));
diff --git a/scripting/engine_v8.h b/scripting/engine_v8.h
index 4b17e0fc796..eb3b16c248e 100644
--- a/scripting/engine_v8.h
+++ b/scripting/engine_v8.h
@@ -113,33 +113,35 @@ namespace mongo {
void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name ,
const string sname , v8::Handle<v8::Value> value , int depth = 0 );
- v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f );
+ v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false );
virtual void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
v8::Function * getNamedCons( const char * name );
v8::Function * getObjectIdCons();
Local< v8::Value > newId( const OID &id );
- v8::Persistent<v8::String> getV8Str(string str);
-
- Persistent<v8::String> V8STR_CONN;
- Persistent<v8::String> V8STR_ID;
- Persistent<v8::String> V8STR_LENGTH;
- Persistent<v8::String> V8STR_ISOBJECTID;
- Persistent<v8::String> V8STR_NATIVE_FUNC;
- Persistent<v8::String> V8STR_NATIVE_DATA;
- Persistent<v8::String> V8STR_V8_FUNC;
- Persistent<v8::String> V8STR_RETURN;
- Persistent<v8::String> V8STR_ARGS;
- Persistent<v8::String> V8STR_T;
- Persistent<v8::String> V8STR_I;
- Persistent<v8::String> V8STR_EMPTY;
- Persistent<v8::String> V8STR_MINKEY;
- Persistent<v8::String> V8STR_MAXKEY;
- Persistent<v8::String> V8STR_NUMBERLONG;
- Persistent<v8::String> V8STR_DBPTR;
- Persistent<v8::String> V8STR_BINDATA;
- Persistent<v8::String> V8STR_WRAPPER;
+ v8::Handle<v8::String> getV8Str(string str);
+// inline v8::Handle<v8::String> getV8Str(string str) { return v8::String::New(str.c_str()); }
+ inline v8::Handle<v8::String> getLocalV8Str(string str) { return v8::String::New(str.c_str()); }
+
+ Handle<v8::String> V8STR_CONN;
+ Handle<v8::String> V8STR_ID;
+ Handle<v8::String> V8STR_LENGTH;
+ Handle<v8::String> V8STR_ISOBJECTID;
+ Handle<v8::String> V8STR_NATIVE_FUNC;
+ Handle<v8::String> V8STR_NATIVE_DATA;
+ Handle<v8::String> V8STR_V8_FUNC;
+ Handle<v8::String> V8STR_RETURN;
+ Handle<v8::String> V8STR_ARGS;
+ Handle<v8::String> V8STR_T;
+ Handle<v8::String> V8STR_I;
+ Handle<v8::String> V8STR_EMPTY;
+ Handle<v8::String> V8STR_MINKEY;
+ Handle<v8::String> V8STR_MAXKEY;
+ Handle<v8::String> V8STR_NUMBERLONG;
+ Handle<v8::String> V8STR_DBPTR;
+ Handle<v8::String> V8STR_BINDATA;
+ Handle<v8::String> V8STR_WRAPPER;
private:
void _startCall();
@@ -169,7 +171,9 @@ namespace mongo {
std::map <string, v8::Persistent <v8::String> > _strCache;
Persistent<v8::ObjectTemplate> lzObjectTemplate;
+ Persistent<v8::ObjectTemplate> roObjectTemplate;
Persistent<v8::ObjectTemplate> lzArrayTemplate;
+ Persistent<v8::ObjectTemplate> internalFieldObjects;
};
class V8ScriptEngine : public ScriptEngine {
@@ -196,6 +200,23 @@ namespace mongo {
friend class V8Scope;
};
+ class ExternalString : public v8::String::ExternalAsciiStringResource {
+ public:
+ ExternalString(std::string str) : _data(str) {
+ }
+
+ ~ExternalString() {
+ }
+
+ const char* data () const { return _data.c_str(); }
+ size_t length () const { return _data.length(); }
+ private:
+// string _str;
+// const char* _data;
+ std::string _data;
+// size_t _len;
+ };
+
extern ScriptEngine * globalScriptEngine;
extern map< unsigned, int > __interruptSpecToThreadId;