summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDwight <dmerriman@gmail.com>2008-03-29 23:30:44 -0400
committerDwight <dmerriman@gmail.com>2008-03-29 23:30:44 -0400
commit93b8ffe1830891f093dd466d55625043e1ad2abb (patch)
tree0194df00b568bffd84c13738e1e691bf1cde4b16
parenta34ad50532c0dcf0c8de0f8f02592692dd0337fa (diff)
downloadmongo-93b8ffe1830891f093dd466d55625043e1ad2abb.tar.gz
$where optimization
-rw-r--r--db/db.cpp7
-rw-r--r--db/db.vcproj4
-rw-r--r--db/javajs.cpp2
-rw-r--r--db/jsobj.cpp93
-rw-r--r--db/jsobj.h5
-rw-r--r--db/minilex.h97
6 files changed, 196 insertions, 12 deletions
diff --git a/db/db.cpp b/db/db.cpp
index cefbff22e4f..d2d73d9f67a 100644
--- a/db/db.cpp
+++ b/db/db.cpp
@@ -273,7 +273,7 @@ public:
};
void listen(int port) {
- cout << "db version: 102 mar2008 where" << endl;
+ cout << "db version: 103 mar2008 minilex" << endl;
pdfileInit();
testTheDb();
cout << curTimeMillis() % 10000 << " waiting for connections...\n" << endl;
@@ -552,9 +552,6 @@ void msg(const char *m, int extras = 0) {
int main(int argc, char* argv[], char *envp[] )
{
- JavaJS = new JavaJSImpl();
- javajstest();
-
srand(curTimeMillis());
if( argc >= 2 ) {
@@ -583,6 +580,8 @@ int main(int argc, char* argv[], char *envp[] )
return 0;
}
if( strcmp(argv[1], "run") == 0 ) {
+ JavaJS = new JavaJSImpl();
+ javajstest();
listen(port);
goingAway = true;
return 0;
diff --git a/db/db.vcproj b/db/db.vcproj
index 9752e6544f9..f375ef80324 100644
--- a/db/db.vcproj
+++ b/db/db.vcproj
@@ -281,6 +281,10 @@
>
</File>
<File
+ RelativePath=".\minilex.h"
+ >
+ </File>
+ <File
RelativePath="..\util\mmap.h"
>
</File>
diff --git a/db/javajs.cpp b/db/javajs.cpp
index ec5e533a2c6..e7a6ce41fa7 100644
--- a/db/javajs.cpp
+++ b/db/javajs.cpp
@@ -44,7 +44,7 @@ using namespace std;
longer needed and can be removed.
*/
extern "C" void tss_cleanup_implemented(void) {
- cout << "tss_cleanup_implemented called" << endl;
+ //cout << "tss_cleanup_implemented called" << endl;
}
#endif
diff --git a/db/jsobj.cpp b/db/jsobj.cpp
index ded7aa5c9dd..b8ad2b7b266 100644
--- a/db/jsobj.cpp
+++ b/db/jsobj.cpp
@@ -5,13 +5,88 @@
#include "../util/goodies.h"
#include "javajs.h"
+#if defined(_WIN32)
+
+#include <hash_map>
+using namespace stdext;
+
+typedef const char * MyStr;
+struct less_str {
+ bool operator()(const MyStr & x, const MyStr & y) const {
+ if ( strcmp(x, y) > 0)
+ return true;
+
+ return false;
+ }
+};
+
+typedef hash_map<const char*, int, hash_compare<const char *, less_str> > strhashmap;
+
+#else
+
+#include <ext/hash_map>
+using namespace __gnu_cxx;
+
+typedef const char * MyStr;
+struct eq_str {
+ bool operator()(const MyStr & x, const MyStr & y) const {
+ if ( strcmp(x, y) == 0)
+ return true;
+
+ return false;
+ }
+};
+
+typedef hash_map<const char*, int, hash<const char *>, eq_str > strhashmap;
+
+#endif
+
+#include "minilex.h"
+
+MiniLex minilex;
+
class Where {
public:
+ Where() { codeCopy = 0; }
~Where() {
JavaJS->scopeFree(scope);
- scope = 0; func = 0;
+ delete codeCopy;
+ scope = 0; func = 0; codeCopy = 0;
}
jlong scope, func;
+ strhashmap fields;
+// map<string,int> fields;
+ bool fullObject;
+ int nFields;
+ char *codeCopy;
+
+ void setFunc(const char *code) {
+ codeCopy = new char[strlen(code)+1];
+ strcpy(codeCopy,code);
+ func = JavaJS->functionCreate( code );
+ minilex.grabVariables(codeCopy, fields);
+ fullObject = fields.count("fullObject") > 0;
+ nFields = fields.size();
+ }
+
+ void buildSubset(JSObj& src, JSObjBuilder& dst) {
+ JSElemIter it(src);
+ int n = 0;
+ if( !it.more() ) return;
+ while( 1 ) {
+ Element e = it.next();
+ if( e.eoo() )
+ break;
+ if( //n == 0 &&
+ fields.find(e.fieldName()) != fields.end()
+ //fields.count(e.fieldName())
+ ) {
+ dst.append(e);
+ if( ++n >= nFields )
+ break;
+ }
+ }
+ }
};
JSMatcher::~JSMatcher() {
@@ -243,13 +318,10 @@ JSMatcher::JSMatcher(JSObj &_jsobj) :
assert( where == 0 );
where = new Where();
const char *code = e.valuestr();
- if ( ! JavaJS ){
- JavaJS = new JavaJSImpl();
- javajstest();
- }
+ assert( JavaJS );
where->scope = JavaJS->scopeCreate();
JavaJS->scopeSetString(where->scope, "$client", client->name.c_str());
- where->func = JavaJS->functionCreate( code );
+ where->setFunc(code);
continue;
}
@@ -398,7 +470,14 @@ ok:
if( where ) {
if( where->func == 0 )
return false; // didn't compile
- JavaJS->scopeSetObject(where->scope, "obj", &jsobj);
+ if( jsobj.objsize() < 200 || where->fullObject ) {
+ JavaJS->scopeSetObject(where->scope, "obj", &jsobj);
+ } else {
+ JSObjBuilder b;
+ where->buildSubset(jsobj, b);
+ JSObj temp = b.done();
+ JavaJS->scopeSetObject(where->scope, "obj", &temp);
+ }
if( JavaJS->invoke(where->scope, where->func) )
return false;
return JavaJS->scopeGetBoolean(where->scope, "return") != 0;
diff --git a/db/jsobj.h b/db/jsobj.h
index cb4fcd18941..46ba252f43f 100644
--- a/db/jsobj.h
+++ b/db/jsobj.h
@@ -313,6 +313,11 @@ public:
int l;
return JSObj(decouple(l), true);
}
+
+ /* this version, jsobjbuilder still frees the jsobj
+ when the builder goes out of scope. use it this way
+ by default, that's simplest.
+ */
JSObj done() {
return JSObj(_done());
}
diff --git a/db/minilex.h b/db/minilex.h
new file mode 100644
index 00000000000..64c98fb9ff8
--- /dev/null
+++ b/db/minilex.h
@@ -0,0 +1,97 @@
+// minilex.h
+// mini js lexical analyzer. idea is to be dumb and fast.
+
+struct MiniLex {
+ strhashmap reserved;
+ bool ic[256]; // ic=Identifier Character
+ bool starter[256];
+
+ // dm: very dumb about comments and escaped quotes -- but we are faster then at least,
+ // albeit returning too much (which is ok for jsbobj current usage).
+ void grabVariables(char *code /*modified and must stay in scope*/, strhashmap& vars) {
+ char *p = code;
+ char last = 0;
+ while( *p ) {
+ if( starter[*p] ) {
+ char *q = p+1;
+ while( *q && ic[*q] ) q++;
+ const char *identifier = p;
+ bool done = *q == 0;
+ *q = 0;
+ if( !reserved.count(identifier) ) {
+ // we try to be smart about 'obj' but have to be careful as obj.obj
+ // can happen; this is so that nFields is right for simplistic where cases
+ // so we can stop scanning in jsobj when we find the field of interest.
+ if( strcmp(identifier,"obj")==0 && p>code && p[-1] != '.' )
+ ;
+ else
+ vars[identifier] = 1;
+ }
+ if( done )
+ break;
+ p = q + 1;
+ continue;
+ }
+
+ if( *p == '\'' ) {
+ p++;
+ while( *p && *p != '\'' ) p++;
+ }
+ else if( *p == '"' ) {
+ p++;
+ while( *p && *p != '"' ) p++;
+ }
+ p++;
+ }
+ }
+
+ MiniLex() {
+ strhashmap atest;
+ atest["foo"] = 3;
+ assert( atest.count("bar") == 0 );
+ assert( atest.count("foo") == 1 );
+ assert( atest["foo"] == 3 );
+
+ for( int i = 0; i < 256; i++ ) {
+ ic[i] = starter[i] = false;
+ }
+ for( int i = 'a'; i <= 'z'; i++ )
+ ic[i] = starter[i] = true;
+ for( int i = 'A'; i <= 'Z'; i++ )
+ ic[i] = starter[i] = true;
+ for( int i = '0'; i <= '9'; i++ )
+ ic[i] = true;
+ for( int i = 128; i < 256; i++ )
+ ic[i] = starter[i] = true;
+ ic['$'] = starter['$'] = true;
+ ic['_'] = starter['_'] = true;
+
+ reserved["break"] = true;
+ reserved["case"] = true;
+ reserved["catch"] = true;
+ reserved["continue"] = true;
+ reserved["default"] = true;
+ reserved["delete"] = true;
+ reserved["do"] = true;
+ reserved["else"] = true;
+ reserved["finally"] = true;
+ reserved["for"] = true;
+ reserved["function"] = true;
+ reserved["if"] = true;
+ reserved["in"] = true;
+ reserved["instanceof"] = true;
+ reserved["new"] = true;
+ reserved["return"] = true;
+ reserved["switch"] = true;
+ reserved["this"] = true;
+ reserved["throw"] = true;
+ reserved["try"] = true;
+ reserved["typeof"] = true;
+ reserved["var"] = true;
+ reserved["void"] = true;
+ reserved["while"] = true;
+ reserved["with "] = true;
+ }
+};
+
+