1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/**
* Test that the query plan cache will be cleared for the given collection on hiding or unhiding an
* index.
*
* @tags: [
* # This test attempts to perform queries and introspect the server's plan cache entries. The
* # former operation may be routed to a secondary in the replica set, whereas the latter must be
* # routed to the primary.
* assumes_read_concern_unchanged,
* assumes_read_preference_unchanged,
* ]
*/
(function() {
'use strict';
load("jstests/libs/analyze_plan.js"); // For getPlanCacheKeyFromShape.
const collName = 'introspect_hidden_index_plan_cache_entries';
const collNotAffectedName = 'introspect_hidden_index_plan_cache_entries_unaffected';
db[collName].drop();
const coll = db[collName];
// This collection is used to validate that hiding an index will not affect the plan cache entries
// for other collections.
db[collNotAffectedName].drop();
const collNotAffected = db[collNotAffectedName];
function getPlansForCacheEntry(queryShape, collection) {
const keyHash = getPlanCacheKeyFromShape({
query: queryShape.query,
projection: queryShape.projection,
sort: queryShape.sort,
collection: collection,
db: db
});
const match = {
$or: [
{
'createdFromQuery.query': queryShape.query,
'createdFromQuery.sort': queryShape.sort,
'createdFromQuery.projection': queryShape.projection
},
{planCacheKey: keyHash}
]
};
return collection.aggregate([{$planCacheStats: {}}, {$match: match}]).toArray();
}
const queryShape = {
query: {a: 1},
sort: {a: -1},
projection: {_id: 0, a: 1}
};
function initCollection(collection) {
assert.commandWorked(collection.insert([{a: 1, b: 1}, {a: 1, b: 2}, {a: 2, b: 2}]));
// We need three indices so that the MultiPlanRunner will still be executed after we hide one of
// the indexes.
assert.commandWorked(collection.createIndex({a: 1}));
assert.commandWorked(collection.createIndex({b: 1}));
assert.commandWorked(collection.createIndex({a: 1, b: 1}));
// Create a cache entry and ensure it is cached.
const cnt = collection.find({a: 1}, {_id: 0, a: 1}).sort({a: -1}).itcount();
assert.eq(2, cnt);
const cachedPlan = getPlansForCacheEntry(queryShape, collection);
assert.gt(cachedPlan.length, 0);
}
initCollection(coll);
initCollection(collNotAffected);
//
// Test that the query plan cache will be cleared for the given collection on hiding and unhiding an
// index.
//
// Hide an index.
assert.commandWorked(coll.hideIndex("b_1"));
let cachedPlan = getPlansForCacheEntry(queryShape, coll);
assert.eq(0, cachedPlan.length);
// Test that hiding an index will not affect the plan cache entries for the other collection.
cachedPlan = getPlansForCacheEntry(queryShape, collNotAffected);
assert.gt(cachedPlan.length, 0);
// Re-create the query plan.
let cnt = coll.find({a: 1}, {_id: 0, a: 1}).sort({a: -1}).itcount();
assert.eq(2, cnt);
cachedPlan = getPlansForCacheEntry(queryShape, coll);
assert.gt(cachedPlan.length, 0);
// Unhide an index.
assert.commandWorked(coll.unhideIndex("b_1"));
cachedPlan = getPlansForCacheEntry(queryShape, coll);
assert.eq(0, cachedPlan.length);
})();
|