summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaddie Zechar <mez2113@columbia.edu>2022-11-23 21:45:57 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-11-24 00:10:34 +0000
commitb75695e4e1d1b07c545f82ed31663dac248202cb (patch)
tree5f9bf6a6c311e37d653b920f2c0ca2f1c7496438
parent71c42004e0e094a3b6efb3352f516af2b76eda3f (diff)
downloadmongo-b75695e4e1d1b07c545f82ed31663dac248202cb.tar.gz
SERVER-71529 Add serverStatus metric for classic and SBE plan cache size
-rw-r--r--jstests/noPassthrough/plan_cache_invalidation.js36
-rw-r--r--jstests/noPassthrough/sbe_plan_cache_size_metric.js9
-rw-r--r--src/mongo/db/query/classic_plan_cache.cpp1
-rw-r--r--src/mongo/db/query/plan_cache.h11
4 files changed, 39 insertions, 18 deletions
diff --git a/jstests/noPassthrough/plan_cache_invalidation.js b/jstests/noPassthrough/plan_cache_invalidation.js
index e4c54d0a8a3..327fc55d5cf 100644
--- a/jstests/noPassthrough/plan_cache_invalidation.js
+++ b/jstests/noPassthrough/plan_cache_invalidation.js
@@ -18,6 +18,10 @@ function getPlanCacheSize() {
return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalSizeEstimateBytes;
}
+function getGlobalPlanCacheNumEntries() {
+ return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalQueryShapes;
+}
+
/**
* Helper class that creates a collection, indexes on it, and makes a few queries to add entries to
* the plan cache.
@@ -37,20 +41,21 @@ class TestCollection {
assert.gt(getPlanCacheSize(), 0);
- this.nCacheEntries = this.getNumberOfPlanCacheEntries();
+ this.nCacheEntries = this.getNumberOfCollectionPlanCacheEntries();
assert.eq(2, this.nCacheEntries);
}
-
- getNumberOfPlanCacheEntries() {
+ // The following three helper functions concern plan cache entries specific to a given
+ // collection, and not the entire/global plan cache
+ getNumberOfCollectionPlanCacheEntries() {
return this.coll.getPlanCache().list().length;
}
assertAllCollectionCacheEntriesRemoved() {
- assert.eq(0, this.getNumberOfPlanCacheEntries());
+ assert.eq(0, this.getNumberOfCollectionPlanCacheEntries());
}
- assertCacheEntriesNotRemoved() {
- assert.eq(this.nCacheEntries, this.getNumberOfPlanCacheEntries());
+ assertCollectionCacheEntriesNotRemoved() {
+ assert.eq(this.nCacheEntries, this.getNumberOfCollectionPlanCacheEntries());
}
}
@@ -59,23 +64,28 @@ class TestCollection {
const test = new TestCollection();
assert.gt(getPlanCacheSize(), initialPlanCacheSize);
+ assert.eq(getGlobalPlanCacheNumEntries(), 2);
assert(test.coll.drop());
-
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
+ assert.eq(getGlobalPlanCacheNumEntries(), 0);
}());
(function cacheEntriesNotRemovedIfAnotherCollectedDropped() {
const test = new TestCollection("coll1");
const cacheSizeForOneTestCollection = getPlanCacheSize();
+ assert.eq(getGlobalPlanCacheNumEntries(), 2);
const anotherTest = new TestCollection("coll2");
const cacheSizeForTwoTestCollections = getPlanCacheSize();
+ assert.eq(getGlobalPlanCacheNumEntries(), 4);
assert.gt(cacheSizeForTwoTestCollections, cacheSizeForOneTestCollection);
assert(anotherTest.coll.drop());
assert.eq(cacheSizeForOneTestCollection, getPlanCacheSize());
- test.assertCacheEntriesNotRemoved();
+ // Entries associated with anotherTest.coll are booted from the plan cache.
+ assert.eq(getGlobalPlanCacheNumEntries(), 2);
+ test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfANewIndexCreated() {
@@ -107,14 +117,13 @@ class TestCollection {
db.runCommand({collMod: collectionName, validator: {text: {$type: "string"}}}));
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
- test.assertCacheEntriesNotRemoved();
+ test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfIndexChanged() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
const initialPlanCacheSize = getPlanCacheSize();
-
assert.commandWorked(db.runCommand({
collMod: collectionName,
index: {
@@ -122,7 +131,6 @@ class TestCollection {
hidden: true,
}
}));
-
assert.lt(getPlanCacheSize(), initialPlanCacheSize);
test.assertAllCollectionCacheEntriesRemoved();
}());
@@ -143,16 +151,16 @@ class TestCollection {
(function oneCacheEntryRemovedOnClearPlanCacheWithQueryCommand() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
- const numberOfCacheEntries = test.getNumberOfPlanCacheEntries();
+ const numberOfCacheEntries = getGlobalPlanCacheNumEntries();
test.coll.find({a: 1, b: 2, c: 3, d: 4}).itcount();
- assert.eq(numberOfCacheEntries + 1, test.getNumberOfPlanCacheEntries());
+ assert.eq(numberOfCacheEntries + 1, getGlobalPlanCacheNumEntries());
const planCacheSize = getPlanCacheSize();
assert.commandWorked(
db.runCommand({planCacheClear: collectionName, query: {a: 1, b: 2, c: 3, d: 4}}));
assert.lt(getPlanCacheSize(), planCacheSize);
- assert.eq(numberOfCacheEntries, test.getNumberOfPlanCacheEntries());
+ assert.eq(numberOfCacheEntries, getGlobalPlanCacheNumEntries());
}());
MongoRunner.stopMongod(conn);
diff --git a/jstests/noPassthrough/sbe_plan_cache_size_metric.js b/jstests/noPassthrough/sbe_plan_cache_size_metric.js
index 8b760046a34..a0b820d10f2 100644
--- a/jstests/noPassthrough/sbe_plan_cache_size_metric.js
+++ b/jstests/noPassthrough/sbe_plan_cache_size_metric.js
@@ -45,6 +45,9 @@ function getPlanCacheSize() {
return db.serverStatus().metrics.query.planCacheTotalSizeEstimateBytes;
}
+function getPlanCacheNumEntries() {
+ return db.serverStatus().metrics.query.planCacheTotalQueryShapes;
+}
function assertQueryInPlanCache(coll, query) {
const explainResult = assert.commandWorked(coll.explain().find(query).finish());
const queryHash = getQueryHashFromExplain(explainResult, db);
@@ -65,7 +68,7 @@ assert.commandWorked(coll.createIndex({a: 1, b: 1}));
const initialPlanCacheSize = getPlanCacheSize();
// Plan cache must be empty.
-assert.eq(0, coll.getPlanCache().list().length);
+assert.eq(0, getPlanCacheNumEntries());
const sbeQuery = {
a: 1
@@ -79,7 +82,7 @@ const classicQuery = {
assert.eq(1, coll.find(sbeQuery).itcount());
assertQueryInPlanCache(coll, sbeQuery);
// Plan Cache must contain exactly 1 entry.
-assert.eq(1, coll.getPlanCache().list().length);
+assert.eq(1, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterSbePlanCacheSize = getPlanCacheSize();
@@ -92,7 +95,7 @@ assert.commandWorked(
assert.eq(1, coll.find(classicQuery).itcount());
assertQueryInPlanCache(coll, classicQuery);
// Plan Cache must contain exactly 2 entries.
-assert.eq(2, coll.getPlanCache().list().length);
+assert.eq(2, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterClassicPlanCacheSize = getPlanCacheSize();
diff --git a/src/mongo/db/query/classic_plan_cache.cpp b/src/mongo/db/query/classic_plan_cache.cpp
index f4bbff1af2b..7789d894cb5 100644
--- a/src/mongo/db/query/classic_plan_cache.cpp
+++ b/src/mongo/db/query/classic_plan_cache.cpp
@@ -33,6 +33,7 @@
namespace mongo {
CounterMetric planCacheTotalSizeEstimateBytes("query.planCacheTotalSizeEstimateBytes");
+CounterMetric planCacheEntries("query.planCacheTotalQueryShapes");
std::ostream& operator<<(std::ostream& stream, const PlanCacheKey& key) {
stream << key.toString();
diff --git a/src/mongo/db/query/plan_cache.h b/src/mongo/db/query/plan_cache.h
index d950b93f52f..a7db20699f3 100644
--- a/src/mongo/db/query/plan_cache.h
+++ b/src/mongo/db/query/plan_cache.h
@@ -51,6 +51,12 @@ class PlanCacheEntryBase;
extern CounterMetric planCacheTotalSizeEstimateBytes;
/**
+ * Tracks the number of query shapes in the plan cache entries across all the collections. Each
+ * entry in the plan cache is a unique query shape.
+ */
+extern CounterMetric planCacheEntries;
+
+/**
* Information returned from a get(...) query.
*/
template <class CachedPlanType, class DebugInfoType>
@@ -103,7 +109,7 @@ public:
size_t works,
DebugInfoType debugInfo) {
// If the cumulative size of the plan caches is estimated to remain within a predefined
- // threshold, then then include additional debug info which is not strictly necessary for
+ // threshold, then include additional debug info which is not strictly necessary for
// the plan cache to be functional. Once the cumulative plan cache size exceeds this
// threshold, omit this debug info as a heuristic to prevent plan cache memory consumption
// from growing too large.
@@ -155,6 +161,7 @@ public:
~PlanCacheEntryBase() {
planCacheTotalSizeEstimateBytes.decrement(estimatedEntrySizeBytes);
+ planCacheEntries.decrement(1);
}
/**
@@ -258,6 +265,8 @@ private:
// Account for the object in the global metric for estimating the server's total plan cache
// memory consumption.
planCacheTotalSizeEstimateBytes.increment(estimatedEntrySizeBytes);
+ // Account for new entry in the plan cache.
+ planCacheEntries.increment(1);
}
// Ensure that PlanCacheEntryBase is non-copyable.