diff options
author | Samy Lanka <samy.lanka@mongodb.com> | 2018-09-28 10:37:14 -0400 |
---|---|---|
committer | Samy Lanka <samy.lanka@mongodb.com> | 2018-10-01 16:27:56 -0400 |
commit | f7b229af67e5d2e8f77009563347c0220988e6b2 (patch) | |
tree | a2d1f1ae5022312c798714e730a54faeb45119cb /src | |
parent | 3c2eb809fb7f6924612c1900e57cc456bcbb4983 (diff) | |
download | mongo-f7b229af67e5d2e8f77009563347c0220988e6b2.tar.gz |
SERVER-37030 Make internal reads ignore prepare conflicts by default
Diffstat (limited to 'src')
4 files changed, 19 insertions, 15 deletions
diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp index 6184548f7b0..d2f18637fac 100644 --- a/src/mongo/db/read_concern.cpp +++ b/src/mongo/db/read_concern.cpp @@ -206,10 +206,12 @@ Status waitForReadConcern(OperationContext* opCtx, bool allowAfterClusterTime) { // If we are in a direct client within a transaction, then we may be holding locks, so it is // illegal to wait for read concern. This is fine, since the outer operation should have handled - // waiting for read concern. + // waiting for read concern. We don't want to ignore prepare conflicts because snapshot reads + // should block on prepared transactions. auto txnParticipant = TransactionParticipant::get(opCtx); if (opCtx->getClient()->isInDirectClient() && txnParticipant && txnParticipant->inMultiDocumentTransaction()) { + opCtx->recoveryUnit()->setIgnorePrepared(false); return Status::OK(); } @@ -304,6 +306,8 @@ Status waitForReadConcern(OperationContext* opCtx, } if (atClusterTime) { + opCtx->recoveryUnit()->setIgnorePrepared(false); + // TODO(SERVER-34620): We should be using Session::setSpeculativeTransactionReadOpTime when // doing speculative execution with atClusterTime. opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, @@ -339,12 +343,12 @@ Status waitForReadConcern(OperationContext* opCtx, } // Only snapshot, linearizable and afterClusterTime reads should block on prepared transactions. - // We don't ignore prepare conflicts if we are in a direct client in case this overrides - // behavior set by a higher-level operation. if (readConcernArgs.getLevel() != repl::ReadConcernLevel::kSnapshotReadConcern && readConcernArgs.getLevel() != repl::ReadConcernLevel::kLinearizableReadConcern && - !afterClusterTime && !atClusterTime && !opCtx->getClient()->isInDirectClient()) { + !afterClusterTime && !atClusterTime) { opCtx->recoveryUnit()->setIgnorePrepared(true); + } else { + opCtx->recoveryUnit()->setIgnorePrepared(false); } return Status::OK(); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_begin_transaction_block.h b/src/mongo/db/storage/wiredtiger/wiredtiger_begin_transaction_block.h index 6052e1df6d3..73441b8f038 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_begin_transaction_block.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_begin_transaction_block.h @@ -47,7 +47,7 @@ public: // Whether or not to ignore prepared transactions. enum class IgnorePrepared { kNoIgnore, // Do not ignore prepared transactions and return prepare conflicts. - kIgnore // Ignore prepared transactions and show prepared, but uncommitted data. + kIgnore // Ignore prepare conflicts, but don't show prepared data. }; // Whether or not to round up to the oldest timestamp when the read timestamp is behind it. @@ -57,7 +57,7 @@ public: }; WiredTigerBeginTxnBlock(WT_SESSION* session, - IgnorePrepared ignorePrepared = IgnorePrepared::kNoIgnore); + IgnorePrepared ignorePrepared = IgnorePrepared::kIgnore); WiredTigerBeginTxnBlock(WT_SESSION* session, const char* config); ~WiredTigerBeginTxnBlock(); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h index 585f01ece25..66c1e78033f 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h @@ -181,10 +181,10 @@ private: // When 'true', data read from disk should not be kept in the storage engine cache. bool _readOnce = false; - // Ignoring prepared transactions will not return prepare conflicts and allow seeing prepared, - // but uncommitted data. + // Ignoring prepared transactions will not return prepare conflicts and will not allow seeing + // prepared data. WiredTigerBeginTxnBlock::IgnorePrepared _ignorePrepared{ - WiredTigerBeginTxnBlock::IgnorePrepared::kNoIgnore}; + WiredTigerBeginTxnBlock::IgnorePrepared::kIgnore}; Timestamp _commitTimestamp; Timestamp _prepareTimestamp; boost::optional<Timestamp> _lastTimestampSet; diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp index 63b0f95ee26..8e3cb105036 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit_test.cpp @@ -211,7 +211,7 @@ TEST_F(WiredTigerRecoveryUnitTestFixture, CreateAndCheckForCachePressure) { } TEST_F(WiredTigerRecoveryUnitTestFixture, - LocalReadOnADocumentBeingPreparedTriggersPrepareConflict) { + LocalReadOnADocumentBeingPreparedWithoutIgnoringPreparedTriggersPrepareConflict) { // Prepare but don't commit a transaction ru1->beginUnitOfWork(clientAndCtx1.second.get()); WT_CURSOR* cursor; @@ -222,8 +222,9 @@ TEST_F(WiredTigerRecoveryUnitTestFixture, ru1->setPrepareTimestamp({1, 1}); ru1->prepareUnitOfWork(); - // Transaction read default triggers WT_PREPARE_CONFLICT + // Transaction read that does not ignore prepare conflicts triggers WT_PREPARE_CONFLICT ru2->beginUnitOfWork(clientAndCtx2.second.get()); + ru2->setIgnorePrepared(false); getCursor(ru2, &cursor); cursor->set_key(cursor, "key"); int ret = cursor->search(cursor); @@ -234,7 +235,7 @@ TEST_F(WiredTigerRecoveryUnitTestFixture, } TEST_F(WiredTigerRecoveryUnitTestFixture, - AvailableReadOnADocumentBeingPreparedDoesNotTriggerPrepareConflict) { + LocalReadOnADocumentBeingPreparedDoesntTriggerPrepareConflict) { // Prepare but don't commit a transaction ru1->beginUnitOfWork(clientAndCtx1.second.get()); WT_CURSOR* cursor; @@ -245,10 +246,9 @@ TEST_F(WiredTigerRecoveryUnitTestFixture, ru1->setPrepareTimestamp({1, 1}); ru1->prepareUnitOfWork(); - // Transaction that should ignore prepared transactions won't trigger - // WT_PREPARE_CONFLICT + // Transaction read default ignores prepare conflicts but should not be able to read + // data from the prepared transaction. ru2->beginUnitOfWork(clientAndCtx2.second.get()); - ru2->setIgnorePrepared(true); getCursor(ru2, &cursor); cursor->set_key(cursor, "key"); int ret = cursor->search(cursor); |