summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/index_secondary_wait_for_abort.js
blob: eff0b5a0876f7c15ecd24849d7219bcc39b24daa (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
/**
 * Confirms that index builds on a secondary are aborted when we encounter a document that cannot be
 * indexed. Since we expect the index build on the primary to fail, the secondary should wait for
 * the primary's abortIndexBuild oplog entry.
 * @tags: [
 *   requires_replication,
 * ]
 */
(function() {
"use strict";

load('jstests/noPassthrough/libs/index_build.js');

const rst = new ReplSetTest({
    nodes: [
        {},
        {
            // Disallow elections on secondary.
            rsConfig: {
                priority: 0,
                votes: 0,
            },
        },
    ]
});
const nodes = rst.startSet();
rst.initiate();

const primary = rst.getPrimary();

const testDB = primary.getDB('test');
const coll = testDB.getCollection('test');

assert.commandWorked(coll.insert({a: 1}));

// There are two 'a.0' fields in this doc, which prevents us from creating an index on {'a.0': 1}.
// Inserting this document causes the index build to fail during the collection scan phase.
const invalidDocForIndex = {
    a: [
        {'0': 1},
    ],
};

assert.commandWorked(coll.insert(invalidDocForIndex));

// We are using this fail point to pause the index build before it starts the collection scan.
// This is important for this test because we want to prevent the index build on the primary from
// observing the invalid document while we block its progress.
assert.commandWorked(
    testDB.adminCommand({configureFailPoint: 'hangAfterSettingUpIndexBuild', mode: 'alwaysOn'}));

const createIdx = IndexBuildTest.startIndexBuild(primary, coll.getFullName(), {'a.0': 1});

const secondary = rst.getSecondary();
const secondaryDB = secondary.getDB(testDB.getName());
try {
    // Wait for the index build to start on the primary.
    const opId = IndexBuildTest.waitForIndexBuildToStart(testDB, coll.getName(), 'a.0_1');
    IndexBuildTest.assertIndexBuildCurrentOpContents(testDB, opId);

    // The index build on the secondary will fail on the invalid document but will wait for the
    // abortIndexBuild oplog entry from the primary.
    const secondaryOpId =
        IndexBuildTest.waitForIndexBuildToStart(secondaryDB, coll.getName(), 'a.0_1');
    IndexBuildTest.assertIndexBuildCurrentOpContents(secondaryDB, secondaryOpId);
} finally {
    testDB.adminCommand({configureFailPoint: 'hangAfterSettingUpIndexBuild', mode: 'off'});
}

// Wait for the index build to stop.
IndexBuildTest.waitForIndexBuildToStop(testDB);

const exitCode = createIdx({checkExitSuccess: false});
assert.neq(0, exitCode, 'expected shell to exit abnormally due to index build failing');

// Confirm that the index build on the secondary failed because of the invalid document.
// "Ambiguous field name found in array ..."
checkLog.checkContainsOnceJsonStringMatch(secondary, 20649, "error", "\"code\":16746");

// Check indexes on primary.
rst.awaitReplication();
IndexBuildTest.assertIndexes(coll, 1, ['_id_']);

// Check that index was not created on the secondary.
const secondaryColl = secondaryDB.getCollection(coll.getName());
IndexBuildTest.assertIndexes(secondaryColl, 1, ['_id_']);

const cmdNs = testDB.getCollection('$cmd').getFullName();
const ops = rst.dumpOplog(primary, {op: 'c', ns: cmdNs, 'o.abortIndexBuild': coll.getName()});
assert.eq(1, ops.length, 'primary did not write abortIndexBuild oplog entry: ' + tojson(ops));

rst.stopSet();
})();