コード例 #1
0
ファイル: query_planner.cpp プロジェクト: Benguang/mongo
    // static
    Status QueryPlanner::tagAccordingToCache(MatchExpression* filter,
                                             const PlanCacheIndexTree* const indexTree,
                                             const map<BSONObj, size_t>& indexMap) {
        if (NULL == filter) {
            return Status(ErrorCodes::BadValue, "Cannot tag tree: filter is NULL.");
        }
        if (NULL == indexTree) {
            return Status(ErrorCodes::BadValue, "Cannot tag tree: indexTree is NULL.");
        }

        // We're tagging the tree here, so it shouldn't have
        // any tags hanging off yet.
        verify(NULL == filter->getTag());

        if (filter->numChildren() != indexTree->children.size()) {
            mongoutils::str::stream ss;
            ss << "Cache topology and query did not match: "
               << "query has " << filter->numChildren() << " children "
               << "and cache has " << indexTree->children.size() << " children.";
            return Status(ErrorCodes::BadValue, ss);
        }

        // Continue the depth-first tree traversal.
        for (size_t i = 0; i < filter->numChildren(); ++i) {
            Status s = tagAccordingToCache(filter->getChild(i), indexTree->children[i], indexMap);
            if (!s.isOK()) {
                return s;
            }
        }

        if (NULL != indexTree->entry.get()) {
            map<BSONObj, size_t>::const_iterator got = indexMap.find(indexTree->entry->keyPattern);
            if (got == indexMap.end()) {
                mongoutils::str::stream ss;
                ss << "Did not find index with keyPattern: " << indexTree->entry->keyPattern.toString();
                return Status(ErrorCodes::BadValue, ss);
            }
            filter->setTag(new IndexTag(got->second, indexTree->index_pos));
        }

        return Status::OK();
    }
