summaryrefslogtreecommitdiff
path: root/jstests/multiVersion/causal_consistency_upgrade_cluster.js
blob: 916684ea29a3c1d922deb5d4731e99a64269910a (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
/**
 * Tests upgrading a cluster with two shards and two mongos servers from last stable to current
 * version, verifying the behavior of $logicalTime metadata and afterClusterTime commands throughout
 * the process.
 */
(function() {
    "use strict";

    load("jstests/multiVersion/libs/multi_rs.js");
    load("jstests/multiVersion/libs/multi_cluster.js");
    load("jstests/multiVersion/libs/causal_consistency_helpers.js");

    if (!supportsMajorityReadConcern()) {
        jsTestLog("Skipping test since storage engine doesn't support majority read concern.");
        return;
    }

    // Start a cluster at the last stable version, with majority read concern enabled.
    var st = new ShardingTest({
        shards: 2,
        mongos: 2,
        other: {
            mongosOptions: {binVersion: "last-stable"},
            configOptions: {binVersion: "last-stable"},
            rsOptions: {binVersion: "last-stable", enableMajorityReadConcern: ""},
            rs: true
        }
    });
    st.configRS.awaitReplication();

    st.s.getDB("test").runCommand({insert: "foo", documents: [{_id: 1, x: 1}]});

    // No servers return logical or operation time.
    assertDoesNotContainLogicalOrOperationTime(st.s0.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(st.s1.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs0.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs1.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.configRS.getPrimary().getDB("test").runCommand({isMaster: 1}));

    // Upgrade the config servers.
    jsTest.log("Upgrading config servers.");
    st.upgradeCluster("latest", {upgradeMongos: false, upgradeShards: false});
    st.restartMongoses();

    // Mongod and mongos cannot accept afterClusterTime reads.
    assertAfterClusterTimeReadFails(st.s0.getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.s1.getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs0.getPrimary().getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs1.getPrimary().getDB("test"), "foo");

    // Config servers still don't return logical or operation times.
    assertDoesNotContainLogicalOrOperationTime(
        st.configRS.getPrimary().getDB("test").runCommand({isMaster: 1}));

    assertDoesNotContainLogicalOrOperationTime(st.s0.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(st.s1.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs0.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs1.getPrimary().getDB("test").runCommand({isMaster: 1}));

    // Then upgrade the shard servers.
    jsTest.log("Upgrading shard servers.");
    st.upgradeCluster("latest", {upgradeConfigs: false, upgradeMongos: false});
    st.restartMongoses();

    // Mongod and mongos still cannot accept afterClusterTime reads.
    assertAfterClusterTimeReadFails(st.s0.getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.s1.getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs0.getPrimary().getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs1.getPrimary().getDB("test"), "foo");

    // Shards still don't return logical or operation times.
    assertDoesNotContainLogicalOrOperationTime(
        st.rs0.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs1.getPrimary().getDB("test").runCommand({isMaster: 1}));

    // Neither do config servers.
    assertDoesNotContainLogicalOrOperationTime(
        st.configRS.getPrimary().getDB("test").runCommand({isMaster: 1}));

    assertDoesNotContainLogicalOrOperationTime(st.s0.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(st.s1.getDB("test").runCommand({isMaster: 1}));

    // Finally, upgrade mongos servers.
    jsTest.log("Upgrading mongos servers.");
    st.upgradeCluster("latest", {upgradeConfigs: false, upgradeShards: false});
    st.restartMongoses();

    // afterClusterTime reads are still not accepted.
    assertAfterClusterTimeReadFails(st.s.getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs0.getPrimary().getDB("test"), "foo");
    assertAfterClusterTimeReadFails(st.rs1.getPrimary().getDB("test"), "foo");

    // Neither mongos returns logical time or operation time, because there are no keys in the
    // config server, since feature compatibility version is still 3.4.
    assertDoesNotContainLogicalOrOperationTime(st.s0.getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(st.s1.getDB("test").runCommand({isMaster: 1}));

    // All shards and the config servers still don't return logical or operation time.
    assertDoesNotContainLogicalOrOperationTime(
        st.rs0.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.rs1.getPrimary().getDB("test").runCommand({isMaster: 1}));
    assertDoesNotContainLogicalOrOperationTime(
        st.configRS.getPrimary().getDB("test").runCommand({isMaster: 1}));

    // Set feature compatibility version to 3.6 on one mongos.
    assert.commandWorked(st.s0.getDB("admin").runCommand({setFeatureCompatibilityVersion: "3.6"}));

    // Now shards and config servers return dummy signed logical times and operation times.
    assertContainsLogicalAndOperationTime(
        st.rs0.getPrimary().getDB("test").runCommand({isMaster: 1}),
        {initialized: true, signed: false});
    assertContainsLogicalAndOperationTime(
        st.rs1.getPrimary().getDB("test").runCommand({isMaster: 1}),
        {initialized: true, signed: false});
    assertContainsLogicalAndOperationTime(
        st.configRS.getPrimary().getDB("test").runCommand({isMaster: 1}),
        {initialized: true, signed: false});

    // Once the config primary creates keys, both mongos servers discover them and start returning
    // signed logical times.
    assert.soonNoExcept(function() {
        assertContainsLogicalAndOperationTime(st.s0.getDB("test").runCommand({isMaster: 1}),
                                              {initialized: true, signed: true});
        assertContainsLogicalAndOperationTime(st.s1.getDB("test").runCommand({isMaster: 1}),
                                              {initialized: true, signed: true});
        return true;
    });

    // Now shards and mongos can accept afterClusterTime reads.
    assertAfterClusterTimeReadSucceeds(st.s0.getDB("test"), "foo");
    assertAfterClusterTimeReadSucceeds(st.s1.getDB("test"), "foo");
    assertAfterClusterTimeReadSucceeds(st.rs0.getPrimary().getDB("test"), "foo");
    assertAfterClusterTimeReadSucceeds(st.rs1.getPrimary().getDB("test"), "foo");

    // Causally consistent requests are correctly processed.
    let res = assert.commandWorked(
        st.s.getDB("test").runCommand({insert: "foo", documents: [{_id: 2, x: 2}]}));
    res = assert.commandWorked(
        st.s.getDB("test").runCommand({delete: "foo", deletes: [{q: {_id: 1}, limit: 1}]}));

    let operationTime = res.operationTime;
    res = assert.commandWorked(st.s.getDB("test").runCommand(
        {find: "foo", readConcern: {level: "majority", afterClusterTime: operationTime}}));
    assert.eq(res.cursor.firstBatch, [{_id: 2, x: 2}]);

    st.stop();
})();