summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h
diff options
context:
space:
mode:
authorLingzhi Deng <lingzhi.deng@mongodb.com>2019-05-07 17:57:46 -0400
committerLingzhi Deng <lingzhi.deng@mongodb.com>2019-05-14 17:31:19 -0400
commit7353674ed14d39305b2640805524bb5cfe61cbd1 (patch)
tree0d574a0f69c5f9579be24fb40c70f59455775c44 /src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h
parent00f77c5e43270301bfea2ef8ed330b9d6f59cd3e (diff)
downloadmongo-7353674ed14d39305b2640805524bb5cfe61cbd1.tar.gz
SERVER-40936: Add an invariant that we do not get a prepare conflict while holding a global, database, or collection MODE_S lock
Diffstat (limited to 'src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h')
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h19
1 files changed, 19 insertions, 0 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h b/src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h
index f3031a3105d..b9778c55978 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_prepare_conflict.h
@@ -69,6 +69,25 @@ int wiredTigerPrepareConflictRetry(OperationContext* opCtx, F&& f) {
CurOp::get(opCtx)->debug().additiveMetrics.incrementPrepareReadConflicts(1);
wiredTigerPrepareConflictLog(attempts);
+ const auto lockerInfo = opCtx->lockState()->getLockerInfo(boost::none);
+ invariant(lockerInfo);
+ for (const auto& lock : lockerInfo->locks) {
+ const auto type = lock.resourceId.getType();
+ // If a user operation on secondaries acquires a lock in MODE_S and then blocks on a prepare
+ // conflict with a prepared transaction, deadlock will occur at the commit time of the
+ // prepared transaction when it attempts to reacquire (since locks were yielded on
+ // secondaries) an IX lock that conflicts with the MODE_S lock held by the user operation.
+ // User operations that acquire MODE_X locks and block on prepare conflicts could lead to
+ // the same problem. However, user operations on secondaries should never hold MODE_X locks.
+ // Since prepared transactions will not reacquire RESOURCE_MUTEX / RESOURCE_METADATA locks
+ // at commit time, these lock types are safe. Therefore, invariant here that we do not get a
+ // prepare conflict while holding a global, database, or collection MODE_S lock (or MODE_X
+ // lock for completeness).
+ if (type == RESOURCE_GLOBAL || type == RESOURCE_DATABASE || type == RESOURCE_COLLECTION)
+ invariant(lock.mode != MODE_S && lock.mode != MODE_X,
+ str::stream() << lock.resourceId.toString() << " in " << modeName(lock.mode));
+ }
+
if (MONGO_FAIL_POINT(WTSkipPrepareConflictRetries)) {
// Callers of wiredTigerPrepareConflictRetry() should eventually call wtRCToStatus() via
// invariantWTOK() and have the WT_ROLLBACK error bubble up as a WriteConflictException.