summaryrefslogtreecommitdiff
path: root/jstests/sharding/sessions_collection_auto_healing.js
blob: 389380b810cb629f260062b0e7f92e139abae11d (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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/**
 * Requires no shards.
 * @tags: [
 *   config_shard_incompatible,
 *   requires_fcv_70,
 * ]
 */
load('jstests/libs/sessions_collection.js');
load("jstests/libs/feature_flag_util.js");

(function() {
"use strict";

load("jstests/libs/collection_drop_recreate.js");  // For assert[Drop|Create]Collection.

// This test makes assertions about the number of sessions, which are not compatible with
// implicit sessions.
TestData.disableImplicitSessions = true;

var st = new ShardingTest({
    shards: 0,
    other: {
        mongosOptions:
            {setParameter: {'failpoint.skipClusterParameterRefresh': "{'mode':'alwaysOn'}"}}
    }
});
var configSvr = st.configRS.getPrimary();

var mongos = st.s;
var mongosConfig = mongos.getDB("config");

// Test that we can use sessions on the config server before we add any shards.
{
    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(mongos, false, false);

    assert.commandWorked(configSvr.adminCommand({startSession: 1}));

    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(mongos, false, false);
}

// Test that we can use sessions on a mongos before we add any shards.
{
    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(mongos, false, false);

    assert.commandWorked(mongos.adminCommand({startSession: 1}));

    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(mongos, false, false);
}

// Test that the config server does not create the sessions collection
// if there are not any shards.
{
    assert.eq(mongosConfig.shards.countDocuments({}), 0);

    assert.commandFailedWithCode(configSvr.adminCommand({refreshLogicalSessionCacheNow: 1}),
                                 [ErrorCodes.ShardNotFound]);

    validateSessionsCollection(configSvr, false, false);
}

// Test-wide: add a shard
const rs = new ReplSetTest({nodes: 1});
rs.startSet({shardsvr: ""});
rs.initiate();

var shard = rs.getPrimary();
var shardConfig = shard.getDB("config");

// Test that we can add this shard, even with a local config.system.sessions collection,
// and test that we drop its local collection
{
    shardConfig.system.sessions.insert({"hey": "you"});
    validateSessionsCollection(shard, true, false);

    assert.commandWorked(mongos.adminCommand({addShard: rs.getURL()}));
    assert.eq(mongosConfig.shards.countDocuments({}), 1);
    validateSessionsCollection(shard, false, false);
}

// Test that we can use sessions on a shard before the sessions collection
// is set up by the config servers.
{
    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);

    assert.commandWorked(shard.adminCommand({startSession: 1}));

    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);
}

// Test that we can use sessions from a mongos before the sessions collection
// is set up by the config servers.
{
    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);
    validateSessionsCollection(mongos, false, false);

    assert.commandWorked(mongos.adminCommand({startSession: 1}));

    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);
    validateSessionsCollection(mongos, false, false);
}

// Test that if we do a refresh (write) from a shard server while there
// is no sessions collection, it does not create the sessions collection.
{
    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);

    assert.commandFailedWithCode(shard.adminCommand({refreshLogicalSessionCacheNow: 1}),
                                 [ErrorCodes.NamespaceNotSharded]);

    validateSessionsCollection(configSvr, false, false);
    validateSessionsCollection(shard, false, false);
}

// Test that a refresh on the config servers once there are shards creates
// the sessions collection on a shard.
{
    validateSessionsCollection(shard, false, false);

    assert.commandWorked(configSvr.adminCommand({refreshLogicalSessionCacheNow: 1}));

    validateSessionsCollection(shard, true, true);

    const sessionsOpenedByAddShardCmd = 1;
    const sessionsOpenedByShardCollectionCmd = 2;
    const sessionsOpenedByDDLOps = sessionsOpenedByAddShardCmd + sessionsOpenedByShardCollectionCmd;

    // We will have sessionsOpenedByDDLOps sessions because of the sessions used in the
    // shardCollection's retryable write to shard the sessions collection. It will disappear after
    // we run the refresh function on the shard.
    assert.eq(shardConfig.system.sessions.countDocuments({}),
              sessionsOpenedByDDLOps,
              "did not flush config's sessions");

    // Now, if we do refreshes on the other servers, their in-mem records will
    // be written to the collection.
    assert.commandWorked(shard.adminCommand({refreshLogicalSessionCacheNow: 1}));
    assert.eq(shardConfig.system.sessions.countDocuments({}),
              sessionsOpenedByDDLOps + 1,
              "did not flush shard's sessions");

    rs.awaitLastOpCommitted();
    assert.commandWorked(mongos.adminCommand({refreshLogicalSessionCacheNow: 1}));
    assert.eq(shardConfig.system.sessions.countDocuments({}),
              sessionsOpenedByDDLOps + 3,
              "did not flush mongos' sessions");
}

// Test that if we drop the index on the sessions collection, only a refresh on the config
// server heals it.
{
    assert.commandWorked(shardConfig.system.sessions.dropIndex({lastUse: 1}));

    validateSessionsCollection(shard, true, false);

    assert.commandWorked(configSvr.adminCommand({refreshLogicalSessionCacheNow: 1}));
    validateSessionsCollection(shard, true, true);

    assert.commandWorked(shardConfig.system.sessions.dropIndex({lastUse: 1}));

    assert.commandWorked(shard.adminCommand({refreshLogicalSessionCacheNow: 1}));
    validateSessionsCollection(shard, true, false);
}

st.stop();
rs.stopSet();
})();