コード例 #2
0
ファイル: query_planner.cpp プロジェクト: i80and/mongo
StatusWith<std::unique_ptr<QuerySolution>> QueryPlanner::planFromCache(
    const CanonicalQuery& query,
    const QueryPlannerParams& params,
    const CachedSolution& cachedSoln) {
    invariant(!cachedSoln.plannerData.empty());

    // A query not suitable for caching should not have made its way into the cache.
    invariant(PlanCache::shouldCacheQuery(query));

    // Look up winning solution in cached solution's array.
    const SolutionCacheData& winnerCacheData = *cachedSoln.plannerData[0];

    if (SolutionCacheData::WHOLE_IXSCAN_SOLN == winnerCacheData.solnType) {
        // The solution can be constructed by a scan over the entire index.
        auto soln = buildWholeIXSoln(
            *winnerCacheData.tree->entry, query, params, winnerCacheData.wholeIXSolnDir);
        if (!soln) {
            return Status(ErrorCodes::BadValue,
                          "plan cache error: soln that uses index to provide sort");
        } else {
            return {std::move(soln)};
        }
    } else if (SolutionCacheData::COLLSCAN_SOLN == winnerCacheData.solnType) {
        // The cached solution is a collection scan. We don't cache collscans
        // with tailable==true, hence the false below.
        auto soln = buildCollscanSoln(query, false, params);
        if (!soln) {
            return Status(ErrorCodes::BadValue, "plan cache error: collection scan soln");
        } else {
            return {std::move(soln)};
        }
    }

    // SolutionCacheData::USE_TAGS_SOLN == cacheData->solnType
    // If we're here then this is neither the whole index scan or collection scan
    // cases, and we proceed by using the PlanCacheIndexTree to tag the query tree.

    // Create a copy of the expression tree.  We use cachedSoln to annotate this with indices.
    unique_ptr<MatchExpression> clone = query.root()->shallowClone();

    LOG(5) << "Tagging the match expression according to cache data: " << endl
           << "Filter:" << endl
           << redact(clone->toString()) << "Cache data:" << endl
           << redact(winnerCacheData.toString());

    // Map from index name to index number.
    // TODO: can we assume that the index numbering has the same lifetime
    // as the cache state?
    map<StringData, size_t> indexMap;
    for (size_t i = 0; i < params.indices.size(); ++i) {
        const IndexEntry& ie = params.indices[i];
        indexMap[ie.name] = i;
        LOG(5) << "Index " << i << ": " << ie.name;
    }

    Status s = tagAccordingToCache(clone.get(), winnerCacheData.tree.get(), indexMap);
    if (!s.isOK()) {
        return s;
    }

    // The MatchExpression tree is in canonical order. We must order the nodes for access planning.
    prepareForAccessPlanning(clone.get());

    LOG(5) << "Tagged tree:" << endl << redact(clone->toString());

    // Use the cached index assignments to build solnRoot.
    std::unique_ptr<QuerySolutionNode> solnRoot(QueryPlannerAccess::buildIndexedDataAccess(
        query, clone.release(), false, params.indices, params));

    if (!solnRoot) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "Failed to create data access plan from cache. Query: "
                                    << query.toStringShort());
    }

    auto soln = QueryPlannerAnalysis::analyzeDataAccess(query, params, std::move(solnRoot));
    if (!soln) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "Failed to analyze plan from cache. Query: "
                                    << query.toStringShort());
    }

    LOG(5) << "Planner: solution constructed from the cache:\n" << redact(soln->toString());
    return {std::move(soln)};
}
コード例 #3
0
ファイル: query_planner.cpp プロジェクト: i80and/mongo
// static
Status QueryPlanner::tagAccordingToCache(MatchExpression* filter,
                                         const PlanCacheIndexTree* const indexTree,
                                         const map<StringData, size_t>& indexMap) {
    if (NULL == filter) {
        return Status(ErrorCodes::BadValue, "Cannot tag tree: filter is NULL.");
    }
    if (NULL == indexTree) {
        return Status(ErrorCodes::BadValue, "Cannot tag tree: indexTree is NULL.");
    }

    // We're tagging the tree here, so it shouldn't have
    // any tags hanging off yet.
    verify(NULL == filter->getTag());

    if (filter->numChildren() != indexTree->children.size()) {
        mongoutils::str::stream ss;
        ss << "Cache topology and query did not match: "
           << "query has " << filter->numChildren() << " children "
           << "and cache has " << indexTree->children.size() << " children.";
        return Status(ErrorCodes::BadValue, ss);
    }

    // Continue the depth-first tree traversal.
    for (size_t i = 0; i < filter->numChildren(); ++i) {
        Status s = tagAccordingToCache(filter->getChild(i), indexTree->children[i], indexMap);
        if (!s.isOK()) {
            return s;
        }
    }

    if (!indexTree->orPushdowns.empty()) {
        filter->setTag(new OrPushdownTag());
        OrPushdownTag* orPushdownTag = static_cast<OrPushdownTag*>(filter->getTag());
        for (const auto& orPushdown : indexTree->orPushdowns) {
            auto index = indexMap.find(orPushdown.indexName);
            if (index == indexMap.end()) {
                return Status(ErrorCodes::BadValue,
                              str::stream() << "Did not find index with name: "
                                            << orPushdown.indexName);
            }
            OrPushdownTag::Destination dest;
            dest.route = orPushdown.route;
            dest.tagData = stdx::make_unique<IndexTag>(
                index->second, orPushdown.position, orPushdown.canCombineBounds);
            orPushdownTag->addDestination(std::move(dest));
        }
    }

    if (indexTree->entry.get()) {
        map<StringData, size_t>::const_iterator got = indexMap.find(indexTree->entry->name);
        if (got == indexMap.end()) {
            mongoutils::str::stream ss;
            ss << "Did not find index with name: " << indexTree->entry->name;
            return Status(ErrorCodes::BadValue, ss);
        }
        if (filter->getTag()) {
            OrPushdownTag* orPushdownTag = static_cast<OrPushdownTag*>(filter->getTag());
            orPushdownTag->setIndexTag(
                new IndexTag(got->second, indexTree->index_pos, indexTree->canCombineBounds));
        } else {
            filter->setTag(
                new IndexTag(got->second, indexTree->index_pos, indexTree->canCombineBounds));
        }
    }

    return Status::OK();
}
コード例 #4
0
ファイル: query_planner.cpp プロジェクト: Benguang/mongo
    // static
    Status QueryPlanner::planFromCache(const CanonicalQuery& query,
                                       const QueryPlannerParams& params,
                                       const SolutionCacheData& cacheData,
                                       QuerySolution** out) {
        if (SolutionCacheData::WHOLE_IXSCAN_SOLN == cacheData.solnType) {
            // The solution can be constructed by a scan over the entire index.
            QuerySolution* soln = buildWholeIXSoln(*cacheData.tree->entry,
                                                   query,
                                                   params,
                                                   cacheData.wholeIXSolnDir);
            if (soln == NULL) {
                return Status(ErrorCodes::BadValue,
                              "plan cache error: soln that uses index to provide sort");
            }
            else {
                *out = soln;
                return Status::OK();
            }
        }
        else if (SolutionCacheData::COLLSCAN_SOLN == cacheData.solnType) {
            // The cached solution is a collection scan. We don't cache collscans
            // with tailable==true, hence the false below.
            QuerySolution* soln = buildCollscanSoln(query, false, params);
            if (soln == NULL) {
                return Status(ErrorCodes::BadValue, "plan cache error: collection scan soln");
            }
            else {
                *out = soln;
                return Status::OK();
            }
        }

        // SolutionCacheData::USE_TAGS_SOLN == cacheData->solnType
        // If we're here then this is neither the whole index scan or collection scan
        // cases, and we proceed by using the PlanCacheIndexTree to tag the query tree.

        // Create a copy of the expression tree.  We use cachedSoln to annotate this with indices.
        MatchExpression* clone = query.root()->shallowClone();

        QLOG() << "Tagging the match expression according to cache data: " << endl
               << "Filter:" << endl << clone->toString()
               << "Cache data:" << endl << cacheData.toString();

        // Map from index name to index number.
        // TODO: can we assume that the index numbering has the same lifetime
        // as the cache state?
        map<BSONObj, size_t> indexMap;
        for (size_t i = 0; i < params.indices.size(); ++i) {
            const IndexEntry& ie = params.indices[i];
            indexMap[ie.keyPattern] = i;
            QLOG() << "Index " << i << ": " << ie.keyPattern.toString() << endl;
        }

        Status s = tagAccordingToCache(clone, cacheData.tree.get(), indexMap);
        if (!s.isOK()) {
            return s;
        }

        // The planner requires a defined sort order.
        sortUsingTags(clone);

        QLOG() << "Tagged tree:" << endl << clone->toString();

        // Use the cached index assignments to build solnRoot.  Takes ownership of clone.
        QuerySolutionNode* solnRoot =
            QueryPlannerAccess::buildIndexedDataAccess(query, clone, false, params.indices);

        if (NULL != solnRoot) {
            // Takes ownership of 'solnRoot'.
            QuerySolution* soln = QueryPlannerAnalysis::analyzeDataAccess(query,
                                                                          params,
                                                                          solnRoot);
            if (NULL != soln) {
                QLOG() << "Planner: solution constructed from the cache:\n" << soln->toString() << endl;
                *out = soln;
                return Status::OK();
            }
        }

        return Status(ErrorCodes::BadValue, "couldn't plan from cache");
    }