summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorHaley Connelly <haley.connelly@10gen.com>2018-08-13 10:15:38 -0400
committerHaley Connelly <haley.connelly@10gen.com>2018-08-13 10:16:22 -0400
commit1ce4c3db9f598a5c0988362a6908d9b83c07e94f (patch)
tree65f8dd10a32230218423f87adc5f10b79cf5b31c /src/mongo
parentec6f2a54d8b901e95e556d53647944be8ce441d5 (diff)
downloadmongo-1ce4c3db9f598a5c0988362a6908d9b83c07e94f.tar.gz
SERVER-35980 Experimental new output format for planCacheListPlans
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp79
-rw-r--r--src/mongo/db/query/explain.h34
-rw-r--r--src/mongo/db/query/query_knobs.cpp2
-rw-r--r--src/mongo/db/query/query_knobs.h3
4 files changed, 79 insertions, 39 deletions
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index 3c1d6a00a6a..15616a20cf8 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -357,30 +357,15 @@ Status PlanCacheListPlans::runPlanCacheCommand(OperationContext* opCtx,
AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns));
PlanCache* planCache;
- Status status = getPlanCache(opCtx, ctx.getCollection(), ns, &planCache);
- if (!status.isOK()) {
- // No collection - return empty plans array.
- BSONArrayBuilder plansBuilder(bob->subarrayStart("plans"));
- plansBuilder.doneFast();
- return Status::OK();
- }
+ uassertStatusOK(getPlanCache(opCtx, ctx.getCollection(), ns, &planCache));
return list(opCtx, *planCache, ns, cmdObj, bob);
}
-// static
-Status PlanCacheListPlans::list(OperationContext* opCtx,
- const PlanCache& planCache,
- const std::string& ns,
- const BSONObj& cmdObj,
- BSONObjBuilder* bob) {
- auto statusWithCQ = canonicalize(opCtx, ns, cmdObj);
- if (!statusWithCQ.isOK()) {
- return statusWithCQ.getStatus();
- }
- unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
-
+namespace {
+Status listPlansOriginalFormat(std::unique_ptr<CanonicalQuery> cq,
+ const PlanCache& planCache,
+ BSONObjBuilder* bob) {
auto lookupResult = planCache.getEntry(*cq);
-
if (lookupResult == ErrorCodes::NoSuchKey) {
// Return empty plans in results if query shape does not
// exist in plan cache.
@@ -390,9 +375,11 @@ Status PlanCacheListPlans::list(OperationContext* opCtx,
} else if (!lookupResult.isOK()) {
return lookupResult.getStatus();
}
- std::unique_ptr<PlanCacheEntry> entry = std::move(lookupResult.getValue());
+
+ auto entry = std::move(lookupResult.getValue());
BSONArrayBuilder plansBuilder(bob->subarrayStart("plans"));
+
size_t numPlans = entry->plannerData.size();
invariant(numPlans == entry->decision->stats.size());
invariant(numPlans == entry->decision->scores.size());
@@ -442,7 +429,57 @@ Status PlanCacheListPlans::list(OperationContext* opCtx,
// Append whether or not the entry is active.
bob->append("isActive", entry->isActive);
bob->append("works", static_cast<long long>(entry->works));
+ return Status::OK();
+}
+} // namespace
+// static
+Status PlanCacheListPlans::list(OperationContext* opCtx,
+ const PlanCache& planCache,
+ const std::string& ns,
+ const BSONObj& cmdObj,
+ BSONObjBuilder* bob) {
+ auto statusWithCQ = canonicalize(opCtx, ns, cmdObj);
+ if (!statusWithCQ.isOK()) {
+ return statusWithCQ.getStatus();
+ }
+
+ if (!internalQueryCacheListPlansNewOutput.load())
+ return listPlansOriginalFormat(std::move(statusWithCQ.getValue()), planCache, bob);
+
+ unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
+ auto entry = uassertStatusOK(planCache.getEntry(*cq));
+
+ // internalQueryCacheDisableInactiveEntries is True and we should use the new output format.
+ BSONObjBuilder shapeBuilder(bob->subobjStart("createdFromQuery"));
+ shapeBuilder.append("query", entry->query);
+ shapeBuilder.append("sort", entry->sort);
+ shapeBuilder.append("projection", entry->projection);
+ if (!entry->collation.isEmpty()) {
+ shapeBuilder.append("collation", entry->collation);
+ }
+ shapeBuilder.doneFast();
+ bob->append("queryHash", unsignedIntToFixedLengthHex(entry->queryHash));
+
+ // Append whether or not the entry is active.
+ bob->append("isActive", entry->isActive);
+ bob->append("works", static_cast<long long>(entry->works));
+
+ BSONObjBuilder cachedPlanBob(bob->subobjStart("cachedPlan"));
+ Explain::statsToBSON(
+ *entry->decision->stats[0], &cachedPlanBob, ExplainOptions::Verbosity::kQueryPlanner);
+ cachedPlanBob.doneFast();
+
+ bob->append("timeOfCreation", entry->timeOfCreation);
+
+ BSONArrayBuilder creationBuilder(bob->subarrayStart("creationExecStats"));
+ for (auto&& stat : entry->decision->stats) {
+ BSONObjBuilder planBob(creationBuilder.subobjStart());
+ Explain::generateSinglePlanExecutionInfo(
+ stat.get(), ExplainOptions::Verbosity::kExecAllPlans, boost::none, &planBob);
+ planBob.doneFast();
+ }
+ creationBuilder.doneFast();
return Status::OK();
}
diff --git a/src/mongo/db/query/explain.h b/src/mongo/db/query/explain.h
index cb177321f1c..451ffabe219 100644
--- a/src/mongo/db/query/explain.h
+++ b/src/mongo/db/query/explain.h
@@ -164,6 +164,22 @@ public:
**/
static std::unique_ptr<PlanStageStats> getWinningPlanTrialStats(PlanExecutor* exec);
+ /**
+ * Generates the execution stats section for the stats tree 'stats', adding the resulting BSON
+ * to 'out'.
+ *
+ * The 'totalTimeMillis' value passed here will be added to the top level of the execution stats
+ * section, but will not affect the reporting of timing for individual stages. If
+ * 'totalTimeMillis' is not set, we use the approximate timing information collected by the
+ * stages.
+ *
+ * Stats are generated at the verbosity specified by 'verbosity'.
+ **/
+ static void generateSinglePlanExecutionInfo(const PlanStageStats* stats,
+ ExplainOptions::Verbosity verbosity,
+ boost::optional<long long> totalTimeMillis,
+ BSONObjBuilder* out);
+
private:
/**
* Adds the 'queryPlanner' explain section to the BSON object being built
@@ -207,24 +223,6 @@ private:
BSONObjBuilder* out);
/**
- * Generates the execution stats section for the stats tree 'stats',
- * adding the resulting BSON to 'out'.
- *
- * The 'totalTimeMillis' value passed here will be added to the top level of
- * the execution stats section, but will not affect the reporting of timing for
- * individual stages. If 'totalTimeMillis' is not set, we use the approximate timing
- * information collected by the stages.
- *
- * Stats are generated at the verbosity specified by 'verbosity'.
- *
- * This is a helper for generating explain BSON. It is used by generateExecutionInfo().
- */
- static void generateSinglePlanExecutionInfo(const PlanStageStats* stats,
- ExplainOptions::Verbosity verbosity,
- boost::optional<long long> totalTimeMillis,
- BSONObjBuilder* out);
-
- /**
* Adds the 'serverInfo' explain section to the BSON object being build
* by 'out'.
*
diff --git a/src/mongo/db/query/query_knobs.cpp b/src/mongo/db/query/query_knobs.cpp
index 3f002ddf784..4d59a177c2e 100644
--- a/src/mongo/db/query/query_knobs.cpp
+++ b/src/mongo/db/query/query_knobs.cpp
@@ -55,6 +55,8 @@ MONGO_EXPORT_SERVER_PARAMETER(internalQueryCacheWorksGrowthCoefficient, double,
MONGO_EXPORT_SERVER_PARAMETER(internalQueryCacheDisableInactiveEntries, bool, false);
+MONGO_EXPORT_SERVER_PARAMETER(internalQueryCacheListPlansNewOutput, bool, false);
+
MONGO_EXPORT_SERVER_PARAMETER(internalQueryPlannerMaxIndexedSolutions, int, 64);
MONGO_EXPORT_SERVER_PARAMETER(internalQueryEnumerationMaxOrSolutions, int, 10);
diff --git a/src/mongo/db/query/query_knobs.h b/src/mongo/db/query/query_knobs.h
index b0c6849b2ea..d7f6ab8d1c4 100644
--- a/src/mongo/db/query/query_knobs.h
+++ b/src/mongo/db/query/query_knobs.h
@@ -79,6 +79,9 @@ extern AtomicDouble internalQueryCacheWorksGrowthCoefficient;
// Whether or not cache entries can be marked as "inactive."
extern AtomicBool internalQueryCacheDisableInactiveEntries;
+// Whether or not planCacheListPlans uses the new output format.
+extern AtomicBool internalQueryCacheListPlansNewOutput;
+
//
// Planning and enumeration.
//