summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency
diff options
context:
space:
mode:
authorGeert Bosch <geert@mongodb.com>2016-11-01 11:33:50 -0400
committerGeert Bosch <geert@mongodb.com>2017-01-23 15:18:28 -0500
commitacf33ea3cf2b9443246cbc67fae104636c7e7790 (patch)
treec78e539e2b0bbddbde2fb4268f30d8f44908f7cb /src/mongo/db/concurrency
parentcf7c424372c733f572831c42f3a5810bef45543e (diff)
downloadmongo-acf33ea3cf2b9443246cbc67fae104636c7e7790.tar.gz
SERVER-26860 add more unittests for compatible-first locking policy
(cherry picked from commit e36723dd520ca56ba9b0c59a711207741e422697)
Diffstat (limited to 'src/mongo/db/concurrency')
-rw-r--r--src/mongo/db/concurrency/lock_manager.cpp4
-rw-r--r--src/mongo/db/concurrency/lock_manager_test.cpp91
2 files changed, 57 insertions, 38 deletions
diff --git a/src/mongo/db/concurrency/lock_manager.cpp b/src/mongo/db/concurrency/lock_manager.cpp
index 6f8d1fb8a46..c569faf478d 100644
--- a/src/mongo/db/concurrency/lock_manager.cpp
+++ b/src/mongo/db/concurrency/lock_manager.cpp
@@ -781,8 +781,8 @@ void LockManager::_onLockModeChanged(LockHead* lock, bool checkConflictQueue) {
iter->notify->notify(lock->resourceId, LOCK_OK);
- // Small optimization - nothing is compatible with MODE_X, so no point in looking
- // further in the conflict queue.
+ // Small optimization - nothing is compatible with a newly granted MODE_X, so no point in
+ // looking further in the conflict queue. Conflicting MODE_X requests are skipped above.
if (iter->mode == MODE_X) {
break;
}
diff --git a/src/mongo/db/concurrency/lock_manager_test.cpp b/src/mongo/db/concurrency/lock_manager_test.cpp
index 8620e8001a4..4fcda52ae89 100644
--- a/src/mongo/db/concurrency/lock_manager_test.cpp
+++ b/src/mongo/db/concurrency/lock_manager_test.cpp
@@ -26,6 +26,7 @@
* it in the license file.
*/
+#include "mongo/db/concurrency/lock_manager_defs.h"
#include "mongo/db/concurrency/lock_manager_test_help.h"
#include "mongo/unittest/unittest.h"
@@ -747,42 +748,60 @@ TEST(LockManager, CompatibleFirstGrantAlreadyQueued) {
LockManager lockMgr;
const ResourceId resId(RESOURCE_GLOBAL, 0);
- // This tests the following behavior:
- // Lock held in X, queue: S IX IS, where S is compatibleFirst.
- // Once X unlocks both the S and IS requests should proceed.
-
- MMAPV1LockerImpl locker1;
- LockRequestCombo request1(&locker1);
-
- MMAPV1LockerImpl locker2;
- LockRequestCombo request2(&locker2);
- request2.compatibleFirst = true;
-
- MMAPV1LockerImpl locker3;
- LockRequestCombo request3(&locker3);
-
- MMAPV1LockerImpl locker4;
- LockRequestCombo request4(&locker4);
-
- // Hold the lock in X and establish the S IX IS queue.
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_X));
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_S));
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request3, MODE_IX));
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request4, MODE_IS));
-
- // Now unlock, so all readers should be able to proceed, while the IX remains queued.
- ASSERT(lockMgr.unlock(&request1));
- ASSERT(request2.lastResult == LOCK_OK);
- ASSERT(request3.lastResult == LOCK_INVALID);
- ASSERT(request4.lastResult == LOCK_OK);
-
- // Now unlock the S lock, and the IX succeeds as well.
- ASSERT(lockMgr.unlock(&request2));
- ASSERT(request3.lastResult == LOCK_OK);
-
- // Unlock remaining
- ASSERT(lockMgr.unlock(&request4));
- ASSERT(lockMgr.unlock(&request3));
+ // This tests the following behaviors (alternatives indicated with '|'):
+ // Lock held in X, queue: S X|IX IS, where S is compatibleFirst.
+ // Once X unlocks|downgrades both the S and IS requests should proceed.
+
+
+ enum UnblockMethod { kDowngrading, kUnlocking };
+ LockMode conflictingModes[2] = {MODE_IX, MODE_X};
+ UnblockMethod unblockMethods[2] = {kDowngrading, kUnlocking};
+
+ for (LockMode writerMode : conflictingModes) {
+ for (UnblockMethod unblockMethod : unblockMethods) {
+ MMAPV1LockerImpl locker1;
+ LockRequestCombo request1(&locker1);
+
+ MMAPV1LockerImpl locker2;
+ LockRequestCombo request2(&locker2);
+ request2.compatibleFirst = true;
+
+ MMAPV1LockerImpl locker3;
+ LockRequestCombo request3(&locker3);
+
+ MMAPV1LockerImpl locker4;
+ LockRequestCombo request4(&locker4);
+
+ // Hold the lock in X and establish the S IX|X IS queue.
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_X));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_S));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request3, writerMode));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request4, MODE_IS));
+
+ // Now unlock the initial X, so all readers should be able to proceed, while the writer
+ // remains queued.
+ if (unblockMethod == kUnlocking) {
+ ASSERT(lockMgr.unlock(&request1));
+ } else {
+ invariant(unblockMethod == kDowngrading);
+ lockMgr.downgrade(&request1, MODE_S);
+ }
+ ASSERT(request2.lastResult == LOCK_OK);
+ ASSERT(request3.lastResult == LOCK_INVALID);
+ ASSERT(request4.lastResult == LOCK_OK);
+
+ // Now unlock the readers, and the writer succeeds as well.
+ ASSERT(lockMgr.unlock(&request2));
+ ASSERT(lockMgr.unlock(&request4));
+ if (unblockMethod == kDowngrading) {
+ ASSERT(lockMgr.unlock(&request1));
+ }
+ ASSERT(request3.lastResult == LOCK_OK);
+
+ // Unlock the writer
+ ASSERT(lockMgr.unlock(&request3));
+ }
+ }
}
TEST(LockManager, CompatibleFirstDelayedGrant) {