summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaley Connelly <haley.connelly@10gen.com>2018-08-02 17:18:32 -0400
committerHaley Connelly <haley.connelly@10gen.com>2018-08-02 17:18:38 -0400
commitba50688792f3f038271af9edb3d0207691f6f63b (patch)
treeaedb8f9caf4c12852426ff332324de81c33d154f /src
parente68e228f0ebc6c70b808c173cedbda2b7dcfc87c (diff)
downloadmongo-ba50688792f3f038271af9edb3d0207691f6f63b.tar.gz
SERVER-35981 Include hash of plan cache key in planCacheListShapes and planCacheListPlans
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/index_filter_commands_test.cpp8
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp12
-rw-r--r--src/mongo/db/commands/plan_cache_commands_test.cpp27
-rw-r--r--src/mongo/db/query/plan_cache.cpp28
-rw-r--r--src/mongo/db/query/plan_cache.h18
-rw-r--r--src/mongo/db/query/plan_cache_test.cpp4
6 files changed, 58 insertions, 39 deletions
diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp
index f9c6fb51f70..ffc0419616d 100644
--- a/src/mongo/db/commands/index_filter_commands_test.cpp
+++ b/src/mongo/db/commands/index_filter_commands_test.cpp
@@ -167,13 +167,11 @@ bool planCacheContains(OperationContext* opCtx,
unique_ptr<CanonicalQuery> inputQuery = std::move(statusWithInputQuery.getValue());
// Retrieve cache entries from plan cache.
- vector<PlanCacheEntry*> entries = planCache.getAllEntries();
+ auto entries = planCache.getAllEntries();
// Search keys.
bool found = false;
- for (vector<PlanCacheEntry*>::const_iterator i = entries.begin(); i != entries.end(); i++) {
- PlanCacheEntry* entry = *i;
-
+ for (auto&& entry : entries) {
// Canonicalizing query shape in cache entry to get cache key.
// Alternatively, we could add key to PlanCacheEntry but that would be used in one place
// only.
@@ -189,8 +187,6 @@ bool planCacheContains(OperationContext* opCtx,
if (planCache.computeKey(*currentQuery) == planCache.computeKey(*inputQuery)) {
found = true;
}
- // Release resources for cache entry after extracting key.
- delete entry;
}
return found;
}
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index 9237700b70b..1210588d066 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/query/explain.h"
#include "mongo/db/query/plan_ranker.h"
+#include "mongo/util/hex.h"
#include "mongo/util/log.h"
namespace {
@@ -246,11 +247,10 @@ Status PlanCacheListQueryShapes::list(const PlanCache& planCache, BSONObjBuilder
invariant(bob);
// Fetch all cached solutions from plan cache.
- vector<PlanCacheEntry*> solutions = planCache.getAllEntries();
+ auto entries = planCache.getAllEntries();
BSONArrayBuilder arrayBuilder(bob->subarrayStart("shapes"));
- for (vector<PlanCacheEntry*>::const_iterator i = solutions.begin(); i != solutions.end(); i++) {
- PlanCacheEntry* entry = *i;
+ for (auto&& entry : entries) {
invariant(entry);
BSONObjBuilder shapeBuilder(arrayBuilder.subobjStart());
@@ -260,10 +260,8 @@ Status PlanCacheListQueryShapes::list(const PlanCache& planCache, BSONObjBuilder
if (!entry->collation.isEmpty()) {
shapeBuilder.append("collation", entry->collation);
}
+ shapeBuilder.append("queryHash", unsignedIntToFixedLengthHex(entry->queryHash));
shapeBuilder.doneFast();
-
- // Release resources for cached solution after extracting query shape.
- delete entry;
}
arrayBuilder.doneFast();
@@ -440,7 +438,7 @@ Status PlanCacheListPlans::list(OperationContext* opCtx,
// Append the time the entry was inserted into the plan cache.
bob->append("timeOfCreation", entry->timeOfCreation);
-
+ 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));
diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp
index 89f0cc8b0f0..a540d9c68db 100644
--- a/src/mongo/db/commands/plan_cache_commands_test.cpp
+++ b/src/mongo/db/commands/plan_cache_commands_test.cpp
@@ -348,11 +348,13 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
<< cqB->getQueryRequest().getProj());
ASSERT_TRUE(
std::find_if(shapesBefore.begin(), shapesBefore.end(), [&shapeA](const BSONObj& obj) {
- return SimpleBSONObjComparator::kInstance.evaluate(shapeA == obj);
+ auto filteredObj = obj.removeField("queryHash");
+ return SimpleBSONObjComparator::kInstance.evaluate(shapeA == filteredObj);
}) != shapesBefore.end());
ASSERT_TRUE(
std::find_if(shapesBefore.begin(), shapesBefore.end(), [&shapeB](const BSONObj& obj) {
- return SimpleBSONObjComparator::kInstance.evaluate(shapeB == obj);
+ auto filteredObj = obj.removeField("queryHash");
+ return SimpleBSONObjComparator::kInstance.evaluate(shapeB == filteredObj);
}) != shapesBefore.end());
// Drop {b: 1} from cache. Make sure {a: 1} is still in cache afterwards.
@@ -362,7 +364,8 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
opCtx.get(), &planCache, nss.ns(), BSON("query" << cqB->getQueryObj())));
vector<BSONObj> shapesAfter = getShapes(planCache);
ASSERT_EQUALS(shapesAfter.size(), 1U);
- ASSERT_BSONOBJ_EQ(shapesAfter[0], shapeA);
+ auto filteredShape0 = shapesAfter[0].removeField("queryHash");
+ ASSERT_BSONOBJ_EQ(filteredShape0, shapeA);
}
TEST(PlanCacheCommandsTest, planCacheClearOneKeyCollation) {
@@ -414,13 +417,16 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKeyCollation) {
<< cqCollation->getCollator()->getSpec().toBSON());
ASSERT_TRUE(
std::find_if(shapesBefore.begin(), shapesBefore.end(), [&shape](const BSONObj& obj) {
- return SimpleBSONObjComparator::kInstance.evaluate(shape == obj);
+ auto filteredObj = obj.removeField("queryHash");
+ return SimpleBSONObjComparator::kInstance.evaluate(shape == filteredObj);
}) != shapesBefore.end());
- ASSERT_TRUE(
- std::find_if(
- shapesBefore.begin(), shapesBefore.end(), [&shapeWithCollation](const BSONObj& obj) {
- return SimpleBSONObjComparator::kInstance.evaluate(shapeWithCollation == obj);
- }) != shapesBefore.end());
+ ASSERT_TRUE(std::find_if(shapesBefore.begin(),
+ shapesBefore.end(),
+ [&shapeWithCollation](const BSONObj& obj) {
+ auto filteredObj = obj.removeField("queryHash");
+ return SimpleBSONObjComparator::kInstance.evaluate(
+ shapeWithCollation == filteredObj);
+ }) != shapesBefore.end());
// Drop query with collation from cache. Make other query is still in cache afterwards.
BSONObjBuilder bob;
@@ -428,7 +434,8 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKeyCollation) {
ASSERT_OK(PlanCacheClear::clear(opCtx.get(), &planCache, nss.ns(), shapeWithCollation));
vector<BSONObj> shapesAfter = getShapes(planCache);
ASSERT_EQUALS(shapesAfter.size(), 1U);
- ASSERT_BSONOBJ_EQ(shapesAfter[0], shape);
+ auto filteredShape0 = shapesAfter[0].removeField("queryHash");
+ ASSERT_BSONOBJ_EQ(filteredShape0, shape);
}
/**
diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp
index eb8ca720a1b..9e4fb5edf93 100644
--- a/src/mongo/db/query/plan_cache.cpp
+++ b/src/mongo/db/query/plan_cache.cpp
@@ -38,6 +38,7 @@
#include <vector>
#include "mongo/base/owned_pointer_vector.h"
+#include "mongo/base/simple_string_data_comparator.h"
#include "mongo/base/string_data_comparator_interface.h"
#include "mongo/db/matcher/expression_array.h"
#include "mongo/db/matcher/expression_geo.h"
@@ -392,8 +393,9 @@ CachedSolution::~CachedSolution() {
//
PlanCacheEntry::PlanCacheEntry(const std::vector<QuerySolution*>& solutions,
- PlanRankingDecision* why)
- : plannerData(solutions.size()), decision(why) {
+ PlanRankingDecision* why,
+ uint32_t queryHash)
+ : plannerData(solutions.size()), queryHash(queryHash), decision(why) {
invariant(why);
// The caller of this constructor is responsible for ensuring
@@ -424,7 +426,7 @@ PlanCacheEntry* PlanCacheEntry::clone() const {
solutions.push_back(std::move(qs));
}
PlanCacheEntry* entry = new PlanCacheEntry(
- transitional_tools_do_not_use::unspool_vector(solutions), decision->clone());
+ transitional_tools_do_not_use::unspool_vector(solutions), decision->clone(), queryHash);
// Copy query shape.
entry->query = query.getOwned();
@@ -835,7 +837,8 @@ Status PlanCache::set(const CanonicalQuery& query,
isNewEntryActive = newState.shouldBeActive;
}
- auto newEntry = std::make_unique<PlanCacheEntry>(solns, why.release());
+ uint32_t queryHash = computeQueryHash(key);
+ auto newEntry = std::make_unique<PlanCacheEntry>(solns, why.release(), queryHash);
const QueryRequest& qr = query.getQueryRequest();
newEntry->query = qr.getFilter().getOwned();
newEntry->sort = qr.getSort().getOwned();
@@ -846,7 +849,6 @@ Status PlanCache::set(const CanonicalQuery& query,
}
newEntry->timeOfCreation = now;
-
// Strip projections on $-prefixed fields, as these are added by internal callers of the query
// system and are not considered part of the user projection.
BSONObjBuilder projBuilder;
@@ -947,6 +949,10 @@ PlanCacheKey PlanCache::computeKey(const CanonicalQuery& cq) const {
return keyBuilder.str();
}
+uint32_t PlanCache::computeQueryHash(const PlanCacheKey& key) {
+ return SimpleStringDataComparator::kInstance.hash(key);
+}
+
StatusWith<std::unique_ptr<PlanCacheEntry>> PlanCache::getEntry(const CanonicalQuery& query) const {
PlanCacheKey key = computeKey(query);
@@ -961,13 +967,13 @@ StatusWith<std::unique_ptr<PlanCacheEntry>> PlanCache::getEntry(const CanonicalQ
return std::unique_ptr<PlanCacheEntry>(entry->clone());
}
-std::vector<PlanCacheEntry*> PlanCache::getAllEntries() const {
+std::vector<std::unique_ptr<PlanCacheEntry>> PlanCache::getAllEntries() const {
stdx::lock_guard<stdx::mutex> cacheLock(_cacheMutex);
- std::vector<PlanCacheEntry*> entries;
- typedef std::list<std::pair<PlanCacheKey, PlanCacheEntry*>>::const_iterator ConstIterator;
- for (ConstIterator i = _cache.begin(); i != _cache.end(); i++) {
- PlanCacheEntry* entry = i->second;
- entries.push_back(entry->clone());
+ std::vector<std::unique_ptr<PlanCacheEntry>> entries;
+
+ for (auto&& cacheEntry : _cache) {
+ auto entry = cacheEntry.second;
+ entries.push_back(std::unique_ptr<PlanCacheEntry>(entry->clone()));
}
return entries;
diff --git a/src/mongo/db/query/plan_cache.h b/src/mongo/db/query/plan_cache.h
index 6fb9d97eda2..729cdafed3a 100644
--- a/src/mongo/db/query/plan_cache.h
+++ b/src/mongo/db/query/plan_cache.h
@@ -237,7 +237,9 @@ public:
* Grabs any planner-specific data required from the solutions.
* Takes ownership of the PlanRankingDecision that placed the plan in the cache.
*/
- PlanCacheEntry(const std::vector<QuerySolution*>& solutions, PlanRankingDecision* why);
+ PlanCacheEntry(const std::vector<QuerySolution*>& solutions,
+ PlanRankingDecision* why,
+ uint32_t queryHash);
~PlanCacheEntry();
@@ -269,6 +271,10 @@ public:
BSONObj collation;
Date_t timeOfCreation;
+ // Hash of the PlanCacheKey. Intended as an identifier for the query shape in logs and other
+ // diagnostic output.
+ uint32_t queryHash;
+
//
// Performance stats
//
@@ -437,6 +443,12 @@ public:
PlanCacheKey computeKey(const CanonicalQuery&) const;
/**
+ * Returns a hash of the plan cache key. This hash may not be stable between different versions
+ * of the server.
+ */
+ static uint32_t computeQueryHash(const PlanCacheKey& key);
+
+ /**
* Returns a copy of a cache entry.
* Used by planCacheListPlans to display plan details.
*
@@ -446,11 +458,9 @@ public:
/**
* Returns a vector of all cache entries.
- * Caller owns the result vector and is responsible for cleaning up
- * the cache entry copies.
* Used by planCacheListQueryShapes and index_filter_commands_test.cpp.
*/
- std::vector<PlanCacheEntry*> getAllEntries() const;
+ std::vector<std::unique_ptr<PlanCacheEntry>> getAllEntries() const;
/**
* Returns number of entries in cache. Includes inactive entries.
diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp
index d3d5e7f7bf9..7891158532d 100644
--- a/src/mongo/db/query/plan_cache_test.cpp
+++ b/src/mongo/db/query/plan_cache_test.cpp
@@ -1002,7 +1002,9 @@ protected:
qs.cacheData.reset(soln.cacheData->clone());
std::vector<QuerySolution*> solutions;
solutions.push_back(&qs);
- PlanCacheEntry entry(solutions, createDecision(1U).release());
+
+ uint32_t queryHash = PlanCache::computeQueryHash(ck);
+ PlanCacheEntry entry(solutions, createDecision(1U).release(), queryHash);
CachedSolution cachedSoln(ck, entry);
auto statusWithQs = QueryPlanner::planFromCache(*scopedCq, params, cachedSoln);