0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

SERVER-43638 Do not block prepared transactions on index builds on secondaries

This commit is contained in:
Louis Williams 2019-10-09 19:56:36 +00:00 committed by evergreen
parent b1bd366200
commit 906ac3ca78
2 changed files with 18 additions and 9 deletions

View File

@ -5,7 +5,6 @@
* @tags: [
* requires_document_locking,
* requires_replication,
* two_phase_index_builds_unsupported,
* uses_prepare_transaction,
* uses_transactions,
* ]

View File

@ -324,14 +324,24 @@ Status _applyPrepareTransaction(OperationContext* opCtx,
// This will prevent hybrid index builds from corrupting an index on secondary nodes if a
// prepared transaction becomes prepared during a build but commits after the index build
// commits.
for (const auto& op : ops) {
auto ns = op.getNss();
auto uuid = *op.getUuid();
if (BackgroundOperation::inProgForNs(ns)) {
warning() << "blocking replication until index builds are finished on "
<< redact(ns.toString()) << ", due to prepared transaction";
BackgroundOperation::awaitNoBgOpInProgForNs(ns);
IndexBuildsCoordinator::get(opCtx)->awaitNoIndexBuildInProgressForCollection(uuid);
// When two-phase index builds are in use, this is both unnecessary and unsafe. Due to locking,
// we can guarantee that a transaction prepared on a primary during an index build will always
// commit before that index build completes. Because two-phase index builds replicate start and
// commit oplog entries, it will never be possible to replicate a prepared transaction, commit
// an index build, then commit the transaction, the bug described above.
// This blocking behavior can also introduce a deadlock with two-phase index builds on
// a secondary if a prepared transaction blocks on an index build, but the index build can't
// re-acquire its X lock because of the transaction.
if (!IndexBuildsCoordinator::get(opCtx)->supportsTwoPhaseIndexBuild()) {
for (const auto& op : ops) {
auto ns = op.getNss();
auto uuid = *op.getUuid();
if (BackgroundOperation::inProgForNs(ns)) {
warning() << "blocking replication until index builds are finished on "
<< redact(ns.toString()) << ", due to prepared transaction";
BackgroundOperation::awaitNoBgOpInProgForNs(ns);
IndexBuildsCoordinator::get(opCtx)->awaitNoIndexBuildInProgressForCollection(uuid);
}
}
}