summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency/lock_state_test.cpp
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@10gen.com>2018-05-18 09:21:41 -0400
committerDianna Hohensee <dianna.hohensee@10gen.com>2018-05-22 17:33:02 -0400
commitadad00367e75e7c71a781e4610321f7be5d98aa6 (patch)
tree6d9b3bff2d9ebb956dca39c0ef53a549d03240c5 /src/mongo/db/concurrency/lock_state_test.cpp
parent018f33cb0e0f64880295b6d910060365c117a835 (diff)
downloadmongo-adad00367e75e7c71a781e4610321f7be5d98aa6.tar.gz
SERVER-33198 Add complete two-phase locking testing to lock_state_test.cpp
Diffstat (limited to 'src/mongo/db/concurrency/lock_state_test.cpp')
-rw-r--r--src/mongo/db/concurrency/lock_state_test.cpp128
1 files changed, 70 insertions, 58 deletions
diff --git a/src/mongo/db/concurrency/lock_state_test.cpp b/src/mongo/db/concurrency/lock_state_test.cpp
index 00e7e2e0755..4aa0888f51e 100644
--- a/src/mongo/db/concurrency/lock_state_test.cpp
+++ b/src/mongo/db/concurrency/lock_state_test.cpp
@@ -304,67 +304,98 @@ TEST(LockerImpl, CanceledDeadlockUnblocks) {
ASSERT(locker3.unlockGlobal());
}
-TEST(LockerImpl, MODE_ISLocksUseTwoPhaseLockingWhenSharedLocksShouldTwoPhaseLockIsTrue) {
- const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd);
+TEST(LockerImpl, SharedLocksShouldTwoPhaseLockIsTrue) {
+ // Test that when setSharedLocksShouldTwoPhaseLock is true and we are in a WUOW, unlock on IS
+ // and S locks are postponed until endWriteUnitOfWork() is called. Mode IX and X locks always
+ // participate in two-phased locking, regardless of the setting.
+
+ const ResourceId globalResId(RESOURCE_GLOBAL, ResourceId::SINGLETON_GLOBAL);
+ const ResourceId resId1(RESOURCE_DATABASE, "TestDB1"_sd);
+ const ResourceId resId2(RESOURCE_DATABASE, "TestDB2"_sd);
+ const ResourceId resId3(RESOURCE_COLLECTION, "TestDB.collection3"_sd);
+ const ResourceId resId4(RESOURCE_COLLECTION, "TestDB.collection4"_sd);
DefaultLockerImpl locker;
locker.setSharedLocksShouldTwoPhaseLock(true);
- locker.lockGlobal(MODE_IS);
-
- ASSERT_EQ(LOCK_OK, locker.lock(resId, MODE_IS));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_IS));
-
- locker.beginWriteUnitOfWork();
-
- ASSERT_FALSE(locker.unlock(resId));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_IS));
-
- locker.endWriteUnitOfWork();
-
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_NONE));
- locker.unlockGlobal();
-}
-
-TEST(LockerImpl, MODE_ISLocksDoNotUseTwoPhaseLockingWhenSharedLocksShouldTwoPhaseLockIsFalse) {
- const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd);
-
- DefaultLockerImpl locker;
- locker.lockGlobal(MODE_IS);
+ ASSERT_EQ(LOCK_OK, locker.lockGlobal(MODE_IS));
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_IS);
- ASSERT_EQ(LOCK_OK, locker.lock(resId, MODE_IS));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_IS));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId1, MODE_IS));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId2, MODE_IX));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId3, MODE_S));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId4, MODE_X));
+ ASSERT_EQ(locker.getLockMode(resId1), MODE_IS);
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_IX);
+ ASSERT_EQ(locker.getLockMode(resId3), MODE_S);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_X);
locker.beginWriteUnitOfWork();
- ASSERT_TRUE(locker.unlock(resId));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_NONE));
+ ASSERT_FALSE(locker.unlock(resId1));
+ ASSERT_FALSE(locker.unlock(resId2));
+ ASSERT_FALSE(locker.unlock(resId3));
+ ASSERT_FALSE(locker.unlock(resId4));
+ ASSERT_EQ(locker.getLockMode(resId1), MODE_IS);
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_IX);
+ ASSERT_EQ(locker.getLockMode(resId3), MODE_S);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_X);
+
+ ASSERT_FALSE(locker.unlockGlobal());
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_IS);
locker.endWriteUnitOfWork();
- locker.unlockGlobal();
+ ASSERT_EQ(locker.getLockMode(resId1), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId3), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_NONE);
}
-TEST(LockerImpl, MODE_SLocksUseTwoPhaseLockingWhenSharedLocksShouldTwoPhaseLockIsTrue) {
- const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd);
+TEST(LockerImpl, ModeIXAndXLockParticipatesInTwoPhaseLocking) {
+ // Unlock on mode IX and X locks during a WUOW should always be postponed until
+ // endWriteUnitOfWork() is called. Mode IS and S locks should unlock immediately.
+
+ const ResourceId globalResId(RESOURCE_GLOBAL, ResourceId::SINGLETON_GLOBAL);
+ const ResourceId resId1(RESOURCE_DATABASE, "TestDB1"_sd);
+ const ResourceId resId2(RESOURCE_DATABASE, "TestDB2"_sd);
+ const ResourceId resId3(RESOURCE_COLLECTION, "TestDB.collection3"_sd);
+ const ResourceId resId4(RESOURCE_COLLECTION, "TestDB.collection4"_sd);
DefaultLockerImpl locker;
- locker.setSharedLocksShouldTwoPhaseLock(true);
- locker.lockGlobal(MODE_IS);
- ASSERT_EQ(LOCK_OK, locker.lock(resId, MODE_S));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_S));
+ ASSERT_EQ(LOCK_OK, locker.lockGlobal(MODE_IX));
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_IX);
+
+ ASSERT_EQ(LOCK_OK, locker.lock(resId1, MODE_IS));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId2, MODE_IX));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId3, MODE_S));
+ ASSERT_EQ(LOCK_OK, locker.lock(resId4, MODE_X));
+ ASSERT_EQ(locker.getLockMode(resId1), MODE_IS);
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_IX);
+ ASSERT_EQ(locker.getLockMode(resId3), MODE_S);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_X);
locker.beginWriteUnitOfWork();
- ASSERT_FALSE(locker.unlock(resId));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_S));
+ ASSERT_TRUE(locker.unlock(resId1));
+ ASSERT_FALSE(locker.unlock(resId2));
+ ASSERT_TRUE(locker.unlock(resId3));
+ ASSERT_FALSE(locker.unlock(resId4));
+ ASSERT_EQ(locker.getLockMode(resId1), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_IX);
+ ASSERT_EQ(locker.getLockMode(resId3), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_X);
- locker.endWriteUnitOfWork();
+ ASSERT_FALSE(locker.unlockGlobal());
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_IX);
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_NONE));
+ locker.endWriteUnitOfWork();
- locker.unlockGlobal();
+ ASSERT_EQ(locker.getLockMode(resId2), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(resId4), MODE_NONE);
+ ASSERT_EQ(locker.getLockMode(globalResId), MODE_NONE);
}
TEST(LockerImpl, OverrideLockRequestTimeout) {
@@ -438,25 +469,6 @@ TEST(LockerImpl, DoNotWaitForLockAcquisition) {
ASSERT(locker2.unlockGlobal());
}
-TEST(LockerImpl, MODE_SLocksDoNotUseTwoPhaseLockingWhenSharedLocksShouldTwoPhaseLockIsFalse) {
- const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd);
-
- DefaultLockerImpl locker;
- locker.lockGlobal(MODE_IS);
-
- ASSERT_EQ(LOCK_OK, locker.lock(resId, MODE_S));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_S));
-
- locker.beginWriteUnitOfWork();
-
- ASSERT_TRUE(locker.unlock(resId));
- ASSERT_TRUE(locker.isLockHeldForMode(resId, MODE_NONE));
-
- locker.endWriteUnitOfWork();
-
- locker.unlockGlobal();
-}
-
namespace {
/**
* Helper function to determine if 'lockerInfo' contains a lock with ResourceId 'resourceId' and