diff options
author | joshua <80741223+jlap199@users.noreply.github.com> | 2022-02-02 07:09:01 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-02-02 07:52:13 +0000 |
commit | 616ba6a01e803ab159edcca954131c5fe3a9b0ef (patch) | |
tree | 237be76fa83dc409fb2d1abda956155cd9ed635f | |
parent | 324ac9ce57f186d1c21923c60d197b7d969ecbe6 (diff) | |
download | mongo-616ba6a01e803ab159edcca954131c5fe3a9b0ef.tar.gz |
SERVER-59696 Include SBE plan cache as part of cache size metric
-rw-r--r-- | jstests/noPassthrough/sbe_plan_cache_size_metric.js | 86 | ||||
-rw-r--r-- | src/mongo/db/query/classic_plan_cache.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache.h | 10 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache_test.cpp | 90 |
4 files changed, 139 insertions, 51 deletions
diff --git a/jstests/noPassthrough/sbe_plan_cache_size_metric.js b/jstests/noPassthrough/sbe_plan_cache_size_metric.js new file mode 100644 index 00000000000..2d7cd423bad --- /dev/null +++ b/jstests/noPassthrough/sbe_plan_cache_size_metric.js @@ -0,0 +1,86 @@ +/** + * Tests that planCacheTotalSizeEstimateBytes metric increased for SBE and classic plan cache + * entries. + * + * @tags: [ + * # Needed as the setParameter for ForceClassicEngine was introduced in 5.1. + * requires_fcv_51, + * # If all chunks are moved off of a shard, it can cause the plan cache to miss commands. + * assumes_balancer_off, + * does_not_support_stepdowns, + * ] + */ + +(function() { +"use strict"; + +load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. +load('jstests/libs/fixture_helpers.js'); // For FixtureHelpers. + +const conn = MongoRunner.runMongod(); +assert.neq(conn, null, "mongod failed to start"); +const db = conn.getDB("sbe_plan_cache_size_metric"); + +function getCacheEntriesByQueryHashKey(coll, queryHash) { + return coll.aggregate([{$planCacheStats: {}}, {$match: {queryHash}}]).toArray(); +} + +function getQueryHashFromExplain(explainRes) { + const hash = FixtureHelpers.isMongos(db) + ? explainRes.queryPlanner.winningPlan.shards[0].queryHash + : explainRes.queryPlanner.queryHash; + assert.eq(typeof (hash), "string"); + return hash; +} + +function getPlanCacheSize() { + return db.serverStatus().metrics.query.planCacheTotalSizeEstimateBytes; +} + +function assertQueryInPlanCache(coll, query) { + const explainResult = assert.commandWorked(coll.explain().find(query).finish()); + const queryHash = getQueryHashFromExplain(explainResult, db); + const planCacheEntries = getCacheEntriesByQueryHashKey(coll, queryHash); + assert.eq(1, planCacheEntries.length, planCacheEntries); +} + +const isSbePlanCacheEnabled = checkSBEEnabled(db, ["featureFlagSbePlanCache"]); +if (isSbePlanCacheEnabled) { + const coll = db.plan_cache_sbe; + coll.drop(); + + assert.commandWorked(coll.insert({a: 1, b: 1})); + + // We need two indexes so that the multi-planner is executed. + assert.commandWorked(coll.createIndex({a: 1})); + assert.commandWorked(coll.createIndex({a: 1, b: 1})); + + const initialPlanCacheSize = getPlanCacheSize(); + // Plan cache must be empty. + assert.eq(0, coll.getPlanCache().list().length); + + const query = {a: 1}; + + assert.eq(1, coll.find(query).itcount()); + assertQueryInPlanCache(coll, query); + // Plan Cache must contain exactly 1 entry. + assert.eq(1, coll.getPlanCache().list().length); + + // Assert metric is incremented for new cache entry. + const afterSbePlanCacheSize = getPlanCacheSize(); + assert.gt(afterSbePlanCacheSize, initialPlanCacheSize); + + // Force classic plan cache. + assert.commandWorked(db.adminCommand({setParameter: 1, internalQueryForceClassicEngine: true})); + assert.eq(1, coll.find(query).itcount()); + assertQueryInPlanCache(coll, query); + // Plan Cache must contain exactly 2 entries. + assert.eq(2, coll.getPlanCache().list().length); + + // Assert metric is incremented for new cache entry. + const afterClassicPlanCacheSize = getPlanCacheSize(); + assert.gt(afterClassicPlanCacheSize, afterSbePlanCacheSize); +} + +MongoRunner.stopMongod(conn); +})(); diff --git a/src/mongo/db/query/classic_plan_cache.cpp b/src/mongo/db/query/classic_plan_cache.cpp index 6a373a0c76d..aa3f150291c 100644 --- a/src/mongo/db/query/classic_plan_cache.cpp +++ b/src/mongo/db/query/classic_plan_cache.cpp @@ -34,9 +34,11 @@ namespace mongo { namespace { ServerStatusMetricField<Counter64> totalPlanCacheSizeEstimateBytesMetric( - "query.planCacheTotalSizeEstimateBytes", &PlanCacheEntry::planCacheTotalSizeEstimateBytes); + "query.planCacheTotalSizeEstimateBytes", &mongo::planCacheTotalSizeEstimateBytes); } // namespace +Counter64 planCacheTotalSizeEstimateBytes; + std::ostream& operator<<(std::ostream& stream, const PlanCacheKey& key) { stream << key.toString(); return stream; diff --git a/src/mongo/db/query/plan_cache.h b/src/mongo/db/query/plan_cache.h index 64afadd9834..889cd5dc1dd 100644 --- a/src/mongo/db/query/plan_cache.h +++ b/src/mongo/db/query/plan_cache.h @@ -44,6 +44,11 @@ template <class CachedPlanType, class DebugInfoType> class PlanCacheEntryBase; /** + * Tracks the approximate cumulative size of the plan cache entries across all the collections. + */ +extern Counter64 planCacheTotalSizeEstimateBytes; + +/** * Information returned from a get(...) query. */ template <class CachedPlanType, class DebugInfoType> @@ -181,11 +186,6 @@ public: // turn own, and so on. const uint64_t estimatedEntrySizeBytes; - /** - * Tracks the approximate cumulative size of the plan cache entries across all the collections. - */ - inline static Counter64 planCacheTotalSizeEstimateBytes; - private: /** * All arguments constructor. diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index fc48a792e0e..72efd3f6e67 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -1778,7 +1778,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { PlanCache planCache(5000); unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}")); auto qs = getQuerySolutionForCaching(); - long long previousSize, originalSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + long long previousSize, originalSize = planCacheTotalSizeEstimateBytes.get(); auto key = makeKey(*cq); auto decisionPtr = createDecision(1U); auto decision = decisionPtr.get(); @@ -1788,7 +1788,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { callbacks{*cq}; // Verify that the plan cache size increases after adding new entry to cache. - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), *decision, @@ -1796,12 +1796,12 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); decisionPtr = createDecision(1U); decision = decisionPtr.get(); // Verify that trying to set the same entry won't change the plan cache size. - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), *decision, @@ -1809,7 +1809,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), previousSize); decisionPtr = createDecision(2U); decision = decisionPtr.get(); @@ -1821,12 +1821,12 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); decisionPtr = createDecision(1U); decision = decisionPtr.get(); // Verify that the plan cache size decreases after updating the same entry with fewer solutions. - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), *decision, @@ -1834,11 +1834,11 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_LT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), originalSize); + ASSERT_LT(planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), originalSize); // Verify that adding multiple entries will increasing the cache size. - long long sizeWithOneEntry = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + long long sizeWithOneEntry = planCacheTotalSizeEstimateBytes.get(); std::string queryString = "{a: 1, c: 1}"; for (int i = 0; i < 5; ++i) { decisionPtr = createDecision(1U); @@ -1846,7 +1846,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { // Update the field name in the query string so that plan cache creates a new entry. queryString[1] = 'b' + i; unique_ptr<CanonicalQuery> query(canonicalize(queryString)); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(makeKey(*query), qs->cacheData->clone(), *decision, @@ -1854,7 +1854,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that removing multiple entries will decreasing the cache size. @@ -1862,23 +1862,23 @@ TEST(PlanCacheTest, PlanCacheSizeWithCRUDOperations) { // Update the field name in the query to match the previously created plan cache entry key. queryString[1] = 'b' + i; unique_ptr<CanonicalQuery> query(canonicalize(queryString)); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); planCache.remove(makeKey(*query)); - ASSERT_LT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_LT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that size is reset to the size when there is only entry. - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), sizeWithOneEntry); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), sizeWithOneEntry); // Verify that trying to remove a non-existing key won't change the plan cache size. - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); unique_ptr<CanonicalQuery> newQuery(canonicalize("{a: 1}")); planCache.remove(makeKey(*newQuery)); - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), previousSize); // Verify that the plan cache size goes back to original size when the entry is removed. planCache.remove(key); ASSERT_EQ(planCache.size(), 0U); - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), originalSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), originalSize); } TEST(PlanCacheTest, PlanCacheSizeWithEviction) { @@ -1886,8 +1886,8 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { PlanCache planCache(kCacheSize); unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}")); auto qs = getQuerySolutionForCaching(); - long long originalSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); - long long previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + long long originalSize = planCacheTotalSizeEstimateBytes.get(); + long long previousSize = planCacheTotalSizeEstimateBytes.get(); auto key = makeKey(*cq); // Add entries until plan cache is full and verify that the size keeps increasing. @@ -1898,7 +1898,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { // Update the field name in the query string so that plan cache creates a new entry. queryString[1]++; unique_ptr<CanonicalQuery> query(canonicalize(queryString)); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); PlanCacheLoggingCallbacks<PlanCacheKey, SolutionCacheData, mongo::plan_cache_debug_info::DebugInfo> @@ -1910,7 +1910,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that adding entry of same size as evicted entry wouldn't change the plan cache size. @@ -1923,7 +1923,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { SolutionCacheData, mongo::plan_cache_debug_info::DebugInfo> callbacks{*cq}; - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_EQ(planCache.size(), kCacheSize); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), @@ -1933,7 +1933,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { boost::none /* worksGrowthCoefficient */, &callbacks)); ASSERT_EQ(planCache.size(), kCacheSize); - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that adding entry with query bigger than the evicted entry's key should change the @@ -1947,7 +1947,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { SolutionCacheData, mongo::plan_cache_debug_info::DebugInfo> callbacks{*queryBiggerKey}; - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK( planCache.set(makeKey(*queryBiggerKey), qs->cacheData->clone(), @@ -1956,7 +1956,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { plan_cache_util::buildDebugInfo(*queryBiggerKey, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that adding entry with query solutions larger than the evicted entry's query solutions @@ -1970,7 +1970,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { SolutionCacheData, mongo::plan_cache_debug_info::DebugInfo> callbacks{*cq}; - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), *decision, @@ -1978,7 +1978,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that adding entry with query solutions smaller than the evicted entry's query @@ -1992,7 +1992,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { SolutionCacheData, mongo::plan_cache_debug_info::DebugInfo> callbacks{*cq}; - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(key, qs->cacheData->clone(), *decision, @@ -2000,11 +2000,11 @@ TEST(PlanCacheTest, PlanCacheSizeWithEviction) { plan_cache_util::buildDebugInfo(*cq, std::move(decisionPtr)), boost::none /* worksGrowthCoefficient */, &callbacks)); - ASSERT_LT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_LT(planCacheTotalSizeEstimateBytes.get(), previousSize); // clear() should reset the size. planCache.clear(); - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), originalSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), originalSize); } } @@ -2013,7 +2013,7 @@ TEST(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) { PlanCache planCache2(5000); unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1, b: 1}")); auto qs = getQuerySolutionForCaching(); - long long previousSize, originalSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + long long previousSize, originalSize = planCacheTotalSizeEstimateBytes.get(); // Verify that adding entries to both plan caches will keep increasing the cache size. std::string queryString = "{a: 1, c: 1}"; @@ -2023,23 +2023,23 @@ TEST(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) { // Update the field name in the query string so that plan cache creates a new entry. queryString[1] = 'b' + i; unique_ptr<CanonicalQuery> query(canonicalize(queryString)); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache1.set(makeKey(*query), qs->cacheData->clone(), *decisionPtr, Date_t{}, plan_cache_util::buildDebugInfo(*query, std::move(decision)))); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); decision = createDecision(1U); decisionPtr = decision.get(); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache2.set(makeKey(*query), qs->cacheData->clone(), *decisionPtr, Date_t{}, plan_cache_util::buildDebugInfo(*query, std::move(decision)))); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that removing entries from one plan caches will keep decreasing the cache size. @@ -2047,37 +2047,37 @@ TEST(PlanCacheTest, PlanCacheSizeWithMultiplePlanCaches) { // Update the field name in the query to match the previously created plan cache entry key. queryString[1] = 'b' + i; unique_ptr<CanonicalQuery> query(canonicalize(queryString)); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); planCache1.remove(makeKey(*query)); - ASSERT_LT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_LT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify for scoped PlanCache object. - long long sizeBeforeScopedPlanCache = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + long long sizeBeforeScopedPlanCache = planCacheTotalSizeEstimateBytes.get(); { auto decision = createDecision(1U); auto decisionPtr = decision.get(); PlanCache planCache(5000); - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); ASSERT_OK(planCache.set(makeKey(*cq), qs->cacheData->clone(), *decisionPtr, Date_t{}, plan_cache_util::buildDebugInfo(*cq, std::move(decision)))); - ASSERT_GT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_GT(planCacheTotalSizeEstimateBytes.get(), previousSize); } // Verify that size is reset to 'sizeBeforeScopedPlanCache' after the destructor of 'planCache' // is called. - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), sizeBeforeScopedPlanCache); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), sizeBeforeScopedPlanCache); // Clear 'planCache2' to remove all entries. - previousSize = PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(); + previousSize = planCacheTotalSizeEstimateBytes.get(); planCache2.clear(); - ASSERT_LT(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), previousSize); + ASSERT_LT(planCacheTotalSizeEstimateBytes.get(), previousSize); // Verify that size is reset to the original size after removing all entries. - ASSERT_EQ(PlanCacheEntry::planCacheTotalSizeEstimateBytes.get(), originalSize); + ASSERT_EQ(planCacheTotalSizeEstimateBytes.get(), originalSize); } } // namespace |