diff options
author | Hari Khalsa <hkhalsa@10gen.com> | 2014-03-03 12:17:49 -0500 |
---|---|---|
committer | Hari Khalsa <hkhalsa@10gen.com> | 2014-03-03 14:13:09 -0500 |
commit | 785b41bb229d49352e883df2fe0f927888772c8f (patch) | |
tree | 7c500e571f8558b07a8acabcfd271fd142aa1f8d | |
parent | 24f85cdfdba1db685f4da499d8fcb77385e57da7 (diff) | |
download | mongo-785b41bb229d49352e883df2fe0f927888772c8f.tar.gz |
SERVER-12952 do less work for non-matching index docs
-rw-r--r-- | src/mongo/db/exec/filter.h | 60 | ||||
-rw-r--r-- | src/mongo/db/exec/index_scan.cpp | 24 |
2 files changed, 73 insertions, 11 deletions
diff --git a/src/mongo/db/exec/filter.h b/src/mongo/db/exec/filter.h index ff9916bfb27..8fdd3b8be80 100644 --- a/src/mongo/db/exec/filter.h +++ b/src/mongo/db/exec/filter.h @@ -46,7 +46,7 @@ namespace mongo { // This is only called by a $where query. The query system must be smart enough to realize // that it should do a fetch beforehand. BSONObj toBSON() const { - verify(_wsm->hasObj()); + invariant(_wsm->hasObj()); return _wsm->obj; } @@ -67,7 +67,7 @@ namespace mongo { while (keyPatternIt.more()) { BSONElement keyPatternElt = keyPatternIt.next(); - verify(keyDataIt.more()); + invariant(keyDataIt.more()); BSONElement keyDataElt = keyDataIt.next(); if (path->fieldRef().equalsDottedField(keyPatternElt.fieldName())) { @@ -96,6 +96,53 @@ namespace mongo { WorkingSetMember* _wsm; }; + class IndexKeyMatchableDocument : public MatchableDocument { + public: + IndexKeyMatchableDocument(const BSONObj& key, + const BSONObj& keyPattern) + : _keyPattern(keyPattern), _key(key) { } + + BSONObj toBSON() const { + // Planning shouldn't let this happen. + invariant(0); + } + + virtual ElementIterator* allocateIterator(const ElementPath* path) const { + BSONObjIterator keyPatternIt(_keyPattern); + BSONObjIterator keyDataIt(_key); + + while (keyPatternIt.more()) { + BSONElement keyPatternElt = keyPatternIt.next(); + invariant(keyDataIt.more()); + BSONElement keyDataElt = keyDataIt.next(); + + if (path->fieldRef().equalsDottedField(keyPatternElt.fieldName())) { + if (Array == keyDataElt.type()) { + return new SimpleArrayElementIterator(keyDataElt, true); + } + else { + return new SingleElementElementIterator(keyDataElt); + } + } + } + + // Planning should not let this happen. + massert(17409, + "trying to match on unknown field: " + path->fieldRef().dottedField().toString(), + 0); + + return new SingleElementElementIterator(BSONElement()); + } + + virtual void releaseIterator(ElementIterator* iterator) const { + delete iterator; + } + + private: + BSONObj _keyPattern; + BSONObj _key; + }; + /** * Used by every stage with a filter. */ @@ -110,6 +157,15 @@ namespace mongo { WorkingSetMatchableDocument doc(wsm); return filter->matches(&doc, NULL); } + + static bool passes(const BSONObj& keyData, + const BSONObj& keyPattern, + const MatchExpression* filter) { + + if (NULL == filter) { return true; } + IndexKeyMatchableDocument doc(keyData, keyPattern); + return filter->matches(&doc, NULL); + } }; } // namespace mongo diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp index 0c7b1dd937a..31c8b58b4c1 100644 --- a/src/mongo/db/exec/index_scan.cpp +++ b/src/mongo/db/exec/index_scan.cpp @@ -140,7 +140,7 @@ namespace mongo { if (isEOF()) { return PlanStage::IS_EOF; } // Grab the next (key, value) from the index. - BSONObj ownedKeyObj = _indexCursor->getKey().getOwned(); + BSONObj keyObj = _indexCursor->getKey(); DiskLoc loc = _indexCursor->getValue(); // Move to the next result. @@ -162,27 +162,33 @@ namespace mongo { } } - WorkingSetID id = _workingSet->allocate(); - WorkingSetMember* member = _workingSet->get(id); - member->loc = loc; - member->keyData.push_back(IndexKeyDatum(_descriptor->keyPattern(), ownedKeyObj)); - member->state = WorkingSetMember::LOC_AND_IDX; - - if (Filter::passes(member, _filter)) { + if (Filter::passes(keyObj, _descriptor->keyPattern(), _filter)) { if (NULL != _filter) { ++_specificStats.matchTested; } + + // We must make a copy of the on-disk data since it can mutate during the execution of + // this query. + BSONObj ownedKeyObj = keyObj.getOwned(); + + // Fill out the WSM. + WorkingSetID id = _workingSet->allocate(); + WorkingSetMember* member = _workingSet->get(id); + member->loc = loc; + member->keyData.push_back(IndexKeyDatum(_descriptor->keyPattern(), ownedKeyObj)); + member->state = WorkingSetMember::LOC_AND_IDX; + if (_params.addKeyMetadata) { BSONObjBuilder bob; bob.appendKeys(_descriptor->keyPattern(), ownedKeyObj); member->addComputed(new IndexKeyComputedData(bob.obj())); } + *out = id; ++_commonStats.advanced; return PlanStage::ADVANCED; } - _workingSet->free(id); ++_commonStats.needTime; return PlanStage::NEED_TIME; } |