diff options
author | Geert Bosch <geert@mongodb.com> | 2016-11-01 11:33:50 -0400 |
---|---|---|
committer | Geert Bosch <geert@mongodb.com> | 2017-01-23 15:18:28 -0500 |
commit | acf33ea3cf2b9443246cbc67fae104636c7e7790 (patch) | |
tree | c78e539e2b0bbddbde2fb4268f30d8f44908f7cb | |
parent | cf7c424372c733f572831c42f3a5810bef45543e (diff) | |
download | mongo-acf33ea3cf2b9443246cbc67fae104636c7e7790.tar.gz |
SERVER-26860 add more unittests for compatible-first locking policy
(cherry picked from commit e36723dd520ca56ba9b0c59a711207741e422697)
-rw-r--r-- | src/mongo/db/concurrency/lock_manager.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_manager_test.cpp | 91 |
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) { |