diff options
author | Denis Grebennicov <denis.grebennicov@mongodb.com> | 2022-07-18 13:58:29 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-07-18 14:58:30 +0000 |
commit | 460f9e9ecdd209f68d2271241a8bc3b04d8f59d7 (patch) | |
tree | bec449121246aa4765b68396e9aed46b811f5fc4 | |
parent | acaf6284d48691bdea40e64d3fef142c6a011b13 (diff) | |
download | mongo-460f9e9ecdd209f68d2271241a8bc3b04d8f59d7.tar.gz |
SERVER-66935 Invalidate $lookup plan cache when foreign collection size changes
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index c6a54e26102..9ee8ae7dc7b 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -1248,7 +1248,7 @@ std::unique_ptr<sbe::RuntimePlanner> makeRuntimePlannerIfNeeded( bool needsSubplanning, PlanYieldPolicySBE* yieldPolicy, size_t plannerOptions, - const stage_builder::PlanStageData& planStageData) { + const boost::optional<stage_builder::PlanStageData>& planStageData) { // If we have multiple solutions, we always need to do the runtime planning. if (numSolutions > 1) { invariant(!needsSubplanning && !decisionWorks); @@ -1283,7 +1283,8 @@ std::unique_ptr<sbe::RuntimePlanner> makeRuntimePlannerIfNeeded( // If we have a single solution and the plan is not pinned or plan contains a hash_lookup stage, // we will need we will need to do the runtime planning to check if the cached plan still // performs efficiently, or requires re-planning. - const bool hasHashLookup = !planStageData.foreignHashJoinCollections.empty(); + tassert(6693503, "PlanStageData must be present", planStageData); + const bool hasHashLookup = !planStageData->foreignHashJoinCollections.empty(); if (decisionWorks || hasHashLookup) { QueryPlannerParams plannerParams; plannerParams.options = plannerOptions; @@ -1336,6 +1337,12 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getSlotBasedExe auto&& planningResult = planningResultWithStatus.getValue(); auto&& [roots, solutions] = planningResult->extractResultData(); + + // When query requires sub-planning, we may not get any executable plans. + const auto planStageData = roots.empty() + ? boost::none + : boost::optional<stage_builder::PlanStageData>(roots[0].second); + // In some circumstances (e.g. when have multiple candidate plans or using a cached one), we // might need to execute the plan(s) to pick the best one or to confirm the choice. if (auto planner = makeRuntimePlannerIfNeeded(opCtx, @@ -1346,7 +1353,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getSlotBasedExe planningResult->needsSubplanning(), yieldPolicy.get(), plannerParams.options, - roots[0].second)) { + planStageData)) { // Do the runtime planning and pick the best candidate plan. auto candidates = planner->plan(std::move(solutions), std::move(roots)); |