From b1a480423bb8136f69a573413dcc097a900342a4 Mon Sep 17 00:00:00 2001 From: Dwight Date: Fri, 27 Jun 2008 18:35:03 -0400 Subject: first cut at "fast count" --- db/btree.cpp | 7 ------- db/db.vcproj | 8 ++++++++ db/jsobj.h | 8 ++++++++ db/json.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ db/json.h | 8 ++++++++ db/makefile | 2 +- db/namespace.h | 5 +++-- db/pdfile.cpp | 6 ++++-- db/query.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 db/json.cpp create mode 100644 db/json.h diff --git a/db/btree.cpp b/db/btree.cpp index c4a36e2e0ea..d7f0c1e7c02 100644 --- a/db/btree.cpp +++ b/db/btree.cpp @@ -847,13 +847,6 @@ void BtreeCursor::checkUnused() { cout << "btree unused skipped:" << u << endl; } -/*DiskLoc BtreeCursor::currLoc() { - assert( !bucket.isNull() ); - _KeyNode& kn = bucket.btree()->k(keyOfs); - assert( kn.isUsed() ); - return kn.recordLoc; -}*/ - bool BtreeCursor::advance() { if( bucket.isNull() ) return false; diff --git a/db/db.vcproj b/db/db.vcproj index 446dda2e6a9..60d4da0b402 100644 --- a/db/db.vcproj +++ b/db/db.vcproj @@ -198,6 +198,10 @@ RelativePath=".\jsobj.cpp" > + + @@ -280,6 +284,10 @@ RelativePath=".\jsobj.h" > + + diff --git a/db/jsobj.h b/db/jsobj.h index cc7e570307a..50cc3a55fd6 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -330,6 +330,13 @@ public: b.append(fieldName); b.append(n); } + void appendOID(const char *fieldName) { + b.append((char) jstOID); + b.append(fieldName); + b.append((long long) 0); + b.append((unsigned) 0); + } + void appendDate(const char *fieldName, unsigned long long dt) { b.append((char) Date); b.append(fieldName); @@ -342,6 +349,7 @@ public: b.append(str); } + /* JSObj will free the buffer when it is finished. */ JSObj doneAndDecouple() { int l; return JSObj(decouple(l), true); diff --git a/db/json.cpp b/db/json.cpp new file mode 100644 index 00000000000..6c875ab95d4 --- /dev/null +++ b/db/json.cpp @@ -0,0 +1,46 @@ +// json.cpp + +#include "stdafx.h" +#include "json.h" +#include "../util/builder.h" + +/* partial implementation for now */ + +void skipWhite(const char *&p) { + while( *p == ' ' || *p == '\r' || *p == '\n' || *p == '\t' ) + p++; +} + +void value(JSObjBuilder& b, const char *&p, string& id) { + if( strncmp(p, "ObjId()", 7) == 0 ) { + p += 7; + b.appendOID(id.c_str()); + } +} + +void _fromjson(JSObjBuilder& b, const char *&p) { + while( 1 ) { + skipWhite(p); + if( *p == 0 ) + break; + if( *p == '{' ) { _fromjson(b,++p); continue; } + if( *p == '}' ) { ++p; break; } + if( *p == '_' || isalpha(*p) ) { + string id; + while( *p == '_' || isalpha(*p) || isdigit(*p) ) { + id += *p++; + } + skipWhite(p); + assert( *p == ':' ); p++; + skipWhite(p); + value(b, p, id); + continue; + } + } +} + +JSObj fromjson(const char *str) { + JSObjBuilder b; + _fromjson(b,str); + return b.doneAndDecouple(); +} diff --git a/db/json.h b/db/json.h new file mode 100644 index 00000000000..febee18940e --- /dev/null +++ b/db/json.h @@ -0,0 +1,8 @@ +// json.h + +#pragma once + +#include "../stdafx.h" +#include "jsobj.h" + +JSObj fromjson(const char *str); diff --git a/db/makefile b/db/makefile index 76d8cbfdb2f..f8ea9ab2f4b 100644 --- a/db/makefile +++ b/db/makefile @@ -8,7 +8,7 @@ LIBS= $(LIB_DEPS) $(LIB_BOOST) -lstdc++ JVM_LIBS = -L/opt/java/lib/ -OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/mmap.o pdfile.o query.o jsobj.o introspect.o btree.o clientcursor.o ../util/util.o javajs.o tests.o +OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/mmap.o pdfile.o query.o jsobj.o introspect.o btree.o clientcursor.o ../util/util.o javajs.o tests.o json.o # ../grid/protorecv.o ../grid/protosend.o diff --git a/db/namespace.h b/db/namespace.h index e8e056ed958..0854a666ed6 100644 --- a/db/namespace.h +++ b/db/namespace.h @@ -73,11 +73,12 @@ public: extern int bucketSizes[]; +/* this is the "header" for a collection that has all its details. in the .ns file. +*/ class NamespaceDetails { public: NamespaceDetails() { - /* be sure to initialize new fields here, otherwise they will contain garbage by default. - */ + /* be sure to initialize new fields here -- doesn't default to zeroes the way we use it */ datasize = nrecords = 0; lastExtentSize = 0; nIndexes = 0; diff --git a/db/pdfile.cpp b/db/pdfile.cpp index 1ec6a11142d..28cd97f786c 100644 --- a/db/pdfile.cpp +++ b/db/pdfile.cpp @@ -576,7 +576,9 @@ auto_ptr DataFileMgr::findAll(const char *ns) { return auto_ptr(new BasicCursor( e->firstRecord )); } -/* get a table scan cursor, but can be forward or reverse direction */ +/* get a table scan cursor, but can be forward or reverse direction. + order.$natural - if set, > 0 means forward (asc), < 0 backward (desc). +*/ auto_ptr findTableScan(const char *ns, JSObj& order) { Element el = order.findElement("$natural"); if( el.type() != Number || el.number() >= 0 ) @@ -919,7 +921,7 @@ DiskLoc DataFileMgr::insert(const char *ns, const void *buf, int len, bool god) } tableToIndex = nsdetails(tabletoidxns); if( tableToIndex == 0 ) { - cout << "user warning: bad add index attempt, no such table(ns):" << tabletoidxns << endl; + cout << "user warning: ignoring add index, no such collection:" << tabletoidxns << endl; return DiskLoc(); } if( tableToIndex->nIndexes >= MaxIndexes ) { diff --git a/db/query.cpp b/db/query.cpp index 3f76624dfb3..144c8d27f1a 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -10,6 +10,7 @@ #include "btree.h" #include "../util/lruishmap.h" #include "javajs.h" +#include "json.h" //ns->query->DiskLoc LRUishMap lrutest(123); @@ -29,6 +30,7 @@ JSObj emptyObj((char *) &emptyObject); int getGtLtOp(Element& e); void appendElementHandlingGtLt(JSObjBuilder& b, Element& e); +int runCount(const char *ns, const JSObj& cmd, string& err); /* todo: _ cache query plans _ use index on partial match with the query @@ -552,9 +554,25 @@ inline bool _runCommands(const char *ns, JSObj& jsobj, stringstream& ss, BufBuil } } else if( e.type() == String ) { + /* { count: "collectionname"[, query: ] } */ string us(ns, p-ns); - if( strcmp( e.fieldName(), "create") == 0 ) { + if( strcmp( e.fieldName(), "count" ) == 0 ) { + valid = true; + string ns = us + '.' + e.valuestr(); + string err; + int n = runCount(ns.c_str(), jsobj, err); + int nn = n; + ok = true; + if( n < 0 ) { + ok = false; + nn = 0; + if( !err.empty() ) + anObjBuilder.append("errmsg", err.c_str()); + } + anObjBuilder.append("n", (double) nn); + } + else if( strcmp( e.fieldName(), "create") == 0 ) { valid = true; string ns = us + '.' + e.valuestr(); string err; @@ -684,8 +702,36 @@ void killCursors(int n, long long *ids) { cout << "killCursors: found " << k << " of " << n << endl; } +// order.$natural sets natural order direction auto_ptr findTableScan(const char *ns, JSObj& order); +JSObj id_obj = fromjson("{_id:ObjId()}"); +JSObj empty_obj = fromjson("{}"); + +/* { count: "collectionname"[, query: ] } + returns -1 on error. +*/ +int runCount(const char *ns, const JSObj& cmd, string& err) { + NamespaceDetails *d = nsdetails(ns); + if( d == 0 ) { + err = "ns does not exist"; + return -1; + } + + auto_ptr c = getIndexCursor(ns, id_obj, empty_obj); + if( c.get() == 0 ) { + cout << "TEMP: table scan" << endl; + c = findTableScan(ns, empty_obj); + } + else cout << "TEMP: indexed scan" << endl; + int count = 0; + if( c->ok() ) { + count++; + while( c->advance() ) count++; + } + return count; +} + QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoreturn, JSObj jsobj, auto_ptr< set > filter, stringstream& ss) { -- cgit v1.2.1