diff --git a/db/btree.h b/db/btree.h index 617b8570b7c..05c0c7f62ef 100644 --- a/db/btree.h +++ b/db/btree.h @@ -200,7 +200,10 @@ public: virtual Record* _current() { return currLoc().rec(); } virtual BSONObj current() { return BSONObj(_current()); } virtual string toString() { - return string("BtreeCursor ") + indexDetails.indexName(); + string s = string("BtreeCursor ") + indexDetails.indexName(); + if( direction < 0 ) s += " reverse"; + if( stopmiss ) s += " stopmiss"; + return s; } private: diff --git a/db/commands.cpp b/db/commands.cpp index d77323cf0ba..8b4840ddc6b 100644 --- a/db/commands.cpp +++ b/db/commands.cpp @@ -65,4 +65,4 @@ bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& } return false; -} \ No newline at end of file +} diff --git a/db/jsobj.cpp b/db/jsobj.cpp index 15736327f07..29720896eb6 100644 --- a/db/jsobj.cpp +++ b/db/jsobj.cpp @@ -389,7 +389,8 @@ BSONObj BSONObj::extractFieldsDotted(BSONObj pattern, BSONObjBuilder& b) { } return b.done(); } -BSONObj BSONObj::extractFieldsUnDotted(BSONObj pattern, BSONObjBuilder& b) { +BSONObj BSONObj::extractFieldsUnDotted(BSONObj pattern) { + BSONObjBuilder b; BSONObjIterator i(pattern); while( i.more() ) { BSONElement e = i.next(); @@ -400,7 +401,7 @@ BSONObj BSONObj::extractFieldsUnDotted(BSONObj pattern, BSONObjBuilder& b) { return BSONObj(); b.append(x); } - return b.done(); + return b.doneAndDecouple(); } BSONObj BSONObj::extractFields(BSONObj& pattern) { @@ -439,6 +440,18 @@ BSONObj BSONObj::getObjectField(const char *name) { return t == Object || t == Array ? e.embeddedObject() : BSONObj(); } +int BSONObj::nFields() { + int n = 0; + BSONObjIterator i(*this); + while( i.more() ) { + BSONElement e = i.next(); + if( e.eoo() ) + break; + n++; + } + return n; +} + /* grab names of all the fields in this object */ int BSONObj::getFieldNames(set& fields) { int n = 0; diff --git a/db/jsobj.h b/db/jsobj.h index 0a577a7c3fa..9f858b04880 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -264,6 +264,11 @@ public: /* note: addFields always adds _id even if not specified */ int addFields(BSONObj& from, set& fields); /* returns n added */ + /* returns # of top level fields in the object + note: iterates to count the fields + */ + int nFields(); + /* adds the field names to the fields set. does NOT clear it (appends). */ int getFieldNames(set& fields); @@ -288,7 +293,7 @@ public: if any field missing, you get back an empty object overall. */ BSONObj extractFieldsDotted(BSONObj pattern, BSONObjBuilder& b); // this version, builder owns the returned obj buffer - BSONObj extractFieldsUnDotted(BSONObj pattern, BSONObjBuilder& b); + BSONObj extractFieldsUnDotted(BSONObj pattern); BSONObj extractFields(BSONObj &pattern); const char *objdata() const { return details->_objdata; } @@ -456,7 +461,7 @@ public: /* assume ownership of the buffer - you must then free it (with free()) */ char* decouple(int& l) { char *x = _done(); - assert( x ); + assert( x ); l = b.len(); b.decouple(); return x; diff --git a/db/namespace.h b/db/namespace.h index d541a19feb1..a880cf8d267 100644 --- a/db/namespace.h +++ b/db/namespace.h @@ -72,6 +72,18 @@ public: */ DiskLoc info; + /* extract key value from the query object + e.g., if key() == { x : 1 }, + { x : 70, y : 3 } -> { x : 70 } + handles our embedded dot notation too. + */ + BSONObj getKeyFromQuery(BSONObj& query) { + BSONObj k = key(); + BSONObj res = query.extractFieldsUnDotted(k); + assert(res.objsize() != 0); // guard against a seg fault if details is 0 + return res; + } + /* pull out the relevant key objects from obj, so we can index them. Note that the set is multiple elements only when it's a "multikey" array. diff --git a/db/query.cpp b/db/query.cpp index af9d9d4a1d9..0d5dd735a81 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -54,7 +54,7 @@ void appendElementHandlingGtLt(BSONObjBuilder& b, BSONElement& e); simpleKeyMatch - set to true if the query is purely for a single key value unchanged otherwise. */ -auto_ptr getIndexCursor(const char *ns, BSONObj& query, BSONObj& order, bool *simpleKeyMatch = 0, bool *isSorted = 0) { +auto_ptr getIndexCursor(const char *ns, BSONObj& query, BSONObj& order, bool *simpleKeyMatch = 0, bool *isSorted = 0, string *hint = 0) { NamespaceDetails *d = nsdetails(ns); if( d == 0 ) return auto_ptr(); @@ -87,6 +87,25 @@ auto_ptr getIndexCursor(const char *ns, BSONObj& query, BSONObj& order, } } + if( hint && !hint->empty() ) { + /* todo: more work needed. doesn't handle $lt & $gt for example. + waiting for query optimizer rewrite (see queryoptimizer.h) before finishing the work. + */ + for(int i = 0; i < d->nIndexes; i++ ) { + IndexDetails& ii = d->indexes[i]; + if( ii.indexName() == *hint ) { + BSONObj startKey = ii.getKeyFromQuery(query); + int direction = 1; + bool stopMiss = true; + if( simpleKeyMatch ) + *simpleKeyMatch = query.nFields() == startKey.nFields(); + if( isSorted ) *isSorted = false; + return auto_ptr( + new BtreeCursor(ii, startKey, direction, stopMiss)); + } + } + } + // regular query without order by for(int i = 0; i < d->nIndexes; i++ ) { BSONObj idxInfo = d->indexes[i].info.obj(); // { name:, ns:, key: } @@ -104,8 +123,8 @@ auto_ptr getIndexCursor(const char *ns, BSONObj& query, BSONObj& order, if( match ) { bool simple = true; - BSONObjBuilder b; - BSONObj q = query.extractFieldsUnDotted(idxKey, b); + //BSONObjBuilder b; + BSONObj q = query.extractFieldsUnDotted(idxKey); assert(q.objsize() != 0); // guard against a seg fault if details is 0 /* regexp: only supported if form is /^text/ */ BSONObjBuilder b2; @@ -588,6 +607,7 @@ QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoret uassert("not master", isMaster() || (queryOptions & Option_SlaveOk)); + string hint; bool explain = false; bool _gotquery = false; BSONObj query;// = jsobj.getObjectField("query"); @@ -611,6 +631,7 @@ QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoret query = jsobj; else { explain = jsobj.getBoolField("$explain"); + hint = jsobj.getStringField("$hint"); } /* The ElemIter will not be happy if this isn't really an object. So throw exception @@ -632,7 +653,7 @@ QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoret auto_ptr c = getSpecialCursor(ns); if( c.get() == 0 ) - c = getIndexCursor(ns, query, order, 0, &isSorted); + c = getIndexCursor(ns, query, order, 0, &isSorted, &hint); if( c.get() == 0 ) c = findTableScan(ns, order, &isSorted);