summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/transaction_oplog_application.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/repl/transaction_oplog_application.cpp')
-rw-r--r--src/mongo/db/repl/transaction_oplog_application.cpp47
1 files changed, 38 insertions, 9 deletions
diff --git a/src/mongo/db/repl/transaction_oplog_application.cpp b/src/mongo/db/repl/transaction_oplog_application.cpp
index af8fa188671..a71f8470212 100644
--- a/src/mongo/db/repl/transaction_oplog_application.cpp
+++ b/src/mongo/db/repl/transaction_oplog_application.cpp
@@ -35,9 +35,10 @@
#include "mongo/db/catalog_raii.h"
#include "mongo/db/commands/txn_cmds_gen.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/index_builds_coordinator.h"
+#include "mongo/db/op_observer.h"
#include "mongo/db/repl/apply_ops.h"
#include "mongo/db/repl/storage_interface_impl.h"
#include "mongo/db/repl/timestamp_block.h"
@@ -88,9 +89,26 @@ Status _applyOperationsForTransaction(OperationContext* opCtx,
}
} catch (const DBException& ex) {
// Ignore NamespaceNotFound errors if we are in initial sync or recovering mode.
+ // During recovery we reconsutuct prepared transactions at the end after applying all
+ // the oplogs, so 'NamespaceNotFound' error shouldn't be hit whether it is a stable or
+ // unstable recovery. However we have some scenarios when this error should be skipped:
+ // 1- This code path can be called while applying commit oplog during unstable recovery
+ // when 'startupRecoveryForRestore' is set.
+ // 2- During selective backup:
+ // - During restore when 'recoverFromOplogAsStandalone' is set which is usually be
+ // done in a stable recovery mode.
+ // - After the restore finished as the standalone node started with the flag
+ // 'takeUnstableCheckpointOnShutdown' so after restarting the node as a replica
+ // set member it will go through unstable recovery.
const bool ignoreException = ex.code() == ErrorCodes::NamespaceNotFound &&
(oplogApplicationMode == repl::OplogApplication::Mode::kInitialSync ||
- oplogApplicationMode == repl::OplogApplication::Mode::kRecovering);
+ repl::OplogApplication::inRecovering(oplogApplicationMode));
+
+ if (ex.code() == ErrorCodes::NamespaceNotFound &&
+ oplogApplicationMode == repl::OplogApplication::Mode::kStableRecovering) {
+ repl::OplogApplication::checkOnOplogFailureForRecovery(
+ opCtx, op.getNss(), redact(op.toBSONForLogging()), redact(ex));
+ }
if (!ignoreException) {
LOGV2_DEBUG(
@@ -130,7 +148,7 @@ Status _applyTransactionFromOplogChain(OperationContext* opCtx,
repl::OplogApplication::Mode mode,
Timestamp commitTimestamp,
Timestamp durableTimestamp) {
- invariant(mode == repl::OplogApplication::Mode::kRecovering);
+ invariant(repl::OplogApplication::inRecovering(mode));
auto ops = readTransactionOperationsFromOplogChain(opCtx, entry, {});
@@ -189,7 +207,8 @@ Status applyCommitTransaction(OperationContext* opCtx,
invariant(commitCommand.getCommitTimestamp());
switch (mode) {
- case repl::OplogApplication::Mode::kRecovering: {
+ case repl::OplogApplication::Mode::kUnstableRecovering:
+ case repl::OplogApplication::Mode::kStableRecovering: {
return _applyTransactionFromOplogChain(opCtx,
entry,
mode,
@@ -236,7 +255,8 @@ Status applyAbortTransaction(OperationContext* opCtx,
const OplogEntry& entry,
repl::OplogApplication::Mode mode) {
switch (mode) {
- case repl::OplogApplication::Mode::kRecovering: {
+ case repl::OplogApplication::Mode::kUnstableRecovering:
+ case repl::OplogApplication::Mode::kStableRecovering: {
// We don't put transactions into the prepare state until the end of recovery,
// so there is no transaction to abort.
return Status::OK();
@@ -388,7 +408,7 @@ Status _applyPrepareTransaction(OperationContext* opCtx,
// The prepare time of the transaction is set explicitly below.
auto ops = readTransactionOperationsFromOplogChain(opCtx, entry, {});
- if (mode == repl::OplogApplication::Mode::kRecovering ||
+ if (repl::OplogApplication::inRecovering(mode) ||
mode == repl::OplogApplication::Mode::kInitialSync) {
// We might replay a prepared transaction behind oldest timestamp. Note that since this is
// scoped to the storage transaction, and readTransactionOperationsFromOplogChain implicitly
@@ -465,7 +485,7 @@ Status _applyPrepareTransaction(OperationContext* opCtx,
// 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 ||
+ if (repl::OplogApplication::inRecovering(mode) ||
mode == repl::OplogApplication::Mode::kInitialSync) {
txnParticipant.setPrepareOpTimeForRecovery(opCtx, entry.getOpTime());
}
@@ -498,6 +518,11 @@ Status _applyPrepareTransaction(OperationContext* opCtx,
}
txnParticipant.prepareTransaction(opCtx, entry.getOpTime());
+
+ auto opObserver = opCtx->getServiceContext()->getOpObserver();
+ invariant(opObserver);
+ opObserver->onTransactionPrepareNonPrimary(opCtx, ops, entry.getOpTime());
+
// Prepare transaction success.
abortOnError.dismiss();
@@ -543,7 +568,8 @@ Status applyPrepareTransaction(OperationContext* opCtx,
const OplogEntry& entry,
repl::OplogApplication::Mode mode) {
switch (mode) {
- case repl::OplogApplication::Mode::kRecovering: {
+ case repl::OplogApplication::Mode::kUnstableRecovering:
+ case repl::OplogApplication::Mode::kStableRecovering: {
if (!serverGlobalParams.enableMajorityReadConcern) {
LOGV2_ERROR(
21850,
@@ -613,7 +639,10 @@ void reconstructPreparedTransactions(OperationContext* opCtx, repl::OplogApplica
AlternativeClientRegion acr(newClient);
const auto newOpCtx = cc().makeOperationContext();
- _reconstructPreparedTransaction(newOpCtx.get(), prepareOplogEntry, mode);
+ // Ignore interruptions while reconstructing prepared transactions, so that we do not
+ // fassert and crash due to interruptions inside this call.
+ newOpCtx->runWithoutInterruptionExceptAtGlobalShutdown(
+ [&] { _reconstructPreparedTransaction(newOpCtx.get(), prepareOplogEntry, mode); });
}
}
}