summaryrefslogtreecommitdiff
path: root/jstests/replsets/drop_collections_two_phase_rename_drop_target.js
blob: 9aa9a15c9c1a9d26af645b0b6bebb609512a4218 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/**
 * Test to ensure that the two phase drop behavior is applied to the target collection of a
 * renameCollection command when dropTarget is set to true.
 */

(function() {
'use strict';

load("jstests/libs/logv2_helpers.js");
load('jstests/replsets/libs/two_phase_drops.js');  // For TwoPhaseDropCollectionTest.

// Return a list of all indexes for a given collection. Use 'args' as the
// 'listIndexes' command arguments.
// Assumes all indexes in the collection fit in the first batch of results.
function listIndexes(database, coll, args) {
    args = args || {};
    let failMsg = "'listIndexes' command failed";
    let listIndexesCmd = {listIndexes: coll};
    let res = assert.commandWorked(database.runCommand(listIndexesCmd, args), failMsg);
    return res.cursor.firstBatch;
}

// Set up a two phase drop test.
let testName = 'drop_collection_two_phase_rename_drop_target';
let dbName = testName;
let fromCollName = 'collToRename';
let toCollName = 'collToDrop';
let twoPhaseDropTest = new TwoPhaseDropCollectionTest(testName, dbName);

// Initialize replica set.
let replTest = twoPhaseDropTest.initReplSet();

// Check for 'system.drop' two phase drop support.
if (!twoPhaseDropTest.supportsDropPendingNamespaces()) {
    jsTestLog('Drop pending namespaces not supported by storage engine. Skipping test.');
    twoPhaseDropTest.stop();
    return;
}

// Create the collections that will be renamed and dropped.
twoPhaseDropTest.createCollection(fromCollName);
twoPhaseDropTest.createCollection(toCollName);

// Collection renames with dropTarget set to true should handle long index names in the target
// collection gracefully.
const primary = replTest.getPrimary();
const testDb = primary.getDB(dbName);
const fromColl = testDb.getCollection(fromCollName);
const toColl = testDb.getCollection(toCollName);
let longIndexName = 'a'.repeat(8192);
let shortIndexName = "short_name";

// In the target collection, which will be dropped, create one index with a "too long" name, and
// one with a name of acceptable size.
assert.commandWorked(toColl.createIndex({a: 1}, {name: longIndexName}));
assert.commandWorked(toColl.createIndex({b: 1}, {name: shortIndexName}));

// Insert documents into both collections so that we can tell them apart.
assert.commandWorked(fromColl.insert({_id: 'from'}));
assert.commandWorked(toColl.insert({_id: 'to'}));
replTest.awaitReplication();

// Prevent renameCollection from being applied on the secondary so that we can examine the state
// of the primary after target collection has been dropped.
jsTestLog('Pausing oplog application on the secondary node.');
const secondary = replTest.getSecondary();
twoPhaseDropTest.pauseOplogApplication(secondary);

// This logs each operation being applied.
const previousLogLevel =
    assert.commandWorked(primary.setLogLevel(1, 'storage')).was.replication.verbosity;

try {
    // When the target collection exists, the renameCollection command should fail if dropTarget
    // flag is set to false or is omitted.
    jsTestLog(
        'Checking renameCollection error handling when dropTarget is set to false and target collection exists.');
    let dropTarget = false;
    assert.commandFailedWithCode(fromColl.renameCollection(toCollName, dropTarget),
                                 ErrorCodes.NamespaceExists);

    // Rename collection with dropTarget set to true. Check collection contents after rename.
    jsTestLog('Renaming collection ' + fromColl.getFullName() + ' to ' + toColl.getFullName() +
              ' with dropTarget set to true.');
    dropTarget = true;
    assert.commandWorked(fromColl.renameCollection(toColl.getName(), dropTarget));
    assert(!twoPhaseDropTest.collectionExists(fromCollName));
    assert(twoPhaseDropTest.collectionExists(toCollName));
    assert.eq({_id: 'from'}, toColl.findOne());

    // Confirm that original target collection is now a drop-pending collection.
    const isPendingDropResult = twoPhaseDropTest.collectionIsPendingDrop(toCollName);
    assert(isPendingDropResult);
    const droppedCollName = isPendingDropResult.name;
    jsTestLog('Original target collection is now in a drop-pending state: ' + droppedCollName);

    // COMMIT collection drop.
    twoPhaseDropTest.resumeOplogApplication(secondary);
    replTest.awaitReplication();
    assert.soonNoExcept(function() {
        return !twoPhaseDropTest.collectionIsPendingDrop(toCollName);
    });

    // Confirm in the logs that the renameCollection dropped the target collection on the
    // secondary using two phase collection drop.
    if (isJsonLog(secondary)) {
        checkLog.containsJson(secondary, 20315, {namespace: toColl.getFullName()});
    } else {
        checkLog.contains(secondary, new RegExp('dropCollection:.*' + toColl.getFullName()));
    }

    // Rename target collection back to source collection. This helps to ensure the collection
    // metadata is updated correctly on both primary and secondary.
    assert.commandWorked(toColl.renameCollection(fromCollName + '_roundtrip'));
    replTest.awaitReplication();
} finally {
    // Reset log level.
    primary.setLogLevel(previousLogLevel, 'storage');

    twoPhaseDropTest.stop();
}
}());