本文整理汇总了C++中MatchExpression::toString方法的典型用法代码示例。如果您正苦于以下问题:C++ MatchExpression::toString方法的具体用法?C++ MatchExpression::toString怎么用?C++ MatchExpression::toString使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类MatchExpression
的用法示例。
在下文中一共展示了MatchExpression::toString方法的11个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: planSubqueries
Status SubplanRunner::planSubqueries() {
MatchExpression* theOr = _query->root();
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.keyPattern] = i;
QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl;
}
const WhereCallbackReal whereCallback(_collection->ns().db());
for (size_t i = 0; i < theOr->numChildren(); ++i) {
// Turn the i-th child into its own query.
MatchExpression* orChild = theOr->getChild(i);
CanonicalQuery* orChildCQ;
Status childCQStatus = CanonicalQuery::canonicalize(*_query,
orChild,
&orChildCQ,
whereCallback);
if (!childCQStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Subplanner: Can't canonicalize subchild " << orChild->toString()
<< " " << childCQStatus.reason();
return Status(ErrorCodes::BadValue, ss);
}
// Make sure it gets cleaned up.
auto_ptr<CanonicalQuery> safeOrChildCQ(orChildCQ);
// Plan the i-th child.
vector<QuerySolution*> solutions;
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
QLOG() << "Subplanner: planning child " << i << " of " << theOr->numChildren();
Status status = QueryPlanner::plan(*safeOrChildCQ, _plannerParams, &solutions);
if (!status.isOK()) {
mongoutils::str::stream ss;
ss << "Subplanner: Can't plan for subchild " << orChildCQ->toString()
<< " " << status.reason();
return Status(ErrorCodes::BadValue, ss);
}
QLOG() << "Subplanner: got " << solutions.size() << " solutions";
if (0 == solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "Subplanner: No solutions for subchild " << orChildCQ->toString();
return Status(ErrorCodes::BadValue, ss);
}
// Hang onto the canonicalized subqueries and the corresponding query solutions
// so that they can be used in subplan running later on.
_cqs.push(safeOrChildCQ.release());
_solutions.push(solutions);
}
return Status::OK();
}
示例2: choosePlanForSubqueries
Status SubplanStage::choosePlanForSubqueries(PlanYieldPolicy* yieldPolicy) {
// This is what we annotate with the index selections and then turn into a solution.
auto_ptr<OrMatchExpression> orExpr(
static_cast<OrMatchExpression*>(_query->root()->shallowClone()));
// This is the skeleton of index selections that is inserted into the cache.
auto_ptr<PlanCacheIndexTree> cacheData(new PlanCacheIndexTree());
for (size_t i = 0; i < orExpr->numChildren(); ++i) {
MatchExpression* orChild = orExpr->getChild(i);
BranchPlanningResult* branchResult = _branchResults[i];
if (branchResult->cachedSolution.get()) {
// We can get the index tags we need out of the cache.
Status tagStatus = tagOrChildAccordingToCache(
cacheData.get(),
branchResult->cachedSolution->plannerData[0],
orChild,
_indexMap);
if (!tagStatus.isOK()) {
return tagStatus;
}
}
else if (1 == branchResult->solutions.size()) {
QuerySolution* soln = branchResult->solutions.front();
Status tagStatus = tagOrChildAccordingToCache(cacheData.get(),
soln->cacheData.get(),
orChild,
_indexMap);
if (!tagStatus.isOK()) {
return tagStatus;
}
}
else {
// N solutions, rank them.
// We already checked for zero solutions in planSubqueries(...).
invariant(!branchResult->solutions.empty());
_ws->clear();
_child.reset(new MultiPlanStage(_txn, _collection,
branchResult->canonicalQuery.get()));
MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(_child.get());
// Dump all the solutions into the MPS.
for (size_t ix = 0; ix < branchResult->solutions.size(); ++ix) {
PlanStage* nextPlanRoot;
invariant(StageBuilder::build(_txn,
_collection,
*branchResult->solutions[ix],
_ws,
&nextPlanRoot));
// Takes ownership of solution with index 'ix' and 'nextPlanRoot'.
multiPlanStage->addPlan(branchResult->solutions.releaseAt(ix),
nextPlanRoot,
_ws);
}
Status planSelectStat = multiPlanStage->pickBestPlan(yieldPolicy);
if (!planSelectStat.isOK()) {
return planSelectStat;
}
if (!multiPlanStage->bestPlanChosen()) {
mongoutils::str::stream ss;
ss << "Failed to pick best plan for subchild "
<< branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
QuerySolution* bestSoln = multiPlanStage->bestSolution();
// Check that we have good cache data. For example, we don't cache things
// for 2d indices.
if (NULL == bestSoln->cacheData.get()) {
mongoutils::str::stream ss;
ss << "No cache data for subchild " << orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
if (SolutionCacheData::USE_INDEX_TAGS_SOLN != bestSoln->cacheData->solnType) {
mongoutils::str::stream ss;
ss << "No indexed cache data for subchild "
<< orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
// Add the index assignments to our original query.
Status tagStatus = QueryPlanner::tagAccordingToCache(
orChild, bestSoln->cacheData->tree.get(), _indexMap);
if (!tagStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Failed to extract indices from subchild "
<< orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
//.........这里部分代码省略.........
示例3: planSubqueries
Status SubplanStage::planSubqueries() {
// Adds the amount of time taken by planSubqueries() to executionTimeMillis. There's lots of
// work that happens here, so this is needed for the time accounting to make sense.
ScopedTimer timer(&_commonStats.executionTimeMillis);
MatchExpression* orExpr = _query->root();
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.keyPattern] = i;
QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl;
}
const WhereCallbackReal whereCallback(_txn, _collection->ns().db());
for (size_t i = 0; i < orExpr->numChildren(); ++i) {
// We need a place to shove the results from planning this branch.
_branchResults.push_back(new BranchPlanningResult());
BranchPlanningResult* branchResult = _branchResults.back();
MatchExpression* orChild = orExpr->getChild(i);
// Turn the i-th child into its own query.
{
CanonicalQuery* orChildCQ;
Status childCQStatus = CanonicalQuery::canonicalize(*_query,
orChild,
&orChildCQ,
whereCallback);
if (!childCQStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Can't canonicalize subchild " << orChild->toString()
<< " " << childCQStatus.reason();
return Status(ErrorCodes::BadValue, ss);
}
branchResult->canonicalQuery.reset(orChildCQ);
}
// Plan the i-th child. We might be able to find a plan for the i-th child in the plan
// cache. If there's no cached plan, then we generate and rank plans using the MPS.
CachedSolution* rawCS;
if (PlanCache::shouldCacheQuery(*branchResult->canonicalQuery.get()) &&
_collection->infoCache()->getPlanCache()->get(*branchResult->canonicalQuery.get(),
&rawCS).isOK()) {
// We have a CachedSolution. Store it for later.
QLOG() << "Subplanner: cached plan found for child " << i << " of "
<< orExpr->numChildren();
branchResult->cachedSolution.reset(rawCS);
}
else {
// No CachedSolution found. We'll have to plan from scratch.
QLOG() << "Subplanner: planning child " << i << " of " << orExpr->numChildren();
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
Status status = QueryPlanner::plan(*branchResult->canonicalQuery.get(),
_plannerParams,
&branchResult->solutions.mutableVector());
if (!status.isOK()) {
mongoutils::str::stream ss;
ss << "Can't plan for subchild "
<< branchResult->canonicalQuery->toString()
<< " " << status.reason();
return Status(ErrorCodes::BadValue, ss);
}
QLOG() << "Subplanner: got " << branchResult->solutions.size() << " solutions";
if (0 == branchResult->solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "No solutions for subchild " << branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
}
}
return Status::OK();
}
示例4: choosePlanForSubqueries
Status SubplanStage::choosePlanForSubqueries(PlanYieldPolicy* yieldPolicy) {
// This is the skeleton of index selections that is inserted into the cache.
std::unique_ptr<PlanCacheIndexTree> cacheData(new PlanCacheIndexTree());
for (size_t i = 0; i < _orExpression->numChildren(); ++i) {
MatchExpression* orChild = _orExpression->getChild(i);
BranchPlanningResult* branchResult = _branchResults[i].get();
if (branchResult->cachedSolution.get()) {
// We can get the index tags we need out of the cache.
Status tagStatus = tagOrChildAccordingToCache(
cacheData.get(), branchResult->cachedSolution->plannerData[0], orChild, _indexMap);
if (!tagStatus.isOK()) {
return tagStatus;
}
} else if (1 == branchResult->solutions.size()) {
QuerySolution* soln = branchResult->solutions.front().get();
Status tagStatus = tagOrChildAccordingToCache(
cacheData.get(), soln->cacheData.get(), orChild, _indexMap);
if (!tagStatus.isOK()) {
return tagStatus;
}
} else {
// N solutions, rank them.
// We already checked for zero solutions in planSubqueries(...).
invariant(!branchResult->solutions.empty());
_ws->clear();
// We pass the SometimesCache option to the MPS because the SubplanStage currently does
// not use the CachedPlanStage's eviction mechanism. We therefore are more conservative
// about putting a potentially bad plan into the cache in the subplan path.
// We temporarily add the MPS to _children to ensure that we pass down all
// save/restore/invalidate messages that can be generated if pickBestPlan yields.
invariant(_children.empty());
_children.emplace_back(
stdx::make_unique<MultiPlanStage>(getOpCtx(),
_collection,
branchResult->canonicalQuery.get(),
MultiPlanStage::CachingMode::SometimesCache));
ON_BLOCK_EXIT([&] {
invariant(_children.size() == 1); // Make sure nothing else was added to _children.
_children.pop_back();
});
MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(child().get());
// Dump all the solutions into the MPS.
for (size_t ix = 0; ix < branchResult->solutions.size(); ++ix) {
PlanStage* nextPlanRoot;
invariant(StageBuilder::build(getOpCtx(),
_collection,
*branchResult->canonicalQuery,
*branchResult->solutions[ix],
_ws,
&nextPlanRoot));
// Takes ownership of 'nextPlanRoot'.
multiPlanStage->addPlan(std::move(branchResult->solutions[ix]), nextPlanRoot, _ws);
}
Status planSelectStat = multiPlanStage->pickBestPlan(yieldPolicy);
if (!planSelectStat.isOK()) {
return planSelectStat;
}
if (!multiPlanStage->bestPlanChosen()) {
mongoutils::str::stream ss;
ss << "Failed to pick best plan for subchild "
<< branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
QuerySolution* bestSoln = multiPlanStage->bestSolution();
// Check that we have good cache data. For example, we don't cache things
// for 2d indices.
if (NULL == bestSoln->cacheData.get()) {
mongoutils::str::stream ss;
ss << "No cache data for subchild " << orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
if (SolutionCacheData::USE_INDEX_TAGS_SOLN != bestSoln->cacheData->solnType) {
mongoutils::str::stream ss;
ss << "No indexed cache data for subchild " << orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
// Add the index assignments to our original query.
Status tagStatus = QueryPlanner::tagAccordingToCache(
orChild, bestSoln->cacheData->tree.get(), _indexMap);
if (!tagStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Failed to extract indices from subchild " << orChild->toString();
return Status(ErrorCodes::BadValue, ss);
}
cacheData->children.push_back(bestSoln->cacheData->tree->clone());
//.........这里部分代码省略.........
示例5: planSubqueries
Status SubplanStage::planSubqueries() {
_orExpression = _query->root()->shallowClone();
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.name] = i;
LOG(5) << "Subplanner: index " << i << " is " << ie;
}
for (size_t i = 0; i < _orExpression->numChildren(); ++i) {
// We need a place to shove the results from planning this branch.
_branchResults.push_back(stdx::make_unique<BranchPlanningResult>());
BranchPlanningResult* branchResult = _branchResults.back().get();
MatchExpression* orChild = _orExpression->getChild(i);
// Turn the i-th child into its own query.
auto statusWithCQ = CanonicalQuery::canonicalize(getOpCtx(), *_query, orChild);
if (!statusWithCQ.isOK()) {
mongoutils::str::stream ss;
ss << "Can't canonicalize subchild " << orChild->toString() << " "
<< statusWithCQ.getStatus().reason();
return Status(ErrorCodes::BadValue, ss);
}
branchResult->canonicalQuery = std::move(statusWithCQ.getValue());
// Plan the i-th child. We might be able to find a plan for the i-th child in the plan
// cache. If there's no cached plan, then we generate and rank plans using the MPS.
const auto* planCache = _collection->infoCache()->getPlanCache();
if (auto cachedSol = planCache->getCacheEntryIfCacheable(*branchResult->canonicalQuery)) {
// We have a CachedSolution. Store it for later.
LOG(5) << "Subplanner: cached plan found for child " << i << " of "
<< _orExpression->numChildren();
branchResult->cachedSolution = std::move(cachedSol);
} else {
// No CachedSolution found. We'll have to plan from scratch.
LOG(5) << "Subplanner: planning child " << i << " of " << _orExpression->numChildren();
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
invariant(branchResult->solutions.empty());
auto solutions = QueryPlanner::plan(*branchResult->canonicalQuery, _plannerParams);
if (!solutions.isOK()) {
mongoutils::str::stream ss;
ss << "Can't plan for subchild " << branchResult->canonicalQuery->toString() << " "
<< solutions.getStatus().reason();
return Status(ErrorCodes::BadValue, ss);
}
branchResult->solutions = std::move(solutions.getValue());
LOG(5) << "Subplanner: got " << branchResult->solutions.size() << " solutions";
if (0 == branchResult->solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "No solutions for subchild " << branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
}
}
return Status::OK();
}
示例6: plan
// static
Status QueryPlanner::plan(const CanonicalQuery& query,
const QueryPlannerParams& params,
std::vector<QuerySolution*>* out) {
LOG(5) << "Beginning planning..." << endl
<< "=============================" << endl
<< "Options = " << optionString(params.options) << endl
<< "Canonical query:" << endl
<< query.toString() << "=============================" << endl;
for (size_t i = 0; i < params.indices.size(); ++i) {
LOG(5) << "Index " << i << " is " << params.indices[i].toString() << endl;
}
bool canTableScan = !(params.options & QueryPlannerParams::NO_TABLE_SCAN);
// If the query requests a tailable cursor, the only solution is a collscan + filter with
// tailable set on the collscan. TODO: This is a policy departure. Previously I think you
// could ask for a tailable cursor and it just tried to give you one. Now, we fail if we
// can't provide one. Is this what we want?
if (query.getParsed().isTailable()) {
if (!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR) && canTableScan) {
QuerySolution* soln = buildCollscanSoln(query, true, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return Status::OK();
}
// The hint or sort can be $natural: 1. If this happens, output a collscan. If both
// a $natural hint and a $natural sort are specified, then the direction of the collscan
// is determined by the sign of the sort (not the sign of the hint).
if (!query.getParsed().getHint().isEmpty() || !query.getParsed().getSort().isEmpty()) {
BSONObj hintObj = query.getParsed().getHint();
BSONObj sortObj = query.getParsed().getSort();
BSONElement naturalHint = hintObj.getFieldDotted("$natural");
BSONElement naturalSort = sortObj.getFieldDotted("$natural");
// A hint overrides a $natural sort. This means that we don't force a table
// scan if there is a $natural sort with a non-$natural hint.
if (!naturalHint.eoo() || (!naturalSort.eoo() && hintObj.isEmpty())) {
LOG(5) << "Forcing a table scan due to hinted $natural\n";
// min/max are incompatible with $natural.
if (canTableScan && query.getParsed().getMin().isEmpty() &&
query.getParsed().getMax().isEmpty()) {
QuerySolution* soln = buildCollscanSoln(query, false, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return Status::OK();
}
}
// Figure out what fields we care about.
unordered_set<string> fields;
QueryPlannerIXSelect::getFields(query.root(), "", &fields);
for (unordered_set<string>::const_iterator it = fields.begin(); it != fields.end(); ++it) {
LOG(5) << "Predicate over field '" << *it << "'" << endl;
}
// Filter our indices so we only look at indices that are over our predicates.
vector<IndexEntry> relevantIndices;
// Hints require us to only consider the hinted index.
// If index filters in the query settings were used to override
// the allowed indices for planning, we should not use the hinted index
// requested in the query.
BSONObj hintIndex;
if (!params.indexFiltersApplied) {
hintIndex = query.getParsed().getHint();
}
// Snapshot is a form of a hint. If snapshot is set, try to use _id index to make a real
// plan. If that fails, just scan the _id index.
if (query.getParsed().isSnapshot()) {
// Find the ID index in indexKeyPatterns. It's our hint.
for (size_t i = 0; i < params.indices.size(); ++i) {
if (isIdIndex(params.indices[i].keyPattern)) {
hintIndex = params.indices[i].keyPattern;
break;
}
}
}
size_t hintIndexNumber = numeric_limits<size_t>::max();
if (hintIndex.isEmpty()) {
QueryPlannerIXSelect::findRelevantIndices(fields, params.indices, &relevantIndices);
} else {
// Sigh. If the hint is specified it might be using the index name.
BSONElement firstHintElt = hintIndex.firstElement();
if (str::equals("$hint", firstHintElt.fieldName()) && String == firstHintElt.type()) {
string hintName = firstHintElt.String();
for (size_t i = 0; i < params.indices.size(); ++i) {
if (params.indices[i].name == hintName) {
LOG(5) << "Hint by name specified, restricting indices to "
<< params.indices[i].keyPattern.toString() << endl;
//.........这里部分代码省略.........
示例7: plan
// static
void QueryPlanner::plan(const CanonicalQuery& query,
const QueryPlannerParams& params,
vector<QuerySolution*>* out) {
QLOG() << "=============================\n"
<< "Beginning planning, options = " << optionString(params.options) << endl
<< "Canonical query:\n" << query.toString() << endl
<< "============================="
<< endl;
// The shortcut formerly known as IDHACK. See if it's a simple _id query. If so we might
// just make an ixscan over the _id index and bypass the rest of planning entirely.
if (!query.getParsed().isExplain() && !query.getParsed().showDiskLoc()
&& isSimpleIdQuery(query.getParsed().getFilter())
&& !query.getParsed().hasOption(QueryOption_CursorTailable)) {
// See if we can find an _id index.
for (size_t i = 0; i < params.indices.size(); ++i) {
if (isIdIndex(params.indices[i].keyPattern)) {
const IndexEntry& index = params.indices[i];
QLOG() << "IDHACK using index " << index.toString() << endl;
// If so, we make a simple scan to find the doc.
IndexScanNode* isn = new IndexScanNode();
isn->indexKeyPattern = index.keyPattern;
isn->indexIsMultiKey = index.multikey;
isn->direction = 1;
isn->bounds.isSimpleRange = true;
BSONObj key = getKeyFromQuery(index.keyPattern, query.getParsed().getFilter());
isn->bounds.startKey = isn->bounds.endKey = key;
isn->bounds.endKeyInclusive = true;
isn->computeProperties();
QuerySolution* soln = QueryPlannerAnalysis::analyzeDataAccess(query, params, isn);
if (NULL != soln) {
out->push_back(soln);
QLOG() << "IDHACK solution is:\n" << (*out)[0]->toString() << endl;
// And that's it.
return;
}
}
}
}
for (size_t i = 0; i < params.indices.size(); ++i) {
QLOG() << "idx " << i << " is " << params.indices[i].toString() << endl;
}
bool canTableScan = !(params.options & QueryPlannerParams::NO_TABLE_SCAN);
// If the query requests a tailable cursor, the only solution is a collscan + filter with
// tailable set on the collscan. TODO: This is a policy departure. Previously I think you
// could ask for a tailable cursor and it just tried to give you one. Now, we fail if we
// can't provide one. Is this what we want?
if (query.getParsed().hasOption(QueryOption_CursorTailable)) {
if (!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR)
&& canTableScan) {
QuerySolution* soln = buildCollscanSoln(query, true, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return;
}
// The hint can be $natural: 1. If this happens, output a collscan. It's a weird way of
// saying "table scan for two, please."
if (!query.getParsed().getHint().isEmpty()) {
BSONElement natural = query.getParsed().getHint().getFieldDotted("$natural");
if (!natural.eoo()) {
QLOG() << "forcing a table scan due to hinted $natural\n";
if (canTableScan) {
QuerySolution* soln = buildCollscanSoln(query, false, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return;
}
}
// NOR and NOT we can't handle well with indices. If we see them here, they weren't
// rewritten to remove the negation. Just output a collscan for those.
if (QueryPlannerCommon::hasNode(query.root(), MatchExpression::NOT)
|| QueryPlannerCommon::hasNode(query.root(), MatchExpression::NOR)) {
// If there's a near predicate, we can't handle this.
// TODO: Should canonicalized query detect this?
if (QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR)) {
warning() << "Can't handle NOT/NOR with GEO_NEAR";
return;
}
QLOG() << "NOT/NOR in plan, just outtping a collscan\n";
if (canTableScan) {
QuerySolution* soln = buildCollscanSoln(query, false, params);
if (NULL != soln) {
out->push_back(soln);
}
}
//.........这里部分代码省略.........
示例8: runSubplans
bool SubplanRunner::runSubplans() {
// This is what we annotate with the index selections and then turn into a solution.
auto_ptr<OrMatchExpression> theOr(
static_cast<OrMatchExpression*>(_query->root()->shallowClone()));
// This is the skeleton of index selections that is inserted into the cache.
auto_ptr<PlanCacheIndexTree> cacheData(new PlanCacheIndexTree());
for (size_t i = 0; i < theOr->numChildren(); ++i) {
MatchExpression* orChild = theOr->getChild(i);
auto_ptr<CanonicalQuery> orChildCQ(_cqs.front());
_cqs.pop();
// 'solutions' is owned by the SubplanRunner instance until
// it is popped from the queue.
vector<QuerySolution*> solutions = _solutions.front();
_solutions.pop();
// We already checked for zero solutions in planSubqueries(...).
invariant(!solutions.empty());
if (1 == solutions.size()) {
// There is only one solution. Transfer ownership to an auto_ptr.
auto_ptr<QuerySolution> autoSoln(solutions[0]);
// We want a well-formed *indexed* solution.
if (NULL == autoSoln->cacheData.get()) {
// For example, we don't cache things for 2d indices.
QLOG() << "Subplanner: No cache data for subchild " << orChild->toString();
return false;
}
if (SolutionCacheData::USE_INDEX_TAGS_SOLN != autoSoln->cacheData->solnType) {
QLOG() << "Subplanner: No indexed cache data for subchild "
<< orChild->toString();
return false;
}
// Add the index assignments to our original query.
Status tagStatus = QueryPlanner::tagAccordingToCache(
orChild, autoSoln->cacheData->tree.get(), _indexMap);
if (!tagStatus.isOK()) {
QLOG() << "Subplanner: Failed to extract indices from subchild "
<< orChild->toString();
return false;
}
// Add the child's cache data to the cache data we're creating for the main query.
cacheData->children.push_back(autoSoln->cacheData->tree->clone());
}
else {
// N solutions, rank them. Takes ownership of orChildCQ.
// the working set will be shared by the candidate plans and owned by the runner
WorkingSet* sharedWorkingSet = new WorkingSet();
MultiPlanStage* multiPlanStage = new MultiPlanStage(_collection,
orChildCQ.get());
// Dump all the solutions into the MPR.
for (size_t ix = 0; ix < solutions.size(); ++ix) {
PlanStage* nextPlanRoot;
verify(StageBuilder::build(_txn,
_collection,
*solutions[ix],
sharedWorkingSet,
&nextPlanRoot));
// Owns first two arguments
multiPlanStage->addPlan(solutions[ix], nextPlanRoot, sharedWorkingSet);
}
multiPlanStage->pickBestPlan();
if (! multiPlanStage->bestPlanChosen()) {
QLOG() << "Subplanner: Failed to pick best plan for subchild "
<< orChildCQ->toString();
return false;
}
Runner* mpr = new SingleSolutionRunner(_collection,
orChildCQ.release(),
multiPlanStage->bestSolution(),
multiPlanStage,
sharedWorkingSet);
_underlyingRunner.reset(mpr);
if (_killed) {
QLOG() << "Subplanner: Killed while picking best plan for subchild "
<< orChild->toString();
return false;
}
QuerySolution* bestSoln = multiPlanStage->bestSolution();
if (SolutionCacheData::USE_INDEX_TAGS_SOLN != bestSoln->cacheData->solnType) {
QLOG() << "Subplanner: No indexed cache data for subchild "
<< orChild->toString();
//.........这里部分代码省略.........
示例9: planSubqueries
Status SubplanStage::planSubqueries() {
_orExpression = _query->root()->shallowClone();
if (isContainedOr(_orExpression.get())) {
_orExpression = rewriteToRootedOr(std::move(_orExpression));
invariant(CanonicalQuery::isValid(_orExpression.get(), _query->getParsed()).isOK());
}
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.keyPattern] = i;
LOG(5) << "Subplanner: index " << i << " is " << ie.toString();
}
const ExtensionsCallbackReal extensionsCallback(getOpCtx(), &_collection->ns());
for (size_t i = 0; i < _orExpression->numChildren(); ++i) {
// We need a place to shove the results from planning this branch.
_branchResults.push_back(new BranchPlanningResult());
BranchPlanningResult* branchResult = _branchResults.back();
MatchExpression* orChild = _orExpression->getChild(i);
// Turn the i-th child into its own query.
auto statusWithCQ = CanonicalQuery::canonicalize(*_query, orChild, extensionsCallback);
if (!statusWithCQ.isOK()) {
mongoutils::str::stream ss;
ss << "Can't canonicalize subchild " << orChild->toString() << " "
<< statusWithCQ.getStatus().reason();
return Status(ErrorCodes::BadValue, ss);
}
branchResult->canonicalQuery = std::move(statusWithCQ.getValue());
// Plan the i-th child. We might be able to find a plan for the i-th child in the plan
// cache. If there's no cached plan, then we generate and rank plans using the MPS.
CachedSolution* rawCS;
if (PlanCache::shouldCacheQuery(*branchResult->canonicalQuery) &&
_collection->infoCache()
->getPlanCache()
->get(*branchResult->canonicalQuery, &rawCS)
.isOK()) {
// We have a CachedSolution. Store it for later.
LOG(5) << "Subplanner: cached plan found for child " << i << " of "
<< _orExpression->numChildren();
branchResult->cachedSolution.reset(rawCS);
} else {
// No CachedSolution found. We'll have to plan from scratch.
LOG(5) << "Subplanner: planning child " << i << " of " << _orExpression->numChildren();
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
Status status = QueryPlanner::plan(*branchResult->canonicalQuery,
_plannerParams,
&branchResult->solutions.mutableVector());
if (!status.isOK()) {
mongoutils::str::stream ss;
ss << "Can't plan for subchild " << branchResult->canonicalQuery->toString() << " "
<< status.reason();
return Status(ErrorCodes::BadValue, ss);
}
LOG(5) << "Subplanner: got " << branchResult->solutions.size() << " solutions";
if (0 == branchResult->solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "No solutions for subchild " << branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
}
}
return Status::OK();
}
示例10: plan
// static
Status QueryPlanner::plan(const CanonicalQuery& query,
const QueryPlannerParams& params,
std::vector<QuerySolution*>* out) {
QLOG() << "=============================\n"
<< "Beginning planning, options = " << optionString(params.options) << endl
<< "Canonical query:\n" << query.toString() << endl
<< "============================="
<< endl;
for (size_t i = 0; i < params.indices.size(); ++i) {
QLOG() << "idx " << i << " is " << params.indices[i].toString() << endl;
}
bool canTableScan = !(params.options & QueryPlannerParams::NO_TABLE_SCAN);
// If the query requests a tailable cursor, the only solution is a collscan + filter with
// tailable set on the collscan. TODO: This is a policy departure. Previously I think you
// could ask for a tailable cursor and it just tried to give you one. Now, we fail if we
// can't provide one. Is this what we want?
if (query.getParsed().hasOption(QueryOption_CursorTailable)) {
if (!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR)
&& canTableScan) {
QuerySolution* soln = buildCollscanSoln(query, true, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return Status::OK();
}
// The hint can be $natural: 1. If this happens, output a collscan. It's a weird way of
// saying "table scan for two, please."
if (!query.getParsed().getHint().isEmpty()) {
BSONElement natural = query.getParsed().getHint().getFieldDotted("$natural");
if (!natural.eoo()) {
QLOG() << "forcing a table scan due to hinted $natural\n";
// min/max are incompatible with $natural.
if (canTableScan && query.getParsed().getMin().isEmpty()
&& query.getParsed().getMax().isEmpty()) {
QuerySolution* soln = buildCollscanSoln(query, false, params);
if (NULL != soln) {
out->push_back(soln);
}
}
return Status::OK();
}
}
// Figure out what fields we care about.
unordered_set<string> fields;
QueryPlannerIXSelect::getFields(query.root(), "", &fields);
for (unordered_set<string>::const_iterator it = fields.begin(); it != fields.end(); ++it) {
QLOG() << "predicate over field " << *it << endl;
}
// Filter our indices so we only look at indices that are over our predicates.
vector<IndexEntry> relevantIndices;
// Hints require us to only consider the hinted index.
BSONObj hintIndex = query.getParsed().getHint();
// Snapshot is a form of a hint. If snapshot is set, try to use _id index to make a real
// plan. If that fails, just scan the _id index.
if (query.getParsed().isSnapshot()) {
// Find the ID index in indexKeyPatterns. It's our hint.
for (size_t i = 0; i < params.indices.size(); ++i) {
if (isIdIndex(params.indices[i].keyPattern)) {
hintIndex = params.indices[i].keyPattern;
break;
}
}
}
size_t hintIndexNumber = numeric_limits<size_t>::max();
if (hintIndex.isEmpty()) {
QueryPlannerIXSelect::findRelevantIndices(fields, params.indices, &relevantIndices);
}
else {
// Sigh. If the hint is specified it might be using the index name.
BSONElement firstHintElt = hintIndex.firstElement();
if (str::equals("$hint", firstHintElt.fieldName()) && String == firstHintElt.type()) {
string hintName = firstHintElt.String();
for (size_t i = 0; i < params.indices.size(); ++i) {
if (params.indices[i].name == hintName) {
QLOG() << "hint by name specified, restricting indices to "
<< params.indices[i].keyPattern.toString() << endl;
relevantIndices.clear();
relevantIndices.push_back(params.indices[i]);
hintIndexNumber = i;
hintIndex = params.indices[i].keyPattern;
break;
}
}
}
else {
for (size_t i = 0; i < params.indices.size(); ++i) {
//.........这里部分代码省略.........
示例11: planFromCache
// 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");
}