Runner::RunnerState SubplanRunner::getNext(BSONObj* objOut, DiskLoc* dlOut) { if (_killed) { return Runner::RUNNER_DEAD; } if (isEOF()) { return Runner::RUNNER_EOF; } if (SubplanRunner::PLANNING == _state) { // Try to run as sub-plans. if (runSubplans()) { // If runSubplans returns true we expect something here. invariant(_underlyingRunner.get()); } else if (!_killed) { // Couldn't run as subplans so we'll just call normal getRunner. Runner* runner; Status status = getRunnerAlwaysPlan( _txn, _collection, _query.release(), _plannerParams, &runner ); if (!status.isOK()) { // We utterly failed. _killed = true; // Propagate the error to the user wrapped in a BSONObj if (NULL != objOut) { BSONObjBuilder bob; bob.append("ok", status.isOK() ? 1.0 : 0.0); bob.append("code", status.code()); bob.append("errmsg", status.reason()); *objOut = bob.obj(); } return Runner::RUNNER_ERROR; } else { _underlyingRunner.reset(runner); } } // We can change state when we're either killed or we have an underlying runner. invariant(_killed || NULL != _underlyingRunner.get()); _state = SubplanRunner::RUNNING; } if (_killed) { return Runner::RUNNER_DEAD; } if (isEOF()) { return Runner::RUNNER_EOF; } // If we're here we should have planned already. invariant(SubplanRunner::RUNNING == _state); invariant(_underlyingRunner.get()); return _underlyingRunner->getNext(objOut, dlOut); }
PlanStage::StageState SubplanStage::work(WorkingSetID* out) { ++_commonStats.works; // Adds the amount of time taken by work() to executionTimeMillis. ScopedTimer timer(&_commonStats.executionTimeMillis); if (_killed) { return PlanStage::DEAD; } if (isEOF()) { return PlanStage::IS_EOF; } if (SubplanStage::PLANNING == _state) { // Try to run as sub-plans. if (runSubplans()) { // If runSubplans returns true we expect something here. invariant(_child.get()); } else if (!_killed) { // Couldn't run as subplans so we'll just call normal getExecutor. PlanExecutor* exec; Status status = getExecutorAlwaysPlan(_collection, _query, _plannerParams, &exec); if (!status.isOK()) { // We utterly failed. _killed = true; // Propagate the error to the user wrapped in a BSONObj WorkingSetID id = _ws->allocate(); WorkingSetMember* member = _ws->get(id); member->state = WorkingSetMember::OWNED_OBJ; member->keyData.clear(); member->loc = DiskLoc(); BSONObjBuilder bob; bob.append("ok", status.isOK() ? 1.0 : 0.0); bob.append("code", status.code()); bob.append("errmsg", status.reason()); member->obj = bob.obj(); *out = id; return PlanStage::FAILURE; } else { scoped_ptr<PlanExecutor> cleanupExec(exec); _child.reset(exec->releaseStages()); } } // We can change state when we're either killed or we have an underlying runner. invariant(_killed || NULL != _child.get()); _state = SubplanStage::RUNNING; } if (_killed) { return PlanStage::DEAD; } if (isEOF()) { return PlanStage::IS_EOF; } // If we're here we should have planned already. invariant(SubplanStage::RUNNING == _state); invariant(_child.get()); return _child->work(out); }