summaryrefslogtreecommitdiff
path: root/jstests/replsets/rollback_via_refetch_survives_nonexistent_collection_drop.js
blob: 8218545bd9370e86d80a15770510f82013631f4e (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
/**
 * Test that rollbackViaRefetch survives an attempt to drop a collection that does not exist.
 * This test simulates a scenario where a collection is dropped during the first rollback
 * attempt.
 *
 * We use a failpoint to ensure the collection was dropped before forcing rollback to return
 * early with a recoverable error. We then turn this failpoint off so that the second attempt
 * can succeed even though the collection has already been dropped.
 *
 */

(function() {
    "use strict";
    load("jstests/libs/check_log.js");
    load("jstests/replsets/libs/rollback_test.js");

    const dbName = "test";
    const collName = "rollback_via_refetch_survives_nonexistent_collection_drop";

    // Provide RollbackTest with custom ReplSetTest so we can set enableMajorityReadConcern.
    const rst = new ReplSetTest({
        name: collName,
        nodes: 3,
        useBridge: true,
        nodeOptions: {enableMajorityReadConcern: "false"}
    });

    rst.startSet();
    const nodes = rst.nodeList();
    rst.initiateWithHighElectionTimeout({
        _id: collName,
        members: [
            {_id: 0, host: nodes[0]},
            {_id: 1, host: nodes[1]},
            {_id: 2, host: nodes[2], arbiterOnly: true},
        ]
    });

    const rollbackTest = new RollbackTest(collName, rst);

    // Stop replication from the current primary, the rollback node.
    const rollbackNode = rollbackTest.transitionToRollbackOperations();
    const rollbackDB = rollbackNode.getDB(dbName);

    jsTestLog("Turning on the rollbackExitEarlyAfterCollectionDrop fail point");
    assert.commandWorked(rollbackDB.adminCommand(
        {configureFailPoint: 'rollbackExitEarlyAfterCollectionDrop', mode: 'alwaysOn'}));

    // Create a collection on the rollback node.
    assert.commandWorked(rollbackDB.runCommand({create: collName}));

    // Step down the current primary and elect the node that does not have the collection.
    rollbackTest.transitionToSyncSourceOperationsBeforeRollback();

    jsTestLog("Attempting to roll back.");
    // Make the old primary rollback against the new primary. This attempt should fail because the
    // rollbackExitEarlyAfterCollectionDrop fail point is set. We fail with a recoverable error
    // so that the rollback will be retried.
    rollbackTest.transitionToSyncSourceOperationsDuringRollback();

    // Make sure we exit the rollback early by checking for the correct log messages.
    checkLog.contains(rollbackDB.getMongo(),
                      "rollbackExitEarlyAfterCollectionDrop fail point enabled.");

    jsTestLog("Turning off the rollbackExitEarlyAfterCollectionDrop fail point");
    // A rollback attempt after turning off the fail point should succeed even if we already
    // dropped the collection.
    assert.commandWorked(rollbackDB.adminCommand(
        {configureFailPoint: 'rollbackExitEarlyAfterCollectionDrop', mode: 'off'}));

    rollbackTest.transitionToSteadyStateOperations();

    // After a successful rollback attempt, we should have seen the following log message to ensure
    // that we tried to drop a non-existent collection and continued without acquiring a database
    // lock.
    checkLog.contains(rollbackDB.getMongo(), "This collection does not exist");

    rollbackTest.stop();
}());