summaryrefslogtreecommitdiff
path: root/jstests/replsets/unrecoverable_rollback_early_exit.js
blob: d729b34dd0c59c6c105c5c2dba82e54db98cdfd9 (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
/**
 * This test exercises an unrecoverable rollback using rollback_test.js, expecting it to terminate
 * cleanly early instead of failing.
 * An unrecoverable rollback can happen with EMRC:false, as it is possible for rollback via refetch
 * to set a minValid based on oplog entries that the sync source may have failed to recover after
 * an unclean shutdown. The rollback node will need to sync and apply oplog entries up to minValid
 * to be consistent, but if those oplog entries no longer exist, then it will be stuck in sync
 * source selection and unable to complete recovery.
 * This test reproduces this scenario in a simpler form by modifying the minValid on the rollback
 * node very far forward, so that we do not have to simulate anything happening to the sync source.
 */

(function() {
    "use strict";

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

    function tsToDate(ts) {
        return new Date(ts.getTime() * 1000);
    }

    const testName = jsTestName();

    const rst = new ReplSetTest({
        name: testName,
        nodes: [{}, {}, {rsConfig: {arbiterOnly: true}}],
        useBridge: true,
        settings: {chainingAllowed: false},
        nodeOptions: {enableMajorityReadConcern: "false"}
    });
    rst.startSet();
    rst.initiate();

    const rollbackTest = new RollbackTest(testName, rst);
    const rollbackNode = rollbackTest.transitionToRollbackOperations();

    assert.commandWorked(rollbackNode.adminCommand(
        {configureFailPoint: "rollbackHangBeforeFinish", mode: "alwaysOn"}));

    rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
    rollbackTest.transitionToSyncSourceOperationsDuringRollback();

    checkLog.contains(rollbackNode, "rollbackHangBeforeFinish fail point enabled.");

    const farFutureTS = new Timestamp(
        Math.floor(new Date().getTime() / 1000) + (60 * 60 * 24 * 5 /* in five days*/), 0);

    jsTest.log("future TS: " + tojson(farFutureTS) + ", date:" + tsToDate(farFutureTS));

    const mMinvalid = rollbackNode.getDB("local").getCollection("replset.minvalid");

    const minValidUpdate = {$set: {ts: farFutureTS}};
    jsTestLog("Current minValid is " + tojson(mMinvalid.findOne()));
    jsTestLog("Updating minValid to: " + tojson(minValidUpdate));
    printjson(assert.commandWorked(mMinvalid.update({}, minValidUpdate)));

    assert.commandWorked(
        rollbackNode.adminCommand({configureFailPoint: "rollbackHangBeforeFinish", mode: "off"}));

    rollbackTest.setAwaitSecondaryNodesForRollbackTimeout(5 * 1000);

    // We will detect an unrecoverable rollback here.
    rollbackTest.transitionToSteadyStateOperations();

    rollbackTest.stop();
})();