summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/sbe_plan_cache_api_version.js
blob: 2a3a0d184e3fab2a7ef538d155e74d0fc5b93cd4 (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
/**
 * Validates the behaviour of the the SBE plan cache when the API version was provided to the
 * aggregate command.
 * @tags: [
 *   # TODO SERVER-67607: Test plan cache with CQF enabled.
 *   cqf_incompatible,
 * ]
 */

(function() {
"use strict";

load("jstests/libs/analyze_plan.js");
load("jstests/libs/sbe_util.js");

const conn = MongoRunner.runMongod({});
assert.neq(conn, null, "mongod failed to start");
const db = conn.getDB("plan_cache_api_version");
const coll = db.coll;
coll.drop();

const isSBEEnabled = checkSBEEnabled(db);

assert.commandWorked(coll.insert([{a: 1, b: 1}, {a: 2, b: 2}]));

// Runs the given pipeline with the specified options and returns its plan cache key.
function runPipeline(pipeline, options, explainOptions = {}) {
    const command = Object.assign({aggregate: coll.getName(), pipeline, cursor: {}}, options);
    const result = coll.runCommand(command);
    assert.commandWorked(result);
    assert.eq(result.cursor.firstBatch.length, 1, result.cursor.firstBatch);

    const explain = coll.runCommand(Object.assign({explain: command}, explainOptions));
    assert.commandWorked(explain);
    assert.neq(explain, null);
    assert.eq(explain.explainVersion, isSBEEnabled ? "2" : "1", explain);
    assert.neq(explain.queryPlanner.planCacheKey, null, explain);
    return explain.queryPlanner.planCacheKey;
}

// Runs the given 'pipeline' with the API version and returns its plan cache key.
function runPipelineWithApiVersion(pipeline) {
    const options = {apiVersion: '1'};
    return runPipeline(pipeline, options, options);
}

// Runs the given 'pipeline' with the API version and 'apiStrict: true' and returns its plan cache
// key.
function runPipelineWithApiStrict(pipeline) {
    const options = {apiVersion: '1', apiStrict: true};
    return runPipeline(pipeline, options, options);
}

// Asserts that a plan cache entry for the given 'cacheKey' exists in the plan cache and has
// certain properties set as per provided 'properties' argument.
function assertPlanCacheEntryExists(cacheKey, properties = {}) {
    const entries =
        coll.aggregate([{$planCacheStats: {}}, {$match: {planCacheKey: cacheKey}}]).toArray();
    assert.eq(entries.length, 1, entries);
    const entry = entries[0];

    if (isSBEEnabled) {
        // The version:"2" field indicates that this is an SBE plan cache entry.
        assert.eq(entry.version, "2", entry);
        assert.eq(entry.isActive, properties.isActive, entry);
        assert.eq(entry.isPinned, properties.isPinned, entry);
    } else {
        // The version:"1" field indicates that this is an classic plan cache entry.
        assert.eq(entry.version, "1", entry);
        assert.eq(entry.isActive, properties.isActive, entry);
    }
}

const pipeline = [{$match: {a: 1, b: 1}}];

// Run a set of testcases where each testcase defines a set of indexes on the collection and
// executes the above pipeline with and without the API strict flag. Assert that the plan cache
// keys for each of the two queries are different and two different plan cache entries have been
// created.

const sbeEngineTestcases = [
    {
        withApiVersion: {isActive: true, isPinned: true},
        withApiStrict: {isActive: true, isPinned: true},
        indexSpecs: []
    },
    {
        withApiVersion: {isActive: true, isPinned: true},
        withApiStrict: {isActive: true, isPinned: true},
        indexSpecs: [{keyPattern: {a: 1}, options: {name: "a_1"}}]
    },
    {
        withApiVersion: {isActive: false, isPinned: false},
        withApiStrict: {isActive: true, isPinned: true},
        indexSpecs: [
            {keyPattern: {a: 1}, options: {name: "a_1"}},
            {keyPattern: {a: 1}, options: {name: "a_1_sparse", sparse: true}}
        ]
    }
];

const classicEngineTestcases = [
    {
        withApiVersion: {isActive: false},
        withApiStrict: {isActive: false},
        indexSpecs: [
            {keyPattern: {a: 1}, options: {name: "a_1"}},
            {keyPattern: {b: 1}, options: {name: "b_1"}}
        ]
    },
    {
        withApiVersion: {isActive: false},
        withApiStrict: {isActive: false},
        indexSpecs: [
            {keyPattern: {a: 1}, options: {name: "a_1"}},
            {keyPattern: {a: 1}, options: {name: "a_1_sparse", sparse: true}},
            {keyPattern: {b: 1}, options: {name: "b_1"}}
        ]
    }
];

const testcases = isSBEEnabled ? sbeEngineTestcases : classicEngineTestcases;
for (const testcase of testcases) {
    [true, false].forEach((runWithApiStrictFirst) => {
        assert.commandWorked(coll.dropIndexes());

        for (const indexSpec of testcase.indexSpecs) {
            assert.commandWorked(coll.createIndex(indexSpec.keyPattern, indexSpec.options));
        }

        let planCacheKeyWithApiVersion;
        let planCacheKeyWithApiStrict;

        if (runWithApiStrictFirst) {
            planCacheKeyWithApiStrict = runPipelineWithApiStrict(pipeline);
            planCacheKeyWithApiVersion = runPipelineWithApiVersion(pipeline);
        } else {
            planCacheKeyWithApiVersion = runPipelineWithApiVersion(pipeline);
            planCacheKeyWithApiStrict = runPipelineWithApiStrict(pipeline);
        }

        assert.neq(planCacheKeyWithApiVersion, planCacheKeyWithApiStrict);
        assertPlanCacheEntryExists(planCacheKeyWithApiVersion, testcase.withApiVersion);
        assertPlanCacheEntryExists(planCacheKeyWithApiStrict, testcase.withApiStrict);
    });
}

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