summaryrefslogtreecommitdiff
path: root/src/mongo/db/exec/and_sorted.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/exec/and_sorted.cpp')
-rw-r--r--src/mongo/db/exec/and_sorted.cpp453
1 files changed, 225 insertions, 228 deletions
diff --git a/src/mongo/db/exec/and_sorted.cpp b/src/mongo/db/exec/and_sorted.cpp
index c407b9c842c..27966791c87 100644
--- a/src/mongo/db/exec/and_sorted.cpp
+++ b/src/mongo/db/exec/and_sorted.cpp
@@ -35,292 +35,289 @@
namespace mongo {
- using std::unique_ptr;
- using std::numeric_limits;
- using std::vector;
-
- // static
- const char* AndSortedStage::kStageType = "AND_SORTED";
-
- AndSortedStage::AndSortedStage(WorkingSet* ws, const Collection* collection)
- : _collection(collection),
- _ws(ws),
- _targetNode(numeric_limits<size_t>::max()),
- _targetId(WorkingSet::INVALID_ID), _isEOF(false),
- _commonStats(kStageType) { }
-
- AndSortedStage::~AndSortedStage() {
- for (size_t i = 0; i < _children.size(); ++i) { delete _children[i]; }
+using std::unique_ptr;
+using std::numeric_limits;
+using std::vector;
+
+// static
+const char* AndSortedStage::kStageType = "AND_SORTED";
+
+AndSortedStage::AndSortedStage(WorkingSet* ws, const Collection* collection)
+ : _collection(collection),
+ _ws(ws),
+ _targetNode(numeric_limits<size_t>::max()),
+ _targetId(WorkingSet::INVALID_ID),
+ _isEOF(false),
+ _commonStats(kStageType) {}
+
+AndSortedStage::~AndSortedStage() {
+ for (size_t i = 0; i < _children.size(); ++i) {
+ delete _children[i];
}
+}
- void AndSortedStage::addChild(PlanStage* child) {
- _children.push_back(child);
- }
-
- bool AndSortedStage::isEOF() { return _isEOF; }
+void AndSortedStage::addChild(PlanStage* child) {
+ _children.push_back(child);
+}
- PlanStage::StageState AndSortedStage::work(WorkingSetID* out) {
- ++_commonStats.works;
+bool AndSortedStage::isEOF() {
+ return _isEOF;
+}
- // Adds the amount of time taken by work() to executionTimeMillis.
- ScopedTimer timer(&_commonStats.executionTimeMillis);
+PlanStage::StageState AndSortedStage::work(WorkingSetID* out) {
+ ++_commonStats.works;
- if (isEOF()) { return PlanStage::IS_EOF; }
+ // Adds the amount of time taken by work() to executionTimeMillis.
+ ScopedTimer timer(&_commonStats.executionTimeMillis);
- if (0 == _specificStats.failedAnd.size()) {
- _specificStats.failedAnd.resize(_children.size());
- }
+ if (isEOF()) {
+ return PlanStage::IS_EOF;
+ }
- // If we don't have any nodes that we're work()-ing until they hit a certain RecordId...
- if (0 == _workingTowardRep.size()) {
- // Get a target RecordId.
- return getTargetLoc(out);
- }
+ if (0 == _specificStats.failedAnd.size()) {
+ _specificStats.failedAnd.resize(_children.size());
+ }
- // Move nodes toward the target RecordId.
- // If all nodes reach the target RecordId, return it. The next call to work() will set a new
- // target.
- return moveTowardTargetLoc(out);
+ // If we don't have any nodes that we're work()-ing until they hit a certain RecordId...
+ if (0 == _workingTowardRep.size()) {
+ // Get a target RecordId.
+ return getTargetLoc(out);
}
- PlanStage::StageState AndSortedStage::getTargetLoc(WorkingSetID* out) {
- verify(numeric_limits<size_t>::max() == _targetNode);
- verify(WorkingSet::INVALID_ID == _targetId);
- verify(RecordId() == _targetLoc);
+ // Move nodes toward the target RecordId.
+ // If all nodes reach the target RecordId, return it. The next call to work() will set a new
+ // target.
+ return moveTowardTargetLoc(out);
+}
- // Pick one, and get a loc to work toward.
- WorkingSetID id = WorkingSet::INVALID_ID;
- StageState state = _children[0]->work(&id);
+PlanStage::StageState AndSortedStage::getTargetLoc(WorkingSetID* out) {
+ verify(numeric_limits<size_t>::max() == _targetNode);
+ verify(WorkingSet::INVALID_ID == _targetId);
+ verify(RecordId() == _targetLoc);
- if (PlanStage::ADVANCED == state) {
- WorkingSetMember* member = _ws->get(id);
+ // Pick one, and get a loc to work toward.
+ WorkingSetID id = WorkingSet::INVALID_ID;
+ StageState state = _children[0]->work(&id);
- // Maybe the child had an invalidation. We intersect RecordId(s) so we can't do anything
- // with this WSM.
- if (!member->hasLoc()) {
- _ws->flagForReview(id);
- return PlanStage::NEED_TIME;
- }
+ if (PlanStage::ADVANCED == state) {
+ WorkingSetMember* member = _ws->get(id);
- verify(member->hasLoc());
+ // Maybe the child had an invalidation. We intersect RecordId(s) so we can't do anything
+ // with this WSM.
+ if (!member->hasLoc()) {
+ _ws->flagForReview(id);
+ return PlanStage::NEED_TIME;
+ }
- // We have a value from one child to AND with.
- _targetNode = 0;
- _targetId = id;
- _targetLoc = member->loc;
+ verify(member->hasLoc());
- // We have to AND with all other children.
- for (size_t i = 1; i < _children.size(); ++i) {
- _workingTowardRep.push(i);
- }
+ // We have a value from one child to AND with.
+ _targetNode = 0;
+ _targetId = id;
+ _targetLoc = member->loc;
- ++_commonStats.needTime;
- return PlanStage::NEED_TIME;
+ // We have to AND with all other children.
+ for (size_t i = 1; i < _children.size(); ++i) {
+ _workingTowardRep.push(i);
}
- else if (PlanStage::IS_EOF == state) {
- _isEOF = true;
- return state;
+
+ ++_commonStats.needTime;
+ return PlanStage::NEED_TIME;
+ } else if (PlanStage::IS_EOF == state) {
+ _isEOF = true;
+ return state;
+ } else if (PlanStage::FAILURE == state) {
+ *out = id;
+ // If a stage fails, it may create a status WSM to indicate why it
+ // failed, in which case 'id' is valid. If ID is invalid, we
+ // create our own error message.
+ if (WorkingSet::INVALID_ID == id) {
+ mongoutils::str::stream ss;
+ ss << "sorted AND stage failed to read in results from first child";
+ Status status(ErrorCodes::InternalError, ss);
+ *out = WorkingSetCommon::allocateStatusMember(_ws, status);
}
- else if (PlanStage::FAILURE == state) {
+ _isEOF = true;
+ return state;
+ } else {
+ if (PlanStage::NEED_TIME == state) {
+ ++_commonStats.needTime;
+ } else if (PlanStage::NEED_YIELD == state) {
+ ++_commonStats.needYield;
*out = id;
- // If a stage fails, it may create a status WSM to indicate why it
- // failed, in which case 'id' is valid. If ID is invalid, we
- // create our own error message.
- if (WorkingSet::INVALID_ID == id) {
- mongoutils::str::stream ss;
- ss << "sorted AND stage failed to read in results from first child";
- Status status(ErrorCodes::InternalError, ss);
- *out = WorkingSetCommon::allocateStatusMember( _ws, status);
- }
- _isEOF = true;
- return state;
}
- else {
- if (PlanStage::NEED_TIME == state) {
- ++_commonStats.needTime;
- }
- else if (PlanStage::NEED_YIELD == state) {
- ++_commonStats.needYield;
- *out = id;
- }
- // NEED_TIME, NEED_YIELD.
- return state;
- }
+ // NEED_TIME, NEED_YIELD.
+ return state;
}
+}
- PlanStage::StageState AndSortedStage::moveTowardTargetLoc(WorkingSetID* out) {
- verify(numeric_limits<size_t>::max() != _targetNode);
- verify(WorkingSet::INVALID_ID != _targetId);
+PlanStage::StageState AndSortedStage::moveTowardTargetLoc(WorkingSetID* out) {
+ verify(numeric_limits<size_t>::max() != _targetNode);
+ verify(WorkingSet::INVALID_ID != _targetId);
- // We have nodes that haven't hit _targetLoc yet.
- size_t workingChildNumber = _workingTowardRep.front();
- PlanStage* next = _children[workingChildNumber];
- WorkingSetID id = WorkingSet::INVALID_ID;
- StageState state = next->work(&id);
+ // We have nodes that haven't hit _targetLoc yet.
+ size_t workingChildNumber = _workingTowardRep.front();
+ PlanStage* next = _children[workingChildNumber];
+ WorkingSetID id = WorkingSet::INVALID_ID;
+ StageState state = next->work(&id);
- if (PlanStage::ADVANCED == state) {
- WorkingSetMember* member = _ws->get(id);
+ if (PlanStage::ADVANCED == state) {
+ WorkingSetMember* member = _ws->get(id);
- // Maybe the child had an invalidation. We intersect RecordId(s) so we can't do anything
- // with this WSM.
- if (!member->hasLoc()) {
- _ws->flagForReview(id);
- return PlanStage::NEED_TIME;
- }
+ // Maybe the child had an invalidation. We intersect RecordId(s) so we can't do anything
+ // with this WSM.
+ if (!member->hasLoc()) {
+ _ws->flagForReview(id);
+ return PlanStage::NEED_TIME;
+ }
- verify(member->hasLoc());
+ verify(member->hasLoc());
- if (member->loc == _targetLoc) {
- // The front element has hit _targetLoc. Don't move it forward anymore/work on
- // another element.
- _workingTowardRep.pop();
- AndCommon::mergeFrom(_ws->get(_targetId), *member);
- _ws->free(id);
+ if (member->loc == _targetLoc) {
+ // The front element has hit _targetLoc. Don't move it forward anymore/work on
+ // another element.
+ _workingTowardRep.pop();
+ AndCommon::mergeFrom(_ws->get(_targetId), *member);
+ _ws->free(id);
- if (0 == _workingTowardRep.size()) {
- WorkingSetID toReturn = _targetId;
+ if (0 == _workingTowardRep.size()) {
+ WorkingSetID toReturn = _targetId;
- _targetNode = numeric_limits<size_t>::max();
- _targetId = WorkingSet::INVALID_ID;
- _targetLoc = RecordId();
+ _targetNode = numeric_limits<size_t>::max();
+ _targetId = WorkingSet::INVALID_ID;
+ _targetLoc = RecordId();
- *out = toReturn;
- ++_commonStats.advanced;
- return PlanStage::ADVANCED;
- }
- // More children need to be advanced to _targetLoc.
- ++_commonStats.needTime;
- return PlanStage::NEED_TIME;
- }
- else if (member->loc < _targetLoc) {
- // The front element of _workingTowardRep hasn't hit the thing we're AND-ing with
- // yet. Try again later.
- _ws->free(id);
- ++_commonStats.needTime;
- return PlanStage::NEED_TIME;
+ *out = toReturn;
+ ++_commonStats.advanced;
+ return PlanStage::ADVANCED;
}
- else {
- // member->loc > _targetLoc.
- // _targetLoc wasn't successfully AND-ed with the other sub-plans. We toss it and
- // try AND-ing with the next value.
- _specificStats.failedAnd[_targetNode]++;
-
- _ws->free(_targetId);
- _targetNode = workingChildNumber;
- _targetLoc = member->loc;
- _targetId = id;
- _workingTowardRep = std::queue<size_t>();
- for (size_t i = 0; i < _children.size(); ++i) {
- if (workingChildNumber != i) {
- _workingTowardRep.push(i);
- }
+ // More children need to be advanced to _targetLoc.
+ ++_commonStats.needTime;
+ return PlanStage::NEED_TIME;
+ } else if (member->loc < _targetLoc) {
+ // The front element of _workingTowardRep hasn't hit the thing we're AND-ing with
+ // yet. Try again later.
+ _ws->free(id);
+ ++_commonStats.needTime;
+ return PlanStage::NEED_TIME;
+ } else {
+ // member->loc > _targetLoc.
+ // _targetLoc wasn't successfully AND-ed with the other sub-plans. We toss it and
+ // try AND-ing with the next value.
+ _specificStats.failedAnd[_targetNode]++;
+
+ _ws->free(_targetId);
+ _targetNode = workingChildNumber;
+ _targetLoc = member->loc;
+ _targetId = id;
+ _workingTowardRep = std::queue<size_t>();
+ for (size_t i = 0; i < _children.size(); ++i) {
+ if (workingChildNumber != i) {
+ _workingTowardRep.push(i);
}
- // Need time to chase after the new _targetLoc.
- ++_commonStats.needTime;
- return PlanStage::NEED_TIME;
}
+ // Need time to chase after the new _targetLoc.
+ ++_commonStats.needTime;
+ return PlanStage::NEED_TIME;
}
- else if (PlanStage::IS_EOF == state) {
- _isEOF = true;
- _ws->free(_targetId);
- return state;
+ } else if (PlanStage::IS_EOF == state) {
+ _isEOF = true;
+ _ws->free(_targetId);
+ return state;
+ } else if (PlanStage::FAILURE == state || PlanStage::DEAD == state) {
+ *out = id;
+ // If a stage fails, it may create a status WSM to indicate why it
+ // failed, in which case 'id' is valid. If ID is invalid, we
+ // create our own error message.
+ if (WorkingSet::INVALID_ID == id) {
+ mongoutils::str::stream ss;
+ ss << "sorted AND stage failed to read in results from child " << workingChildNumber;
+ Status status(ErrorCodes::InternalError, ss);
+ *out = WorkingSetCommon::allocateStatusMember(_ws, status);
}
- else if (PlanStage::FAILURE == state || PlanStage::DEAD == state) {
+ _isEOF = true;
+ _ws->free(_targetId);
+ return state;
+ } else {
+ if (PlanStage::NEED_TIME == state) {
+ ++_commonStats.needTime;
+ } else if (PlanStage::NEED_YIELD == state) {
+ ++_commonStats.needYield;
*out = id;
- // If a stage fails, it may create a status WSM to indicate why it
- // failed, in which case 'id' is valid. If ID is invalid, we
- // create our own error message.
- if (WorkingSet::INVALID_ID == id) {
- mongoutils::str::stream ss;
- ss << "sorted AND stage failed to read in results from child " << workingChildNumber;
- Status status(ErrorCodes::InternalError, ss);
- *out = WorkingSetCommon::allocateStatusMember( _ws, status);
- }
- _isEOF = true;
- _ws->free(_targetId);
- return state;
}
- else {
- if (PlanStage::NEED_TIME == state) {
- ++_commonStats.needTime;
- }
- else if (PlanStage::NEED_YIELD == state) {
- ++_commonStats.needYield;
- *out = id;
- }
- return state;
- }
+ return state;
}
+}
- void AndSortedStage::saveState() {
- ++_commonStats.yields;
+void AndSortedStage::saveState() {
+ ++_commonStats.yields;
- for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->saveState();
- }
+ for (size_t i = 0; i < _children.size(); ++i) {
+ _children[i]->saveState();
}
+}
- void AndSortedStage::restoreState(OperationContext* opCtx) {
- ++_commonStats.unyields;
+void AndSortedStage::restoreState(OperationContext* opCtx) {
+ ++_commonStats.unyields;
- for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->restoreState(opCtx);
- }
+ for (size_t i = 0; i < _children.size(); ++i) {
+ _children[i]->restoreState(opCtx);
}
+}
- void AndSortedStage::invalidate(OperationContext* txn,
- const RecordId& dl,
- InvalidationType type) {
- ++_commonStats.invalidates;
-
- if (isEOF()) { return; }
-
- for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->invalidate(txn, dl, type);
- }
-
- if (dl == _targetLoc) {
- // We're in the middle of moving children forward until they hit _targetLoc, which is no
- // longer a valid target. If it's a deletion we can't AND it with anything, if it's a
- // mutation the predicates implied by the AND may no longer be true. So no matter what,
- // fetch it, flag for review, and find another _targetLoc.
- ++_specificStats.flagged;
+void AndSortedStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {
+ ++_commonStats.invalidates;
- // The RecordId could still be a valid result so flag it and save it for later.
- WorkingSetCommon::fetchAndInvalidateLoc(txn, _ws->get(_targetId), _collection);
- _ws->flagForReview(_targetId);
+ if (isEOF()) {
+ return;
+ }
- _targetId = WorkingSet::INVALID_ID;
- _targetNode = numeric_limits<size_t>::max();
- _targetLoc = RecordId();
- _workingTowardRep = std::queue<size_t>();
- }
+ for (size_t i = 0; i < _children.size(); ++i) {
+ _children[i]->invalidate(txn, dl, type);
}
- vector<PlanStage*> AndSortedStage::getChildren() const {
- return _children;
+ if (dl == _targetLoc) {
+ // We're in the middle of moving children forward until they hit _targetLoc, which is no
+ // longer a valid target. If it's a deletion we can't AND it with anything, if it's a
+ // mutation the predicates implied by the AND may no longer be true. So no matter what,
+ // fetch it, flag for review, and find another _targetLoc.
+ ++_specificStats.flagged;
+
+ // The RecordId could still be a valid result so flag it and save it for later.
+ WorkingSetCommon::fetchAndInvalidateLoc(txn, _ws->get(_targetId), _collection);
+ _ws->flagForReview(_targetId);
+
+ _targetId = WorkingSet::INVALID_ID;
+ _targetNode = numeric_limits<size_t>::max();
+ _targetLoc = RecordId();
+ _workingTowardRep = std::queue<size_t>();
}
+}
- PlanStageStats* AndSortedStage::getStats() {
- _commonStats.isEOF = isEOF();
+vector<PlanStage*> AndSortedStage::getChildren() const {
+ return _children;
+}
- unique_ptr<PlanStageStats> ret(new PlanStageStats(_commonStats, STAGE_AND_SORTED));
- ret->specific.reset(new AndSortedStats(_specificStats));
- for (size_t i = 0; i < _children.size(); ++i) {
- ret->children.push_back(_children[i]->getStats());
- }
+PlanStageStats* AndSortedStage::getStats() {
+ _commonStats.isEOF = isEOF();
- return ret.release();
+ unique_ptr<PlanStageStats> ret(new PlanStageStats(_commonStats, STAGE_AND_SORTED));
+ ret->specific.reset(new AndSortedStats(_specificStats));
+ for (size_t i = 0; i < _children.size(); ++i) {
+ ret->children.push_back(_children[i]->getStats());
}
- const CommonStats* AndSortedStage::getCommonStats() const {
- return &_commonStats;
- }
+ return ret.release();
+}
- const SpecificStats* AndSortedStage::getSpecificStats() const {
- return &_specificStats;
- }
+const CommonStats* AndSortedStage::getCommonStats() const {
+ return &_commonStats;
+}
+
+const SpecificStats* AndSortedStage::getSpecificStats() const {
+ return &_specificStats;
+}
} // namespace mongo