summaryrefslogtreecommitdiff
path: root/jstests/replsets/initial_sync_fails_on_rollback.js
blob: 4bd98e0f9603387021e3e487b06c69c17b4fbbe3 (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
/**
 * Test that initial sync fails if a rollback occurs while querying collection data.
 *
 * This test depends on 4.4 features.
 * @tags: [multiversion_incompatible]
 */

(function() {
"use strict";

load("jstests/replsets/libs/rollback_test.js");

const testName = "initial_sync_fails_on_rollback";
const dbName = testName;

// Operations that will be present on both nodes, before the common point.
let CommonOps = (node) => {
    let testDb = node.getDB(dbName);
    let bulk = testDb.test.initializeOrderedBulkOp();
    for (let i = 0; i < 100; i++) {
        bulk.insert({a: i});
    }
    assert.commandWorked(bulk.execute({w: "majority"}));
};

// Operations that will be performed on the rollback node past the common point.
let RollbackOps = (node) => {
    let testDb = node.getDB(dbName);
    assert.commandWorked(testDb.test.insert({b: 1}));
};

// Set up Rollback Test.
let rollbackTest = new RollbackTest(testName);
CommonOps(rollbackTest.getPrimary());

// Add the initial sync node.
const initialSyncNode = rollbackTest.add({
    config: {
        // This node must be non-voting to avoid interfering with the rollback machinery.
        rsConfig: {priority: 0, votes: 0},
        setParameter: {
            'failpoint.initialSyncHangBeforeCopyingDatabases': tojson({mode: 'alwaysOn'}),
            'collectionClonerBatchSize': 10,
            // This test is specifically testing that the cloners stop, so we turn off the
            // oplog fetcher to ensure that we don't inadvertently test that instead.
            'failpoint.hangBeforeStartingOplogFetcher': tojson({mode: 'alwaysOn'}),
            // Make sure our initial sync node only talks to the rolling-back primary.
            'failpoint.forceSyncSourceCandidate':
                tojson({mode: 'alwaysOn', data: {"hostAndPort": rollbackTest.getPrimary().host}}),
            'numInitialSyncAttempts': 1,
        }
    }
});

jsTestLog("Waiting for initial sync node to reach initial sync state");
const rst = rollbackTest.getTestFixture();
rst.waitForState(initialSyncNode, ReplSetTest.State.STARTUP_2);

const afterBatchResponseFailPoint =
    configureFailPoint(initialSyncNode,
                       "initialSyncHangCollectionClonerAfterHandlingBatchResponse",
                       {nss: dbName + ".test"});
const beforeFinishFailPoint = configureFailPoint(initialSyncNode, "initialSyncHangBeforeFinish");
// Release the initial failpoint.
assert.commandWorked(initialSyncNode.adminCommand(
    {configureFailPoint: "initialSyncHangBeforeCopyingDatabases", mode: "off"}));

jsTestLog("Waiting for CollectionCloner to reach " + dbName + ".test collection");
afterBatchResponseFailPoint.wait();

jsTestLog("Rolling back");
let rollbackNode = rollbackTest.transitionToRollbackOperations();
RollbackOps(rollbackNode);

// Wait for rollback to finish.
rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
rollbackTest.transitionToSyncSourceOperationsDuringRollback();
// We must skip consistency checks because our initial sync node is not consistent.
rollbackTest.transitionToSteadyStateOperations({skipDataConsistencyChecks: true});

jsTestLog("Releasing the CollectionCloner failpoint.");
afterBatchResponseFailPoint.off();

jsTestLog("Releasing the oplog fetcher failpoint.");
assert.commandWorked(initialSyncNode.getDB("test").adminCommand(
    {configureFailPoint: "hangBeforeStartingOplogFetcher", mode: "off"}));

beforeFinishFailPoint.wait();
const res = assert.commandWorked(initialSyncNode.adminCommand({replSetGetStatus: 1}));
// The initial sync should have failed.
assert.eq(res.initialSyncStatus.failedInitialSyncAttempts, 1);
// It should have determined the correct number of documents to copy.
assert.eq(res.initialSyncStatus.databases[dbName][dbName + ".test"].documentsToCopy, 100);
// No more than one batch should have been copied.
assert.lte(res.initialSyncStatus.databases[dbName][dbName + ".test"].documentsCopied, 10);

// Get rid of the failed node so the fixture can stop properly.
rst.stop(initialSyncNode);
rst.remove(initialSyncNode);

rollbackTest.stop();
})();