summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/concurrency/d_concurrency_test.cpp101
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp2
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.",