diff options
author | Suganthi Mani <suganthi.mani@mongodb.com> | 2020-07-15 23:14:22 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-16 03:38:36 +0000 |
commit | 841fadf7603f11a4ea66217788c5cd763ca84a0e (patch) | |
tree | 38263af62d8abbe33eefd87781fafc67f30d338b | |
parent | 7c23f84809b9d28dd54dbf8fc514568238bb0020 (diff) | |
download | mongo-841fadf7603f11a4ea66217788c5cd763ca84a0e.tar.gz |
Revert "SERVER-49471 Retry on WT_ROLLBACK (WriteConflictException) when applying prepareTransaction oplog entry."
This reverts commit 7c23f84809b9d28dd54dbf8fc514568238bb0020.
3 files changed, 26 insertions, 125 deletions
diff --git a/etc/backports_required_for_multiversion_tests.yml b/etc/backports_required_for_multiversion_tests.yml index 8e586b3b98a..772495637a4 100644 --- a/etc/backports_required_for_multiversion_tests.yml +++ b/etc/backports_required_for_multiversion_tests.yml @@ -26,10 +26,6 @@ concurrency_replication_multiversion: concurrency_sharded_replication_multiversion: -replica_sets_multiversion: -- ticket: SERVER-49471 - test_file: jstests/replsets/apply_prepare_txn_write_conflict_robustness.js - replica_sets_jscore_multiversion_passthrough: - ticket: SERVER-44260 test_file: jstests/core/txns/new_transaction_waits_for_previous_txn_table_updates.js diff --git a/jstests/replsets/apply_prepare_txn_write_conflict_robustness.js b/jstests/replsets/apply_prepare_txn_write_conflict_robustness.js deleted file mode 100644 index 62e98879d48..00000000000 --- a/jstests/replsets/apply_prepare_txn_write_conflict_robustness.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Tests that WT_ROLLBACK (WriteConflictException) error gets retried when applying - * prepareTransaction oplog entry on secondaries. - * - * @tags: [uses_transactions, uses_prepare_transaction] - */ -(function() { - -"use strict"; -load("jstests/core/txns/libs/prepare_helpers.js"); - -const dbName = jsTest.name(); -const collName = "coll"; - -var rst = new ReplSetTest({nodes: [{}, {rsConfig: {priority: 0}}]}); -rst.startSet(); -rst.initiate(); - -const primary = rst.getPrimary(); -const secondary = rst.getSecondary(); -const primaryDB = primary.getDB(dbName); -const primaryColl = primaryDB[collName]; - -jsTestLog("Do a document write"); -assert.commandWorked( - primaryColl.insert({_id: 0}, {"writeConcern": {"w": "majority"}})); - -// Enable fail point on secondary to cause apply prepare transaction oplog entry's ops to fail -// with write conflict error at least once. -assert.commandWorked(secondary.adminCommand( - {configureFailPoint: "applyPrepareTxnOpsFailsWithWriteConflict", mode: {times: 1}})); - -jsTestLog("Start transaction"); -let session = primary.startSession(); -let sessionDB = session.getDatabase(dbName); -const sessionColl = sessionDB.getCollection(collName); -session.startTransaction({writeConcern: {w: "majority"}}); -assert.commandWorked(sessionColl.insert({_id: 1})); - -// PrepareTransaction cmd will be successful only if secondary is able to retry applying -// prepareTransaction oplog entry on WT_ROLLBACK (WriteConflictException) error. -jsTestLog("Prepare transaction"); -let prepareTimestamp = PrepareHelpers.prepareTransaction(session); - -jsTestLog("Commit transaction"); -assert.commandWorked(PrepareHelpers.commitTransaction(session, prepareTimestamp)); - -// Verify that the committed transaction data is present on secondary. -assert.eq(secondary.getDB(dbName)[collName].findOne({_id: 1}), {_id: 1}); - -// verify that secondaries are not holding any transactional lock resources. -primaryColl.drop(); -rst.awaitReplication(); - -rst.stopSet(); -})(); diff --git a/src/mongo/db/repl/transaction_oplog_application.cpp b/src/mongo/db/repl/transaction_oplog_application.cpp index 4edf468b8b0..eb2a44af338 100644 --- a/src/mongo/db/repl/transaction_oplog_application.cpp +++ b/src/mongo/db/repl/transaction_oplog_application.cpp @@ -56,14 +56,11 @@ MONGO_FAIL_POINT_DEFINE(applyOpsHangBeforePreparingTransaction); // Failpoint that will cause reconstructPreparedTransactions to return early. MONGO_FAIL_POINT_DEFINE(skipReconstructPreparedTransactions); -// Failpoint that causes apply prepare transaction oplog entry's ops to fail with write -// conflict error. -MONGO_FAIL_POINT_DEFINE(applyPrepareTxnOpsFailsWithWriteConflict); // Apply the oplog entries for a prepare or a prepared commit during recovery/initial sync. Status _applyOperationsForTransaction(OperationContext* opCtx, const repl::MultiApplier::Operations& ops, - repl::OplogApplication::Mode oplogApplicationMode) noexcept { + repl::OplogApplication::Mode oplogApplicationMode) { // Apply each the operations via repl::applyOperation. for (const auto& op : ops) { try { @@ -73,21 +70,10 @@ Status _applyOperationsForTransaction(OperationContext* opCtx, if (!status.isOK()) { return status; } - } catch (const DBException& ex) { - // Ignore NamespaceNotFound errors if we are in initial sync or recovering mode. - const bool ignoreException = ex.code() == ErrorCodes::NamespaceNotFound && - (oplogApplicationMode == repl::OplogApplication::Mode::kInitialSync || - oplogApplicationMode == repl::OplogApplication::Mode::kRecovering); - - if (!ignoreException) { - LOG(1) << "Error applying operation in transaction. " << redact(ex) - << "- oplog entry: " << redact(op.toBSON()); - return exceptionToStatus(); - } - LOG(1) << "Encountered but ignoring error: " << redact(ex) - << " while applying operations for transaction because we are either in initial " - "sync or recovering mode - oplog entry: " - << redact(op.toBSON()); + } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>&) { + if (oplogApplicationMode != repl::OplogApplication::Mode::kInitialSync && + oplogApplicationMode != repl::OplogApplication::Mode::kRecovering) + throw; } } return Status::OK(); @@ -356,58 +342,33 @@ Status _applyPrepareTransaction(OperationContext* opCtx, opCtx->setTxnNumber(*entry.getTxnNumber()); opCtx->setInMultiDocumentTransaction(); - return writeConflictRetry(opCtx, "applying prepare transaction", entry.getNss().ns(), [&] { - // The write on transaction table may be applied concurrently, so refreshing state - // from disk may read that write, causing starting a new transaction on an existing - // txnNumber. Thus, we start a new transaction without refreshing state from disk. - MongoDOperationContextSessionWithoutRefresh sessionCheckout(opCtx); - - auto txnParticipant = TransactionParticipant::get(opCtx); - - // Release the WUOW, transaction lock resources and abort storage transaction so that the - // writeConflictRetry loop will be able to retry applying transactional ops on WCE error. - auto abortOnError = makeGuard([&txnParticipant, opCtx] { - // Abort the transaction and invalidate the session it is associated with. - txnParticipant.abortTransaction(opCtx); - txnParticipant.invalidate(opCtx); - }); - - // Starts the WUOW. - txnParticipant.unstashTransactionResources(opCtx, "prepareTransaction"); - - // Set this in case the application of any ops need to use the prepare timestamp of this - // transaction. It should be cleared automatically when the transaction finishes. - if (mode == repl::OplogApplication::Mode::kRecovering) { - txnParticipant.setPrepareOpTimeForRecovery(opCtx, entry.getOpTime()); - } + // The write on transaction table may be applied concurrently, so refreshing state + // from disk may read that write, causing starting a new transaction on an existing + // txnNumber. Thus, we start a new transaction without refreshing state from disk. + MongoDOperationContextSessionWithoutRefresh sessionCheckout(opCtx); - auto status = _applyOperationsForTransaction(opCtx, ops, mode); - - if (MONGO_FAIL_POINT(applyPrepareTxnOpsFailsWithWriteConflict)) { - LOG(0) << "Hit applyPrepareTxnOpsFailsWithWriteConflict failpoint"; - status = Status(ErrorCodes::WriteConflict, - "Prepare transaction apply ops failed due to write conflict"); - } + auto transaction = TransactionParticipant::get(opCtx); + transaction.unstashTransactionResources(opCtx, "prepareTransaction"); + // Set this in case the application of any ops need to use the prepare timestamp of this + // transaction. It should be cleared automatically when the transaction finishes. + if (mode == repl::OplogApplication::Mode::kRecovering) { + transaction.setPrepareOpTimeForRecovery(opCtx, entry.getOpTime()); + } - if (status == ErrorCodes::WriteConflict) { - throw WriteConflictException(); - } - fassert(31137, status); + auto status = _applyOperationsForTransaction(opCtx, ops, mode); + fassert(31137, status); - if (MONGO_FAIL_POINT(applyOpsHangBeforePreparingTransaction)) { - LOG(0) << "Hit applyOpsHangBeforePreparingTransaction failpoint"; - MONGO_FAIL_POINT_PAUSE_WHILE_SET_OR_INTERRUPTED(opCtx, - applyOpsHangBeforePreparingTransaction); - } + if (MONGO_FAIL_POINT(applyOpsHangBeforePreparingTransaction)) { + LOG(0) << "Hit applyOpsHangBeforePreparingTransaction failpoint"; + MONGO_FAIL_POINT_PAUSE_WHILE_SET_OR_INTERRUPTED(opCtx, + applyOpsHangBeforePreparingTransaction); + } - txnParticipant.prepareTransaction(opCtx, entry.getOpTime()); - // Prepare transaction success. - abortOnError.dismiss(); + transaction.prepareTransaction(opCtx, entry.getOpTime()); + transaction.stashTransactionResources(opCtx); - txnParticipant.stashTransactionResources(opCtx); - return Status::OK(); - }); + return Status::OK(); } /** |