diff --git a/db/db.cpp b/db/db.cpp index 2119f8b1b20..816dc088c0c 100644 --- a/db/db.cpp +++ b/db/db.cpp @@ -56,6 +56,13 @@ public: nextjsobj += 4; return i; } + long long pullInt64() { + if( nextjsobj == data ) + nextjsobj += strlen(data) + 1; // skip namespace + long long i = *((long long *)nextjsobj); + nextjsobj += 8; + return i; + } OID* getOID() { return (OID *) (data + strlen(data) + 1); // skip namespace @@ -135,7 +142,6 @@ void receivedDelete(Message& m) { void receivedQuery(Message& m) { DbMessage d(m); - const char *ns = d.getns(); int ntoreturn = d.pullInt(); assert( d.moreJSObjs() ); @@ -145,6 +151,17 @@ void receivedQuery(Message& m) { dbMsgPort.reply(m, resp); } +void receivedGetMore(Message& m) { + DbMessage d(m); + const char *ns = d.getns(); + int ntoreturn = d.pullInt(); + long long cursorid = d.pullInt64(); + QueryResult* msgdata = getMore(ns, ntoreturn, cursorid); + Message resp; + resp.setData(msgdata, true); + dbMsgPort.reply(m, resp); +} + /*void getbyoid(Message& m) { DbMessage d(m); Record *r = findByOID(d.getns(), d.getOID()); diff --git a/db/db.vcproj b/db/db.vcproj index e8670b5a20c..77892c3d80a 100644 Binary files a/db/db.vcproj and b/db/db.vcproj differ diff --git a/db/jsobj.cpp b/db/jsobj.cpp index 3217bbca891..95df34c8403 100644 --- a/db/jsobj.cpp +++ b/db/jsobj.cpp @@ -91,19 +91,16 @@ JSMatcher::JSMatcher(JSObj &_jsobj) : struct RXTest { RXTest() { -// pcre_compile(0, 0, 0, 0, 0); -//pcre_compile(const char *, int, const char **, int *, -// const unsigned char *); - -/* + /* static const boost::regex e("(\\d{4}[- ]){3}\\d{4}"); static const boost::regex b("....."); cout << "regex result: " << regex_match("hello", e) << endl; cout << "regex result: " << regex_match("abcoo", b) << endl; -*/ - pcrecpp::RE re("h.*o"); - cout << "regex test: " << re.FullMatch("hello") << endl; - cout << "regex test: " << re.FullMatch("blah") << endl; + */ + pcrecpp::RE re1(")({a}h.*o"); + pcrecpp::RE re("h.llo"); + assert( re.FullMatch("hello") ); + assert( !re1.FullMatch("hello") ); } } rxtest; diff --git a/db/query.cpp b/db/query.cpp index 609d2a3954a..9bc2e465399 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -5,6 +5,7 @@ #include "pdfile.h" #include "jsobj.h" #include "../util/builder.h" +#include int nextCursorId = 1; @@ -65,13 +66,28 @@ void updateObjects(const char *ns, JSObj updateobj, JSObj pattern, bool upsert) theDataFileMgr.insert(ns, (void*) updateobj.objdata(), updateobj.objsize()); } +typedef map CCMap; +CCMap clientCursors; + +long long allocCursorId() { + long long x; + while( 1 ) { + x = (((long long)rand()) << 32); + x = x | time(0); + if( clientCursors.count(x) == 0 ) + break; + } + return x; +} + QueryResult* runQuery(const char *ns, int ntoreturn, JSObj jsobj) { cout << "runQuery ns:" << ns << " ntoreturn:" << ntoreturn << " queryobjsize:" << jsobj.objsize() << endl; BufBuilder b; - JSMatcher matcher(jsobj); + + auto_ptr matcher(new JSMatcher(jsobj)); QueryResult *qr = 0; b.skip(sizeof(QueryResult)); @@ -79,17 +95,28 @@ QueryResult* runQuery(const char *ns, int ntoreturn, JSObj jsobj) { int n = 0; auto_ptr c = -// strcmp(ns, "system.namespaces") == 0 ? -// makeNamespaceCursor() : + // strcmp(ns, "system.namespaces") == 0 ? + // makeNamespaceCursor() : theDataFileMgr.findAll(ns); + long long cursorid = 0; while( c->ok() ) { JSObj js = c->current(); - if( matcher.matches(js) ) { + if( matcher->matches(js) ) { b.append((void*) js.objdata(), js.objsize()); n++; - if( n >= ntoreturn && ntoreturn != 0 ) + if( n >= ntoreturn && ntoreturn != 0 ) { + // more...so save a cursor + ClientCursor *cc = new ClientCursor(); + cc->c = c; + cursorid = allocCursorId(); + cc->cursorid = cursorid; + cc->matcher = matcher; + cc->ns = ns; + cc->pos = n; + clientCursors[cursorid] = cc; break; + } } c->advance(); } @@ -98,10 +125,68 @@ QueryResult* runQuery(const char *ns, int ntoreturn, JSObj jsobj) { qr->len = b.len(); qr->reserved = 0; qr->operation = opReply; - qr->cursorId = 0; //nextCursorId++; + qr->cursorId = cursorid; qr->startingFrom = 0; qr->nReturned = n; b.decouple(); return qr; } + +QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid) { + + cout << "getMore ns:" << ns << " ntoreturn:" << ntoreturn << " cursorid:" << + cursorid << endl; + + BufBuilder b; + + ClientCursor *cc = 0; + CCMap::iterator it = clientCursors.find(cursorid); + if( it == clientCursors.end() ) { + cout << "Cursor not found in map. cursorid: " << cursorid << endl; + } + else { + cc = it->second; + } + + b.skip(sizeof(QueryResult)); + + int start = 0; + int n = 0; + + if( cc ) { + start = cc->pos; + Cursor *c = cc->c.get(); + while( 1 ) { + if( !c->ok() ) { + // done! kill cursor. + cursorid = 0; + clientCursors.erase(it); + delete cc; + cc = 0; + break; + } + JSObj js = c->current(); + if( cc->matcher->matches(js) ) { + b.append((void*) js.objdata(), js.objsize()); + n++; + if( n >= ntoreturn && ntoreturn != 0 ) { + cc->pos += n; + break; + } + } + } + c->advance(); + } + + QueryResult *qr = (QueryResult *) b.buf(); + qr->cursorId = cursorid; + qr->startingFrom = start; + qr->len = b.len(); + qr->reserved = 0; + qr->operation = opReply; + qr->nReturned = n; + b.decouple(); + + return qr; +} diff --git a/db/query.h b/db/query.h index f216a858c94..437be85c207 100644 --- a/db/query.h +++ b/db/query.h @@ -25,9 +25,10 @@ int nToReturn; // how many you want back as the beginning of the cursor data JSObject query; dbGetMore: - int reserved;; - int64 cursorID; + int reserved; + string collection; // redundant, might use for security. int nToReturn; + int64 cursorID; Note that on Update, there is only one object, which is different from insert where you can pass a list of objects to insert in the db. @@ -51,7 +52,20 @@ struct QueryResult : public MsgData { const char *data() { return (char *) (((int *)&nReturned)+1); } }; +QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid); QueryResult* runQuery(const char *ns, int ntoreturn, JSObj); void updateObjects(const char *ns, JSObj updateobj, JSObj pattern, bool upsert); void deleteObjects(const char *ns, JSObj pattern, bool justOne); + +class Cursor; +class ClientCursor { +public: + ClientCursor() { cursorid=0; pos=0; } + long long cursorid; + string ns; + auto_ptr matcher; + auto_ptr c; + int pos; +}; +