summaryrefslogtreecommitdiff
path: root/src/mongo/db/exec
diff options
context:
space:
mode:
authorHari Khalsa <hkhalsa@10gen.com>2014-03-03 12:17:49 -0500
committerHari Khalsa <hkhalsa@10gen.com>2014-03-03 14:13:09 -0500
commit785b41bb229d49352e883df2fe0f927888772c8f (patch)
tree7c500e571f8558b07a8acabcfd271fd142aa1f8d /src/mongo/db/exec
parent24f85cdfdba1db685f4da499d8fcb77385e57da7 (diff)
downloadmongo-785b41bb229d49352e883df2fe0f927888772c8f.tar.gz
SERVER-12952 do less work for non-matching index docs
Diffstat (limited to 'src/mongo/db/exec')
-rw-r--r--src/mongo/db/exec/filter.h60
-rw-r--r--src/mongo/db/exec/index_scan.cpp24
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;
}