summaryrefslogtreecommitdiff
path: root/jstests/replsets/prepare_transaction_index_build.js
blob: aa5d53673e18add65976a59bd05e6b88f6b54f65 (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
/**
 * Tests that background index builds on secondaries block prepared transactions from being
 * prepared.
 * This behavior is necessary because hybrid index builds would otherwise miss prepared transaction
 * writes if the prepared transaction commits after a hybrid index build commits.  The long term
 * solution to this problem is to synchronize index build commits.
 *
 * @tags: [uses_transactions, uses_prepare_transaction]
 */
(function() {
"use strict";
load("jstests/core/txns/libs/prepare_helpers.js");

const replTest = new ReplSetTest({nodes: 2});
replTest.startSet();
replTest.initiate();

const primary = replTest.getPrimary();
const secondary = replTest.getSecondary();

const dbName = "test";
const collName = "prepared_transactions_index_build";
const testDB = primary.getDB(dbName);
const testColl = testDB.getCollection(collName);

assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}}));

const bulk = testColl.initializeUnorderedBulkOp();
for (let i = 0; i < 10; ++i) {
    bulk.insert({x: i});
}
assert.writeOK(bulk.execute());

// activate failpoint to hang index build on secondary.
secondary.getDB("admin").runCommand(
    {configureFailPoint: 'hangAfterStartingIndexBuild', mode: 'alwaysOn'});

jsTestLog("Starting a background index build.");
assert.commandWorked(testDB.runCommand({
    createIndexes: collName,
    indexes: [{key: {x: 1}, name: 'x_1'}],
    writeConcern: {w: 2},
}));

const session = primary.startSession({causalConsistency: false});
const sessionDB = session.getDatabase(dbName);
const sessionColl = sessionDB.getCollection(collName);

jsTestLog("Starting a transaction that should involve the index and putting it into prepare");

session.startTransaction();
assert.commandWorked(sessionColl.insert({x: 1000}));

const prepareTimestamp = PrepareHelpers.prepareTransaction(session, {w: 1});
jsTestLog("Prepared a transaction at " + prepareTimestamp);

jsTestLog("Unblocking index build.");

// finish the index build
secondary.getDB("admin").runCommand(
    {configureFailPoint: 'hangAfterStartingIndexBuild', mode: 'off'});

// It's illegal to commit a prepared transaction before its prepare oplog entry has been
// majority committed. So wait for prepare oplog entry to be majority committed before issuing
// the commitTransaction command. We know the index build is also done if the prepare has
// finished on the secondary.
jsTestLog(
    "Waiting for prepare oplog entry to be majority committed and all index builds to finish on all nodes.");
PrepareHelpers.awaitMajorityCommitted(replTest, prepareTimestamp);

jsTestLog("Committing txn");
// Commit the transaction.
assert.commandWorked(PrepareHelpers.commitTransaction(session, prepareTimestamp));
replTest.awaitReplication();

jsTestLog("Testing index integrity");
// Index should work.
assert.eq(
    1000,
    secondary.getDB(dbName).getCollection(collName).find({x: 1000}).hint({x: 1}).toArray()[0].x);
jsTestLog("Shutting down the set");
replTest.stopSet();
}());