summaryrefslogtreecommitdiff
path: root/jstests/replsets/rollback_drop_database.js
blob: 70fb856114003cce8277248596a9bc37944741bf (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
/*
* Test that the server is able to roll back a 'dropDatabase' entry correctly.  This test creates
* a collection, then executes a 'dropDatabase' command, partitioning the primary such that the
* final 'dropDatabase' oplog entry is not replicated. The test then forces rollback of that entry.
*
* The 'dropDatabase' command drops each collection, ensures that the last drop is committed,
* and only then logs a 'dropDatabase' oplog entry. This is therefore the only entry that could
* get rolled back.
*/

(function() {

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

    const testName = "rollback_drop_database";
    const oldDbName = "oldDatabase";
    const newDbName = "newDatabase";

    let rollbackTest = new RollbackTest(testName);
    let rollbackNode = rollbackTest.getPrimary();
    let syncSourceNode = rollbackTest.getSecondary();

    // Perform initial insert (common operation).
    assert.writeOK(rollbackNode.getDB(oldDbName)["beforeRollback"].insert({"num": 1}));

    // Set a failpoint on the original primary, so that it blocks after it commits the last
    // 'dropCollection' entry but before the 'dropDatabase' entry is logged.
    assert.commandWorked(rollbackNode.adminCommand(
        {configureFailPoint: "dropDatabaseHangBeforeLog", mode: "alwaysOn"}));

    // Issue a 'dropDatabase' command.
    let dropDatabaseFn = function() {
        const rollbackDb = "oldDatabase";
        var primary = db.getMongo();
        jsTestLog("Dropping database " + rollbackDb + " on primary node " + primary.host);
        var dbToDrop = db.getSiblingDB(rollbackDb);
        assert.commandWorked(dbToDrop.dropDatabase({w: 1}));
    };
    let waitForDropDatabaseToFinish = startParallelShell(dropDatabaseFn, rollbackNode.port);

    // Ensure that we've hit the failpoint before moving on.
    checkLog.contains(rollbackNode, "dropDatabase - fail point dropDatabaseHangBeforeLog enabled");

    // Wait for the secondary to finish dropping the collection (the last replicated entry).
    // We use the default 10-minute timeout for this.
    assert.soon(function() {
        let res = syncSourceNode.getDB(oldDbName).getCollectionNames().includes("beforeRollback");
        return !res;
    }, "Sync source did not finish dropping collection beforeRollback", 10 * 60 * 1000);

    rollbackTest.transitionToRollbackOperations();

    // Allow the final 'dropDatabase' entry to be logged on the now isolated primary.
    // This is the rollback node's divergent oplog entry.
    assert.commandWorked(
        rollbackNode.adminCommand({configureFailPoint: "dropDatabaseHangBeforeLog", mode: "off"}));
    waitForDropDatabaseToFinish();
    assert.eq(false, rollbackNode.getDB(oldDbName).getCollectionNames().includes("beforeRollback"));
    jsTestLog("Database " + oldDbName + " successfully dropped on primary node " +
              rollbackNode.host);

    rollbackTest.transitionToSyncSourceOperationsBeforeRollback();

    // Perform an insert on another database while interfacing with the new primary.
    // This is the sync source's divergent oplog entry.
    assert.writeOK(syncSourceNode.getDB(newDbName)["afterRollback"].insert({"num": 2}));

    rollbackTest.transitionToSyncSourceOperationsDuringRollback();
    rollbackTest.transitionToSteadyStateOperations();

    rollbackTest.stop();
})();