Skip to content

Commit 906ac3c

Browse files
louiswilliamsevergreen
authored andcommitted
SERVER-43638 Do not block prepared transactions on index builds on secondaries
1 parent b1bd366 commit 906ac3c

File tree

2 files changed

+18
-9
lines changed

2 files changed

+18
-9
lines changed

jstests/noPassthrough/index_builds_ignore_prepare_conflicts.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* @tags: [
66
* requires_document_locking,
77
* requires_replication,
8-
* two_phase_index_builds_unsupported,
98
* uses_prepare_transaction,
109
* uses_transactions,
1110
* ]

src/mongo/db/repl/transaction_oplog_application.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -324,14 +324,24 @@ Status _applyPrepareTransaction(OperationContext* opCtx,
324324
// This will prevent hybrid index builds from corrupting an index on secondary nodes if a
325325
// prepared transaction becomes prepared during a build but commits after the index build
326326
// commits.
327-
for (const auto& op : ops) {
328-
auto ns = op.getNss();
329-
auto uuid = *op.getUuid();
330-
if (BackgroundOperation::inProgForNs(ns)) {
331-
warning() << "blocking replication until index builds are finished on "
332-
<< redact(ns.toString()) << ", due to prepared transaction";
333-
BackgroundOperation::awaitNoBgOpInProgForNs(ns);
334-
IndexBuildsCoordinator::get(opCtx)->awaitNoIndexBuildInProgressForCollection(uuid);
327+
// When two-phase index builds are in use, this is both unnecessary and unsafe. Due to locking,
328+
// we can guarantee that a transaction prepared on a primary during an index build will always
329+
// commit before that index build completes. Because two-phase index builds replicate start and
330+
// commit oplog entries, it will never be possible to replicate a prepared transaction, commit
331+
// an index build, then commit the transaction, the bug described above.
332+
// This blocking behavior can also introduce a deadlock with two-phase index builds on
333+
// a secondary if a prepared transaction blocks on an index build, but the index build can't
334+
// re-acquire its X lock because of the transaction.
335+
if (!IndexBuildsCoordinator::get(opCtx)->supportsTwoPhaseIndexBuild()) {
336+
for (const auto& op : ops) {
337+
auto ns = op.getNss();
338+
auto uuid = *op.getUuid();
339+
if (BackgroundOperation::inProgForNs(ns)) {
340+
warning() << "blocking replication until index builds are finished on "
341+
<< redact(ns.toString()) << ", due to prepared transaction";
342+
BackgroundOperation::awaitNoBgOpInProgForNs(ns);
343+
IndexBuildsCoordinator::get(opCtx)->awaitNoIndexBuildInProgressForCollection(uuid);
344+
}
335345
}
336346
}
337347

0 commit comments

Comments
 (0)