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
|
/**
* Test that index filters are applied regardless of catalog changes. Intended to reproduce
* SERVER-33303.
*
* @tags: [
* # This test performs queries with index filters set up. Since index filters are local to a
* # mongod, and do not replicate, this test must issue all of its commands against the same node.
* assumes_read_preference_unchanged,
* does_not_support_stepdowns,
* sbe_incompatible,
* ]
*/
(function() {
"use strict";
load("jstests/libs/analyze_plan.js"); // For getPlanStages.
const collName = "index_filter_catalog_independent";
const coll = db[collName];
coll.drop();
/*
* Check that there's one index filter on the given query which allows only 'indexes'.
*/
function assertOneIndexFilter(query, indexes) {
let res = assert.commandWorked(db.runCommand({planCacheListFilters: collName}));
assert.eq(res.filters.length, 1);
assert.eq(res.filters[0].query, query);
assert.eq(res.filters[0].indexes, indexes);
}
function assertIsIxScanOnIndex(winningPlan, keyPattern) {
const ixScans = getPlanStages(winningPlan, "IXSCAN");
assert.gt(ixScans.length, 0);
ixScans.every((ixScan) => assert.eq(ixScan.keyPattern, keyPattern));
const collScans = getPlanStages(winningPlan, "COLLSCAN");
assert.eq(collScans.length, 0);
}
function checkIndexFilterSet(explain, shouldBeSet) {
if (explain.queryPlanner.winningPlan.shards) {
for (let shard of explain.queryPlanner.winningPlan.shards) {
assert.eq(shard.indexFilterSet, shouldBeSet);
}
} else {
assert.eq(explain.queryPlanner.indexFilterSet, shouldBeSet);
}
}
assert.commandWorked(coll.createIndexes([{x: 1}, {x: 1, y: 1}]));
assert.commandWorked(
db.runCommand({planCacheSetFilter: collName, query: {"x": 3}, indexes: [{x: 1, y: 1}]}));
assertOneIndexFilter({x: 3}, [{x: 1, y: 1}]);
let explain = assert.commandWorked(coll.find({x: 3}).explain());
checkIndexFilterSet(explain, true);
assertIsIxScanOnIndex(explain.queryPlanner.winningPlan, {x: 1, y: 1});
// Drop an index. The filter should not change.
assert.commandWorked(coll.dropIndex({x: 1, y: 1}));
assertOneIndexFilter({x: 3}, [{x: 1, y: 1}]);
// The {x: 1} index _could_ be used, but should not be considered because of the filter.
// Since we dropped the {x: 1, y: 1} index, a COLLSCAN must be used.
explain = coll.find({x: 3}).explain();
checkIndexFilterSet(explain, true);
assert(isCollscan(db, explain.queryPlanner.winningPlan));
// Create another index. This should not change whether the index filter is applied.
assert.commandWorked(coll.createIndex({x: 1, z: 1}));
explain = assert.commandWorked(coll.find({x: 3}).explain());
checkIndexFilterSet(explain, true);
assert(isCollscan(db, explain.queryPlanner.winningPlan));
// Changing the catalog and then setting an index filter should not result in duplicate entries.
assert.commandWorked(coll.createIndex({x: 1, a: 1}));
assert.commandWorked(
db.runCommand({planCacheSetFilter: collName, query: {"x": 3}, indexes: [{x: 1, y: 1}]}));
assertOneIndexFilter({x: 3}, [{x: 1, y: 1}]);
// Recreate the {x: 1, y: 1} index and be sure that it's still used.
assert.commandWorked(coll.createIndexes([{x: 1}, {x: 1, y: 1}]));
assertOneIndexFilter({x: 3}, [{x: 1, y: 1}]);
explain = assert.commandWorked(coll.find({x: 3}).explain());
checkIndexFilterSet(explain, true);
assertIsIxScanOnIndex(explain.queryPlanner.winningPlan, {x: 1, y: 1});
})();
|