summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/plan_cache_invalidation.js
blob: e4c54d0a8a3e5542d28f96f9a681529cdb6e4415 (plain)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
 * Test that cache entries are removed and plan cache size is decreased on Plan Cache invalidation
 * and clearing.
 * @tags: [
 *   # TODO SERVER-67607: Test plan cache with CQF enabled.
 *   cqf_incompatible,
 * ]
 */

(function() {
"use strict";

const conn = MongoRunner.runMongod();
assert.neq(conn, null, "mongod failed to start");
const db = conn.getDB("sbe_plan_cache_invalidation");

function getPlanCacheSize() {
    return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalSizeEstimateBytes;
}

/**
 * Helper class that creates a collection, indexes on it, and makes a few queries to add entries to
 * the plan cache.
 */
class TestCollection {
    constructor(name = "coll") {
        this.coll = db[name];
        this.coll.drop();

        this.indexNames = ["index1", "index2", "index3"];
        assert.commandWorked(this.coll.createIndex({a: 1}, {name: this.indexNames[0]}));
        assert.commandWorked(this.coll.createIndex({b: 1}, {name: this.indexNames[1]}));
        assert.commandWorked(this.coll.createIndex({b: 1, a: 1}, {name: this.indexNames[2]}));

        assert.eq(0, this.coll.find({a: 1, b: 2}).itcount());
        assert.eq(0, this.coll.find({a: 1, c: 3, b: 2}).itcount());

        assert.gt(getPlanCacheSize(), 0);

        this.nCacheEntries = this.getNumberOfPlanCacheEntries();
        assert.eq(2, this.nCacheEntries);
    }

    getNumberOfPlanCacheEntries() {
        return this.coll.getPlanCache().list().length;
    }

    assertAllCollectionCacheEntriesRemoved() {
        assert.eq(0, this.getNumberOfPlanCacheEntries());
    }

    assertCacheEntriesNotRemoved() {
        assert.eq(this.nCacheEntries, this.getNumberOfPlanCacheEntries());
    }
}

(function cacheEntriesRemovedIfTheCollectionDropped() {
    const initialPlanCacheSize = getPlanCacheSize();
    const test = new TestCollection();

    assert.gt(getPlanCacheSize(), initialPlanCacheSize);

    assert(test.coll.drop());

    assert.eq(getPlanCacheSize(), initialPlanCacheSize);
}());

(function cacheEntriesNotRemovedIfAnotherCollectedDropped() {
    const test = new TestCollection("coll1");
    const cacheSizeForOneTestCollection = getPlanCacheSize();

    const anotherTest = new TestCollection("coll2");
    const cacheSizeForTwoTestCollections = getPlanCacheSize();
    assert.gt(cacheSizeForTwoTestCollections, cacheSizeForOneTestCollection);
    assert(anotherTest.coll.drop());

    assert.eq(cacheSizeForOneTestCollection, getPlanCacheSize());
    test.assertCacheEntriesNotRemoved();
}());

(function cacheEntriesRemovedIfANewIndexCreated() {
    const test = new TestCollection();
    const planCacheSize = getPlanCacheSize();

    assert.commandWorked(test.coll.createIndex({hi: 1}));

    assert.lt(getPlanCacheSize(), planCacheSize);
    test.assertAllCollectionCacheEntriesRemoved();
}());

(function cacheEntriesRemovedIfAnyIndexDropped() {
    const test = new TestCollection();
    const initialPlanCacheSize = getPlanCacheSize();

    assert.commandWorked(test.coll.dropIndex(test.indexNames[0]));

    assert.lt(getPlanCacheSize(), initialPlanCacheSize);
    test.assertAllCollectionCacheEntriesRemoved();
}());

(function cacheEntriesNotRemovedIfCallModCalled() {
    const collectionName = "coll";
    const test = new TestCollection(collectionName);
    const initialPlanCacheSize = getPlanCacheSize();

    assert.commandWorked(
        db.runCommand({collMod: collectionName, validator: {text: {$type: "string"}}}));

    assert.eq(getPlanCacheSize(), initialPlanCacheSize);
    test.assertCacheEntriesNotRemoved();
}());

(function cacheEntriesRemovedIfIndexChanged() {
    const collectionName = "coll";
    const test = new TestCollection(collectionName);
    const initialPlanCacheSize = getPlanCacheSize();

    assert.commandWorked(db.runCommand({
        collMod: collectionName,
        index: {
            name: test.indexNames[0],
            hidden: true,
        }
    }));

    assert.lt(getPlanCacheSize(), initialPlanCacheSize);
    test.assertAllCollectionCacheEntriesRemoved();
}());

(function cacheEntriesRemovedOnClearPlanCacheCommand() {
    const collectionName = "coll";
    const initialPlanCacheSize = getPlanCacheSize();

    const test = new TestCollection(collectionName);
    assert.gt(getPlanCacheSize(), initialPlanCacheSize);

    assert.commandWorked(db.runCommand({planCacheClear: collectionName}));

    assert.eq(getPlanCacheSize(), initialPlanCacheSize);
    test.assertAllCollectionCacheEntriesRemoved();
}());

(function oneCacheEntryRemovedOnClearPlanCacheWithQueryCommand() {
    const collectionName = "coll";
    const test = new TestCollection(collectionName);
    const numberOfCacheEntries = test.getNumberOfPlanCacheEntries();

    test.coll.find({a: 1, b: 2, c: 3, d: 4}).itcount();
    assert.eq(numberOfCacheEntries + 1, test.getNumberOfPlanCacheEntries());
    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());
}());

MongoRunner.stopMongod(conn);
}());