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: [ * @tags: [
* requires_document_locking, * requires_document_locking,
* requires_replication, * requires_replication,
* two_phase_index_builds_unsupported,
* uses_prepare_transaction, * uses_prepare_transaction,
* uses_transactions, * 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 // 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 // prepared transaction becomes prepared during a build but commits after the index build
// commits. // commits.
for (const auto& op : ops) { // When two-phase index builds are in use, this is both unnecessary and unsafe. Due to locking,
auto ns = op.getNss(); // we can guarantee that a transaction prepared on a primary during an index build will always
auto uuid = *op.getUuid(); // commit before that index build completes. Because two-phase index builds replicate start and
if (BackgroundOperation::inProgForNs(ns)) { // commit oplog entries, it will never be possible to replicate a prepared transaction, commit
warning() << "blocking replication until index builds are finished on " // an index build, then commit the transaction, the bug described above.
<< redact(ns.toString()) << ", due to prepared transaction"; // This blocking behavior can also introduce a deadlock with two-phase index builds on
BackgroundOperation::awaitNoBgOpInProgForNs(ns); // a secondary if a prepared transaction blocks on an index build, but the index build can't
IndexBuildsCoordinator::get(opCtx)->awaitNoIndexBuildInProgressForCollection(uuid); // 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);
}
} }
} }