summaryrefslogtreecommitdiff
path: root/jstests/sharding/invalidate_plan_cache_entries_when_collection_generation_changes.js
blob: ffc349fa76b3355ee2e72e7c806336bbed86e2af (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
/**
 * Tests that plan cache entries are deleted after shard key refining, resharding and renaming
 * operations.
 *
 *  @tags: [
 *   # The SBE plan cache was enabled by default in 6.3.
 *   requires_fcv_63,
 * ]
 */

// Cannot run the filtering metadata check on tests that run refineCollectionShardKey.
TestData.skipCheckShardFilteringMetadata = true;

(function() {
'use strict';
load("jstests/libs/sbe_util.js");

const criticalSectionTimeoutMS = 24 * 60 * 60 * 1000;  // 1 day
const st = new ShardingTest({
    mongos: 1,
    config: 1,
    shards: 1,
    other: {
        // Avoid spurious failures with small 'ReshardingCriticalSectionTimeout' values being set.
        configOptions:
            {setParameter: {reshardingCriticalSectionTimeoutMillis: criticalSectionTimeoutMS}}
    }
});

const mongos = st.s;
const dbName = "invalidate_on_coll_generation_change_db";
const db = st.getDB(dbName);
const collA = db["collA"];
const collB = db["collB"];

if (!checkSBEEnabled(db)) {
    jsTestLog("********** Skip the test because SBE is disabled **********");
    st.stop();
    return;
}

function assertPlanCacheSizeForColl(nss, expectedEntriesCount) {
    // Using assert.soon since the sharded metadata cleanup function is executed asynchronously.
    assert.soon(() => {
        const entries = mongos.getCollection(nss).aggregate([{$planCacheStats: {}}]).toArray();
        var numSBEEntries = 0;
        entries.forEach(entry => {
            if (entry.version == "2")
                numSBEEntries++;
        });

        return numSBEEntries === expectedEntriesCount;
    });
}

function assertDropAndShardColl(coll, keyDoc) {
    assert.commandWorked(db.runCommand({drop: coll.getName()}));
    assert.commandWorked(mongos.adminCommand({shardCollection: coll.getFullName(), key: keyDoc}));
}

// Initializes the collection and makes sure there's exactly one plan cache entry after
// initialization.
function initCollection(nss) {
    assertPlanCacheSizeForColl(nss, 0);

    assert.commandWorked(mongos.getCollection(nss).insert({a: 1, b: 2, aKey: 1}));
    assert.commandWorked(mongos.getCollection(nss).insert({a: 2, b: 2, aKey: 2}));

    assert.commandWorked(mongos.getCollection(nss).createIndex({a: 1}));
    assert.commandWorked(mongos.getCollection(nss).createIndex({b: 1}));
    assert.commandWorked(mongos.getCollection(nss).createIndex({a: 1, b: 1}));

    // Run query multiple times to activate a plan cache entry.
    assert.eq(mongos.getCollection(nss).find({a: 1, b: 1}).itcount(), 0);
    assert.eq(mongos.getCollection(nss).find({a: 1, b: 1}).itcount(), 0);
    assertPlanCacheSizeForColl(nss, 1);
}

assert.commandWorked(mongos.adminCommand({enableSharding: dbName}));

// Test that plan cache entries are deleted after refining shard key of a collection.
(function testRefineShardKeyDeletesAssociatedCacheEntry() {
    jsTestLog("Testing refine shard key command");
    // Set up the collections.
    for (let coll of [collA, collB]) {
        assertDropAndShardColl(coll, {a: 1});
        initCollection(coll.getFullName());
    }

    // Ensure that after refining the shard key there are no plan cache entries associated with the
    // 'collA'. However, plan cache entries for 'collB' must remain unchanged.
    assert.commandWorked(
        mongos.adminCommand({refineCollectionShardKey: collA.getFullName(), key: {a: 1, b: 1}}));

    // The refine shard key command may complete but shards might not be aware of it.
    st.shard0.adminCommand(
        {_flushRoutingTableCacheUpdates: collA.getFullName(), syncFromConfig: true});

    assertPlanCacheSizeForColl(collA.getFullName(), 0);
    assertPlanCacheSizeForColl(collB.getFullName(), 1);
})();

// Test that plan cache entries are deleted after collection is resharded.
(function testReshardingDeletesAssociatedCacheEntry() {
    jsTestLog("Testing reshard collection command");
    // Set up the collections.
    for (let coll of [collA, collB]) {
        assertDropAndShardColl(coll, {a: 1});
        initCollection(coll.getFullName());
    }

    // Ensure that after resharding there are no plan cache entries associated with the 'collA'.
    // However, plan cache entries for 'collB' must remain unchanged.
    assert.commandWorked(
        mongos.adminCommand({reshardCollection: collA.getFullName(), key: {b: 1}}));
    assertPlanCacheSizeForColl(collA.getFullName(), 0);
    assertPlanCacheSizeForColl(collB.getFullName(), 1);
})();

// Test that plan cache entries are deleted after a collection is renamed.
(function testRenameCollectionDeletesAssociatedCacheEntry() {
    jsTestLog("Testing rename collection command");
    // Set up the collections.
    for (let coll of [collA, collB]) {
        assertDropAndShardColl(coll, {a: 1});
        initCollection(coll.getFullName());
    }

    // Ensure that after renaming there are no plan cache entries associated with either 'collA' or
    // 'collB'.
    assert.commandWorked(mongos.adminCommand(
        {renameCollection: collA.getFullName(), to: collB.getFullName(), dropTarget: true}));

    assertPlanCacheSizeForColl(collB.getFullName(), 0);

    // 'collB' was dropped by the renameCollection cmd. Check that $planCacheStats returns the
    // exected error (i.e. collection doesn't exist)
    assert.commandFailedWithCode(
        db.runCommand({aggregate: collA.getName(), pipeline: [{$planCacheStats: {}}], cursor: {}}),
        50933);
})();

st.stop();
})();