summaryrefslogtreecommitdiff
path: root/jstests/replsets/write_concern_after_stepdown_and_stepup.js
blob: 3cd88cfcf5769edbeeaa36cd5aaa5f2fda5d9a13 (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
/*
 * Tests that heartbeats containing writes from a different branch of history can't cause a stale
 * primary to incorrectly acknowledge a w:majority write that's about to be rolled back, even if the
 * stale primary is re-elected primary before waiting for the write concern acknowledgement.
 */
(function() {
'use strict';

load("jstests/replsets/rslib.js");
load("jstests/libs/write_concern_util.js");

var name = "writeConcernStepDownAndBackUp";
var dbName = "wMajorityCheck";
var collName = "stepdownAndBackUp";

var rst = new ReplSetTest({
    name: name,
    nodes: [
        {},
        {},
        {rsConfig: {priority: 0}},
    ],
    useBridge: true
});
var nodes = rst.startSet();
rst.initiate();

function waitForPrimary(node) {
    assert.soon(function() {
        return node.adminCommand('ismaster').ismaster;
    });
}

function stepUp(node) {
    var primary = rst.getPrimary();
    if (primary != node) {
        assert.commandWorked(primary.adminCommand({replSetStepDown: 60 * 5}));
    }
    waitForPrimary(node);
}

jsTestLog("Make sure node 0 is primary.");
stepUp(nodes[0]);
var primary = rst.getPrimary();
var secondaries = rst.getSecondaries();
assert.eq(nodes[0], primary);
// Wait for all data bearing nodes to get up to date.
assert.commandWorked(nodes[0].getDB(dbName).getCollection(collName).insert(
    {a: 1}, {writeConcern: {w: 3, wtimeout: rst.kDefaultTimeoutMS}}));

// Stop the secondaries from replicating.
stopServerReplication(secondaries);
// Stop the primary from calling into awaitReplication()
assert.commandWorked(nodes[0].adminCommand(
    {configureFailPoint: 'hangBeforeWaitingForWriteConcern', mode: 'alwaysOn'}));

jsTestLog("Do w:majority write that won't enter awaitReplication() until after the primary " +
          "has stepped down and back up");
var doMajorityWrite = function() {
    // Run ismaster command with 'hangUpOnStepDown' set to false to mark this connection as
    // one that shouldn't be closed when the node steps down.  This simulates the scenario where
    // the write was coming from a mongos.
    assert.commandWorked(db.adminCommand({ismaster: 1, hangUpOnStepDown: false}));

    var res = db.getSiblingDB('wMajorityCheck').stepdownAndBackUp.insert({a: 2}, {
        writeConcern: {w: 'majority'}
    });
    assert.writeErrorWithCode(res, ErrorCodes.InterruptedDueToReplStateChange);
};

var joinMajorityWriter = startParallelShell(doMajorityWrite, nodes[0].port);

jsTest.log("Disconnect primary from all secondaries");
nodes[0].disconnect(nodes[1]);
nodes[0].disconnect(nodes[2]);

jsTest.log("Wait for a new primary to be elected");
// Allow the secondaries to replicate again.
restartServerReplication(secondaries);

waitForPrimary(nodes[1]);

jsTest.log("Do a write to the new primary");
assert.commandWorked(nodes[1].getDB(dbName).getCollection(collName).insert(
    {a: 3}, {writeConcern: {w: 2, wtimeout: rst.kDefaultTimeoutMS}}));

jsTest.log("Reconnect the old primary to the rest of the nodes");
nodes[0].reconnect(nodes[1]);
nodes[0].reconnect(nodes[2]);

jsTest.log("Wait for the old primary to step down, roll back its write, and apply the " +
           "new writes from the new primary");
waitForState(nodes[0], ReplSetTest.State.SECONDARY);
rst.awaitReplication();

// At this point all 3 nodes should have the same data
assert.soonNoExcept(function() {
    nodes.forEach(function(node) {
        assert.eq(null,
                  node.getDB(dbName).getCollection(collName).findOne({a: 2}),
                  "Node " + node.host + " contained op that should have been rolled back");
        assert.neq(null,
                   node.getDB(dbName).getCollection(collName).findOne({a: 3}),
                   "Node " + node.host +
                       " was missing op from branch of history that should have persisted");
    });
    return true;
});

jsTest.log("Make the original primary become primary once again");
stepUp(nodes[0]);

jsTest.log("Unblock the thread waiting for replication of the now rolled-back write, ensure " +
           "that the write concern failed");
assert.commandWorked(
    nodes[0].adminCommand({configureFailPoint: 'hangBeforeWaitingForWriteConcern', mode: 'off'}));

joinMajorityWriter();

rst.stopSet();
}());