コード例 #1
0
ファイル: subplan_runner.cpp プロジェクト: MohdVara/mongo
    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);
    }
コード例 #2
0
ファイル: get_runner.cpp プロジェクト: hshinde/mongo
    /**
     * For a given query, get a runner.  The runner could be a SingleSolutionRunner, a
     * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc.
     */
    Status getRunner(Collection* collection,
                     CanonicalQuery* rawCanonicalQuery,
                     Runner** out,
                     size_t plannerOptions) {

        verify(rawCanonicalQuery);
        auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery);

        // This can happen as we're called by internal clients as well.
        if (NULL == collection) {
            const string& ns = canonicalQuery->ns();
            LOG(2) << "Collection " << ns << " does not exist."
                   << " Using EOF runner: " << canonicalQuery->toStringShort();
            *out = new EOFRunner(canonicalQuery.release(), ns);
            return Status::OK();
        }

        // If we have an _id index we can use the idhack runner.
        if (IDHackRunner::supportsQuery(*canonicalQuery) &&
            collection->getIndexCatalog()->findIdIndex()) {
            LOG(2) << "Using idhack: " << canonicalQuery->toStringShort();
            *out = new IDHackRunner(collection, canonicalQuery.release());
            return Status::OK();
        }

        // Tailable: If the query requests tailable the collection must be capped.
        if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) {
            if (!collection->isCapped()) {
                return Status(ErrorCodes::BadValue,
                              "error processing query: " + canonicalQuery->toString() +
                              " tailable cursor requested on non capped collection");
            }

            // If a sort is specified it must be equal to expectedSort.
            const BSONObj expectedSort = BSON("$natural" << 1);
            const BSONObj& actualSort = canonicalQuery->getParsed().getSort();
            if (!actualSort.isEmpty() && !(actualSort == expectedSort)) {
                return Status(ErrorCodes::BadValue,
                              "error processing query: " + canonicalQuery->toString() +
                              " invalid sort specified for tailable cursor: "
                              + actualSort.toString());
            }
        }

        // Fill out the planning params.  We use these for both cached solutions and non-cached.
        QueryPlannerParams plannerParams;
        plannerParams.options = plannerOptions;
        fillOutPlannerParams(collection, rawCanonicalQuery, &plannerParams);

        // See if the cache has what we're looking for.
        Status cacheStatus = getRunnerFromCache(canonicalQuery.get(),
                                                collection,
                                                plannerParams,
                                                out);

        // This can be not-OK and we can carry on.  It just means the query wasn't cached.
        if (cacheStatus.isOK()) {
            // We got a cached runner.
            canonicalQuery.release();
            return cacheStatus;
        }

        if (internalQueryPlanOrChildrenIndependently
            && SubplanRunner::canUseSubplanRunner(*canonicalQuery)) {

            QLOG() << "Running query as sub-queries: " << canonicalQuery->toStringShort();
            LOG(2) << "Running query as sub-queries: " << canonicalQuery->toStringShort();

            SubplanRunner* runner;
            Status runnerStatus = SubplanRunner::make(collection, plannerParams,
                                                      canonicalQuery.release(), &runner);
            if (!runnerStatus.isOK()) {
                return runnerStatus;
            }

            *out = runner;
            return Status::OK();
        }

        return getRunnerAlwaysPlan(collection, canonicalQuery.release(), plannerParams, out);
    }
コード例 #3
0
ファイル: get_runner.cpp プロジェクト: Robbie1977/mongo
/**
 * For a given query, get a runner.
 */
