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
|
/**
* Tests that we are able to roll back immediately after replSetInitiate.
*
* @tags: [
* requires_persistence,
* multiversion_incompatible,
* ]
*/
(function() {
"use strict";
load("jstests/libs/fail_point_util.js");
load("jstests/libs/write_concern_util.js");
load("jstests/replsets/rslib.js");
const rst = ReplSetTest({
name: jsTestName(),
nodes: [
{
setParameter: {
"failpoint.pauseCheckpointThread": tojson({mode: "alwaysOn"}),
// We will not be able to rebuild primary only services as those ultimately
// require the checkpointer to be running.
"failpoint.PrimaryOnlyServiceSkipRebuildingInstances": tojson({mode: "alwaysOn"}),
"logComponentVerbosity": tojson({replication: 3}),
},
rsConfig: {priority: 2},
},
{
rsConfig: {priority: 1},
},
{
rsConfig: {priority: 0},
},
],
useBridge: true
});
rst.startSet();
const config = rst.getReplSetConfig();
// We have to initiate manually as RST adds nodes one-by-one, which can lead to the first
// node taking a stable checkpoint.
assert.commandWorked(rst.nodes[0].adminCommand({replSetInitiate: config}));
jsTestLog("Done initiating");
const node0 = rst.nodes[0];
const node1 = rst.nodes[1];
const node2 = rst.nodes[2];
const dbName = "testdb";
const collName = "testcoll";
// Make the first node the primary.
rst.stepUp(node0, {awaitReplicationBeforeStepUp: false});
const oldPrimary = rst.getPrimary();
assert.eq(node0, oldPrimary);
rst.awaitSecondaryNodes();
rst.awaitNodesAgreeOnConfigVersion();
rst.awaitReplication();
const oldPrimaryDB = oldPrimary.getDB(dbName);
const oldPrimaryColl = oldPrimaryDB.getCollection(collName);
jsTestLog("Stopping replication");
stopServerReplication(node1);
stopServerReplication(node2);
jsTestLog("Writing to old primary");
assert.commandWorked(oldPrimaryColl.insert({"old1": 1}, {writeConcern: {w: 1}}));
assert.commandWorked(oldPrimaryColl.insert({"old2": 2}, {writeConcern: {w: 1}}));
jsTestLog("Disconnecting old primary");
node0.disconnect(node1);
node0.disconnect(node2);
assert.commandWorked(oldPrimary.adminCommand({replSetStepDown: 10 * 60, force: true}));
rst.waitForState(rst.nodes[0], ReplSetTest.State.SECONDARY);
jsTestLog("Electing new primary");
restartServerReplication(node1);
restartServerReplication(node2);
const newPrimary = rst.getPrimary();
const lastNode = (newPrimary.host === node1.host) ? node2 : node1;
jsTestLog("Writing to new primary " + newPrimary.host);
const newPrimaryDB = newPrimary.getDB(dbName);
const newPrimaryColl = newPrimaryDB.getCollection(collName);
assert.commandWorked(newPrimaryColl.insert({"new1": 1}, {writeConcern: {w: 1}}));
assert.commandWorked(newPrimaryColl.insert({"new2": 2}, {writeConcern: {w: 1}}));
rst.awaitReplication(undefined /* timeout */, undefined /* secondaryOpTimeType */, [lastNode]);
rst.awaitLastOpCommitted(undefined /* timeout */, [lastNode]);
jsTestLog("Reconnecting old primary");
const lastRBID = assert.commandWorked(node0.adminCommand("replSetGetRBID")).rbid;
node0.reconnect(node1);
node0.reconnect(node2);
rst.waitForState(rst.nodes[0], ReplSetTest.State.ROLLBACK);
// We take a stable checkpoint at the end of rollback so we need the checkpointer to be running.
jsTestLog("Reenabling checkpointer so rollback can complete");
assert.soonNoExcept(function() {
assert.commandWorked(
rst.nodes[0].adminCommand({configureFailPoint: 'pauseCheckpointThread', mode: 'off'}));
const rbid = assert.commandWorked(node0.adminCommand("replSetGetRBID")).rbid;
return rbid > lastRBID;
}, "rbid did not update", ReplSetTest.kDefaultTimeoutMS);
rst.waitForState(rst.nodes[0], ReplSetTest.State.SECONDARY);
jsTestLog("Done with test");
rst.stopSet();
})();
|