Beispiel #1
0
PlanStage::StageState SortKeyGeneratorStage::doWork(WorkingSetID* out) {
    if (!_sortKeyGen) {
        _sortKeyGen = stdx::make_unique<SortKeyGenerator>(getOpCtx(), _sortSpec, _query);
        return PlanStage::NEED_TIME;
    }

    auto stageState = child()->work(out);
    if (stageState == PlanStage::ADVANCED) {
        WorkingSetMember* member = _ws->get(*out);

        BSONObj sortKey;
        Status sortKeyStatus = _sortKeyGen->getSortKey(*member, &sortKey);
        if (!sortKeyStatus.isOK()) {
            *out = WorkingSetCommon::allocateStatusMember(_ws, sortKeyStatus);
            return PlanStage::FAILURE;
        }

        // Add the sort key to the WSM as computed data.
        member->addComputed(new SortKeyComputedData(sortKey));

        return PlanStage::ADVANCED;
    }

    if (stageState == PlanStage::IS_EOF) {
        _commonStats.isEOF = true;
    }

    return stageState;
}
StatusWith<ClusterQueryResult> RouterStageAggregationMerge::next() {
    // Pipeline::getNext will return a boost::optional<Document> or boost::none if EOF.
    if (auto result = _mergePipeline->getNext()) {
        return {result->toBson()};
    }

    // If we reach this point, we have hit EOF.
    _mergePipeline.get_deleter().dismissDisposal();
    _mergePipeline->dispose(getOpCtx());

    return {ClusterQueryResult()};
}
Beispiel #3
0
boost::optional<IndexKeyEntry> IndexScan::initIndexScan() {
    if (_params.doNotDedup) {
        _shouldDedup = false;
    } else {
        // TODO it is incorrect to rely on this not changing. SERVER-17678
        _shouldDedup = _params.descriptor->isMultikey(getOpCtx());
    }

    // Perform the possibly heavy-duty initialization of the underlying index cursor.
    _indexCursor = _iam->newCursor(getOpCtx(), _forward);

    // We always seek once to establish the cursor position.
    ++_specificStats.seeks;

    if (_params.bounds.isSimpleRange) {
        // Start at one key, end at another.
        _endKey = _params.bounds.endKey;
        _endKeyInclusive = _params.bounds.endKeyInclusive;
        _indexCursor->setEndPosition(_endKey, _endKeyInclusive);
        return _indexCursor->seek(_params.bounds.startKey, /*inclusive*/ true);
    } else {
        // For single intervals, we can use an optimized scan which checks against the position
        // of an end cursor.  For all other index scans, we fall back on using
        // IndexBoundsChecker to determine when we've finished the scan.
        BSONObj startKey;
        bool startKeyInclusive;
        if (IndexBoundsBuilder::isSingleInterval(
                _params.bounds, &startKey, &startKeyInclusive, &_endKey, &_endKeyInclusive)) {
            _indexCursor->setEndPosition(_endKey, _endKeyInclusive);
            return _indexCursor->seek(startKey, startKeyInclusive);
        } else {
            _checker.reset(new IndexBoundsChecker(&_params.bounds, _keyPattern, _params.direction));

            if (!_checker->getStartSeekPoint(&_seekPoint))
                return boost::none;

            return _indexCursor->seek(_seekPoint);
        }
    }
}
Beispiel #4
0
IndexScan::IndexScan(OperationContext* txn,
                     const IndexScanParams& params,
                     WorkingSet* workingSet,
                     const MatchExpression* filter)
    : PlanStage(kStageType, txn),
      _workingSet(workingSet),
      _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)),
      _keyPattern(params.descriptor->keyPattern().getOwned()),
      _scanState(INITIALIZING),
      _filter(filter),
      _shouldDedup(true),
      _forward(params.direction == 1),
      _params(params),
      _endKeyInclusive(false) {
    // We can't always access the descriptor in the call to getStats() so we pull
    // any info we need for stats reporting out here.
    _specificStats.keyPattern = _keyPattern;
    _specificStats.indexName = _params.descriptor->indexName();
    _specificStats.isMultiKey = _params.descriptor->isMultikey(getOpCtx());
    _specificStats.isUnique = _params.descriptor->unique();
    _specificStats.isSparse = _params.descriptor->isSparse();
    _specificStats.isPartial = _params.descriptor->isPartial();
    _specificStats.indexVersion = _params.descriptor->version();
}
Beispiel #5
0
Status CachedPlanStage::replan(PlanYieldPolicy* yieldPolicy, bool shouldCache) {
    // We're going to start over with a new plan. Clear out info from our old plan.
    _results.clear();
    _ws->clear();
    _children.clear();

    // Use the query planning module to plan the whole query.
    std::vector<QuerySolution*> rawSolutions;
    Status status = QueryPlanner::plan(*_canonicalQuery, _plannerParams, &rawSolutions);
    if (!status.isOK()) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "error processing query: " << _canonicalQuery->toString()
                                    << " planner returned error: " << status.reason());
    }

    OwnedPointerVector<QuerySolution> solutions(rawSolutions);

    // We cannot figure out how to answer the query.  Perhaps it requires an index
    // we do not have?
    if (0 == solutions.size()) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "error processing query: " << _canonicalQuery->toString()
                                    << " No query solutions");
    }

    if (1 == solutions.size()) {
        // If there's only one solution, it won't get cached. Make sure to evict the existing
        // cache entry if requested by the caller.
        if (shouldCache) {
            PlanCache* cache = _collection->infoCache()->getPlanCache();
            cache->remove(*_canonicalQuery);
        }

        PlanStage* newRoot;
        // Only one possible plan. Build the stages from the solution.
        verify(StageBuilder::build(
            getOpCtx(), _collection, *_canonicalQuery, *solutions[0], _ws, &newRoot));
        _children.emplace_back(newRoot);
        _replannedQs.reset(solutions.popAndReleaseBack());

        LOG(1)
            << "Replanning of query resulted in single query solution, which will not be cached. "
            << _canonicalQuery->toStringShort()
            << " plan summary after replan: " << Explain::getPlanSummary(child().get())
            << " previous cache entry evicted: " << (shouldCache ? "yes" : "no");
        return Status::OK();
    }

    // Many solutions. Create a MultiPlanStage to pick the best, update the cache,
    // and so on. The working set will be shared by all candidate plans.
    auto cachingMode = shouldCache ? MultiPlanStage::CachingMode::AlwaysCache
                                   : MultiPlanStage::CachingMode::NeverCache;
    _children.emplace_back(
        new MultiPlanStage(getOpCtx(), _collection, _canonicalQuery, cachingMode));
    MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(child().get());

    for (size_t ix = 0; ix < solutions.size(); ++ix) {
        if (solutions[ix]->cacheData.get()) {
            solutions[ix]->cacheData->indexFilterApplied = _plannerParams.indexFiltersApplied;
        }

        PlanStage* nextPlanRoot;
        verify(StageBuilder::build(
            getOpCtx(), _collection, *_canonicalQuery, *solutions[ix], _ws, &nextPlanRoot));

        // Takes ownership of 'solutions[ix]' and 'nextPlanRoot'.
        multiPlanStage->addPlan(solutions.releaseAt(ix), nextPlanRoot, _ws);
    }

    // Delegate to the MultiPlanStage's plan selection facility.
    Status pickBestPlanStatus = multiPlanStage->pickBestPlan(yieldPolicy);
    if (!pickBestPlanStatus.isOK()) {
        return pickBestPlanStatus;
    }

    LOG(1) << "Replanning " << _canonicalQuery->toStringShort()
           << " resulted in plan with summary: " << Explain::getPlanSummary(child().get())
           << ", which " << (shouldCache ? "has" : "has not") << " been written to the cache";
    return Status::OK();
}
void RouterStageAggregationMerge::doReattachToOperationContext() {
    _mergePipeline->reattachToOperationContext(getOpCtx());
}
Beispiel #7
0
void IndexScan::doReattachToOperationContext() {
    if (_indexCursor)
        _indexCursor->reattachToOperationContext(getOpCtx());
}