Status getRunner(Collection* collection,
                 CanonicalQuery* rawCanonicalQuery,
                 Runner** out,
                 size_t plannerOptions) {

    verify(rawCanonicalQuery);
    auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery);

    // This can happen as we're called by internal clients as well.
    if (NULL == collection) {
        const string& ns = canonicalQuery->ns();
        LOG(2) << "Collection " << ns << " does not exist."
               << " Using EOF runner: " << canonicalQuery->toStringShort();
        *out = new EOFRunner(canonicalQuery.release(), ns);
        return Status::OK();
    }

    // If we have an _id index we can use the idhack runner.
    if (IDHackRunner::supportsQuery(*canonicalQuery) &&
            collection->getIndexCatalog()->findIdIndex()) {
        LOG(2) << "Using idhack: " << canonicalQuery->toStringShort();
        *out = new IDHackRunner(collection, canonicalQuery.release());
        return Status::OK();
    }

    // Tailable: If the query requests tailable the collection must be capped.
    if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) {
        if (!collection->isCapped()) {
            return Status(ErrorCodes::BadValue,
                          "error processing query: " + canonicalQuery->toString() +
                          " tailable cursor requested on non capped collection");
        }

        // If a sort is specified it must be equal to expectedSort.
        const BSONObj expectedSort = BSON("$natural" << 1);
        const BSONObj& actualSort = canonicalQuery->getParsed().getSort();
        if (!actualSort.isEmpty() && !(actualSort == expectedSort)) {
            return Status(ErrorCodes::BadValue,
                          "error processing query: " + canonicalQuery->toString() +
                          " invalid sort specified for tailable cursor: "
                          + actualSort.toString());
        }
    }

    // Fill out the planning params.  We use these for both cached solutions and non-cached.
    QueryPlannerParams plannerParams;
    plannerParams.options = plannerOptions;
    fillOutPlannerParams(collection, rawCanonicalQuery, &plannerParams);

    // Try to look up a cached solution for the query.

    CachedSolution* rawCS;
    if (PlanCache::shouldCacheQuery(*canonicalQuery) &&
            collection->infoCache()->getPlanCache()->get(*canonicalQuery, &rawCS).isOK()) {
        // We have a CachedSolution.  Have the planner turn it into a QuerySolution.
        boost::scoped_ptr<CachedSolution> cs(rawCS);
        QuerySolution *qs, *backupQs;
        QuerySolution*& chosenSolution=qs; // either qs or backupQs
        Status status = QueryPlanner::planFromCache(*canonicalQuery, plannerParams, *cs,
                        &qs, &backupQs);

        if (status.isOK()) {
            // the working set will be shared by the root and backupRoot plans
            // and owned by the containing single-solution-runner
            //
            WorkingSet* sharedWs = new WorkingSet();

            PlanStage *root, *backupRoot=NULL;
            verify(StageBuilder::build(collection, *qs, sharedWs, &root));
            if ((plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT)
                    && turnIxscanIntoCount(qs)) {
                LOG(2) << "Using fast count: " << canonicalQuery->toStringShort()
                       << ", planSummary: " << getPlanSummary(*qs);

                if (NULL != backupQs) {
                    delete backupQs;
                }
            }
            else if (NULL != backupQs) {
                verify(StageBuilder::build(collection, *backupQs, sharedWs, &backupRoot));
            }

            // add a CachedPlanStage on top of the previous root
            root = new CachedPlanStage(collection, rawCanonicalQuery, root, backupRoot);

            *out = new SingleSolutionRunner(collection,
                                            canonicalQuery.release(),
                                            chosenSolution, root, sharedWs);
            return Status::OK();
        }
    }

    if (internalQueryPlanOrChildrenIndependently
            && SubplanRunner::canUseSubplanRunner(*canonicalQuery)) {

        QLOG() << "Running query as sub-queries: " << canonicalQuery->toStringShort();
        LOG(2) << "Running query as sub-queries: " << canonicalQuery->toStringShort();

        SubplanRunner* runner;
        Status runnerStatus = SubplanRunner::make(collection, plannerParams,
                              canonicalQuery.release(), &runner);
        if (!runnerStatus.isOK()) {
            return runnerStatus;
        }

        *out = runner;
        return Status::OK();
    }

    return getRunnerAlwaysPlan(collection, canonicalQuery.release(), plannerParams, out);
}