diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/concurrency/d_concurrency_test.cpp | 101 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 2 |
2 files changed, 102 insertions, 1 deletions
diff --git a/src/mongo/db/concurrency/d_concurrency_test.cpp b/src/mongo/db/concurrency/d_concurrency_test.cpp index 1a0b49a9e82..735b162dcaf 100644 --- a/src/mongo/db/concurrency/d_concurrency_test.cpp +++ b/src/mongo/db/concurrency/d_concurrency_test.cpp @@ -120,6 +120,12 @@ public: return result; } + + void waitForLockerToHaveWaitingResource(Locker* locker) { + while (!locker->getWaitingResource().isValid()) { + sleepmillis(0); + } + } }; @@ -2243,5 +2249,100 @@ TEST_F(DConcurrencyTestFixture, RSTLLockGuardResilientToExceptionThrownBeforeWai ASSERT_TRUE(firstOpCtx->lockState()->isRSTLExclusive()); } +TEST_F(DConcurrencyTestFixture, FailPointInLockDoesNotFailUninterruptibleGlobalNonIntentLocks) { + FailPointEnableBlock failWaitingNonPartitionedLocks("failNonIntentLocksIfWaitNeeded"); + + LockerImpl locker1; + LockerImpl locker2; + LockerImpl locker3; + + { + locker1.lockGlobal(MODE_IX); + + // MODE_S attempt. + stdx::thread t2([&]() { + UninterruptibleLockGuard noInterrupt(&locker2); + locker2.lockGlobal(MODE_S); + }); + + // Wait for the thread to attempt to acquire the global lock in MODE_S. + waitForLockerToHaveWaitingResource(&locker2); + + locker1.unlockGlobal(); + t2.join(); + locker2.unlockGlobal(); + } + + { + locker1.lockGlobal(MODE_IX); + + // MODE_X attempt. + stdx::thread t3([&]() { + UninterruptibleLockGuard noInterrupt(&locker3); + locker3.lockGlobal(MODE_X); + }); + + // Wait for the thread to attempt to acquire the global lock in MODE_X. + waitForLockerToHaveWaitingResource(&locker3); + + locker1.unlockGlobal(); + t3.join(); + locker3.unlockGlobal(); + } +} + +TEST_F(DConcurrencyTestFixture, FailPointInLockDoesNotFailUninterruptibleNonIntentLocks) { + FailPointEnableBlock failWaitingNonPartitionedLocks("failNonIntentLocksIfWaitNeeded"); + + LockerImpl locker1; + LockerImpl locker2; + LockerImpl locker3; + + // Granted MODE_X lock, fail incoming MODE_S and MODE_X. + const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd); + + locker1.lockGlobal(MODE_IX); + + { + locker1.lock(resId, MODE_X); + + // MODE_S attempt. + stdx::thread t2([&]() { + UninterruptibleLockGuard noInterrupt(&locker2); + locker2.lockGlobal(MODE_IS); + locker2.lock(resId, MODE_S); + }); + + // Wait for the thread to attempt to acquire the collection lock in MODE_S. + waitForLockerToHaveWaitingResource(&locker2); + + locker1.unlock(resId); + t2.join(); + locker2.unlock(resId); + locker2.unlockGlobal(); + } + + { + locker1.lock(resId, MODE_X); + + // MODE_X attempt. + stdx::thread t3([&]() { + UninterruptibleLockGuard noInterrupt(&locker3); + locker3.lockGlobal(MODE_IX); + locker3.lock(resId, MODE_X); + }); + + // Wait for the thread to attempt to acquire the collection lock in MODE_X. + waitForLockerToHaveWaitingResource(&locker3); + + locker1.unlock(resId); + t3.join(); + locker3.unlock(resId); + locker3.unlockGlobal(); + } + + locker1.unlockGlobal(); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 269b7f38ee6..44557163c75 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -904,7 +904,7 @@ void LockerImpl::lockComplete(OperationContext* opCtx, // This failpoint is used to time out non-intent locks if they cannot be granted immediately. // Testing-only. - if (MONGO_FAIL_POINT(failNonIntentLocksIfWaitNeeded)) { + if (!_uninterruptibleLocksRequested && MONGO_FAIL_POINT(failNonIntentLocksIfWaitNeeded)) { uassert(ErrorCodes::LockTimeout, str::stream() << "Cannot immediately acquire lock '" << resId.toString() << "'. Timing out due to failpoint.", |