diff options
author | Haley Connelly <haley.connelly@10gen.com> | 2018-08-02 17:18:32 -0400 |
---|---|---|
committer | Haley Connelly <haley.connelly@10gen.com> | 2018-08-02 17:18:38 -0400 |
commit | ba50688792f3f038271af9edb3d0207691f6f63b (patch) | |
tree | aedb8f9caf4c12852426ff332324de81c33d154f /src/mongo/db | |
parent | e68e228f0ebc6c70b808c173cedbda2b7dcfc87c (diff) | |
download | mongo-ba50688792f3f038271af9edb3d0207691f6f63b.tar.gz |
SERVER-35981 Include hash of plan cache key in planCacheListShapes and planCacheListPlans
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/commands/index_filter_commands_test.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/plan_cache_commands.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/commands/plan_cache_commands_test.cpp | 27 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache.h | 18 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache_test.cpp | 4 |
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); |