summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency/lock_manager_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/concurrency/lock_manager_test.cpp')
-rw-r--r--src/mongo/db/concurrency/lock_manager_test.cpp1289
1 files changed, 643 insertions, 646 deletions
diff --git a/src/mongo/db/concurrency/lock_manager_test.cpp b/src/mongo/db/concurrency/lock_manager_test.cpp
index 50fc9826a9b..ce722b6f572 100644
--- a/src/mongo/db/concurrency/lock_manager_test.cpp
+++ b/src/mongo/db/concurrency/lock_manager_test.cpp
@@ -31,792 +31,789 @@
namespace mongo {
- TEST(ResourceId, Semantics) {
- ResourceId resIdDb(RESOURCE_DATABASE, 324334234);
- ASSERT(resIdDb.getType() == RESOURCE_DATABASE);
- ASSERT(resIdDb.getHashId() == 324334234);
-
- ResourceId resIdColl(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- ASSERT(resIdColl.getType() == RESOURCE_COLLECTION);
-
- // Comparison functions
-
- // Make sure the operator < is defined.
- ASSERT(resIdDb < resIdColl || resIdColl < resIdDb);
-
- ResourceId resId(RESOURCE_DATABASE, 324334234);
- ASSERT_EQUALS(resIdDb, resId);
-
- // Assignment functions
- resId = resIdColl;
- ASSERT_EQUALS(resId, resIdColl);
- }
-
- TEST(ResourceId, Constructors) {
- ResourceId resIdString(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- ResourceId resIdStringData(RESOURCE_COLLECTION, StringData("TestDB.collection"));
-
- ASSERT_EQUALS(resIdString, resIdStringData);
- }
-
- TEST(ResourceId, Masking) {
- const ResourceType maxRes = static_cast<ResourceType>(ResourceTypesCount - 1);
- const uint64_t maxHash = (1ULL<<61) - 1; // Only 61 bits usable for hash
- ResourceType resources[3] = { maxRes, RESOURCE_GLOBAL, RESOURCE_METADATA };
- uint64_t hashes[3] = {maxHash, maxHash / 3, maxHash / 3 * 2};
-
- // The test below verifies that types/hashes are stored/retrieved unchanged
- for (int h = 0; h < 3; h++) {
- for (int r = 0; r < 3; r++) {
- ResourceId id(resources[r], hashes[h]);
- ASSERT_EQUALS(id.getHashId(), hashes[h]);
- ASSERT_EQUALS(id.getType(), resources[r]);
- }
+TEST(ResourceId, Semantics) {
+ ResourceId resIdDb(RESOURCE_DATABASE, 324334234);
+ ASSERT(resIdDb.getType() == RESOURCE_DATABASE);
+ ASSERT(resIdDb.getHashId() == 324334234);
+
+ ResourceId resIdColl(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ ASSERT(resIdColl.getType() == RESOURCE_COLLECTION);
+
+ // Comparison functions
+
+ // Make sure the operator < is defined.
+ ASSERT(resIdDb < resIdColl || resIdColl < resIdDb);
+
+ ResourceId resId(RESOURCE_DATABASE, 324334234);
+ ASSERT_EQUALS(resIdDb, resId);
+
+ // Assignment functions
+ resId = resIdColl;
+ ASSERT_EQUALS(resId, resIdColl);
+}
+
+TEST(ResourceId, Constructors) {
+ ResourceId resIdString(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ ResourceId resIdStringData(RESOURCE_COLLECTION, StringData("TestDB.collection"));
+
+ ASSERT_EQUALS(resIdString, resIdStringData);
+}
+
+TEST(ResourceId, Masking) {
+ const ResourceType maxRes = static_cast<ResourceType>(ResourceTypesCount - 1);
+ const uint64_t maxHash = (1ULL << 61) - 1; // Only 61 bits usable for hash
+ ResourceType resources[3] = {maxRes, RESOURCE_GLOBAL, RESOURCE_METADATA};
+ uint64_t hashes[3] = {maxHash, maxHash / 3, maxHash / 3 * 2};
+
+ // The test below verifies that types/hashes are stored/retrieved unchanged
+ for (int h = 0; h < 3; h++) {
+ for (int r = 0; r < 3; r++) {
+ ResourceId id(resources[r], hashes[h]);
+ ASSERT_EQUALS(id.getHashId(), hashes[h]);
+ ASSERT_EQUALS(id.getType(), resources[r]);
}
}
+}
- //
- // LockManager
- //
+//
+// LockManager
+//
- TEST(LockManager, Grant) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+TEST(LockManager, Grant) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- MMAPV1LockerImpl locker;
- TrackingLockGrantNotification notify;
+ MMAPV1LockerImpl locker;
+ TrackingLockGrantNotification notify;
- LockRequest request;
- request.initNew(&locker, &notify);
+ LockRequest request;
+ request.initNew(&locker, &notify);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 1);
- ASSERT(notify.numNotifies == 0);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 1);
+ ASSERT(notify.numNotifies == 0);
- lockMgr.unlock(&request);
- ASSERT(request.recursiveCount == 0);
- }
+ lockMgr.unlock(&request);
+ ASSERT(request.recursiveCount == 0);
+}
- TEST(LockManager, GrantMultipleNoConflict) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+TEST(LockManager, GrantMultipleNoConflict) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- MMAPV1LockerImpl locker;
- TrackingLockGrantNotification notify;
+ MMAPV1LockerImpl locker;
+ TrackingLockGrantNotification notify;
- LockRequest request[6];
- for (int i = 0; i < 6; i++) {
- request[i].initNew(&locker, &notify);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request[i], MODE_S));
+ LockRequest request[6];
+ for (int i = 0; i < 6; i++) {
+ request[i].initNew(&locker, &notify);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request[i], MODE_S));
- ASSERT(request[i].mode == MODE_S);
- ASSERT(request[i].recursiveCount == 1);
- }
-
- ASSERT(notify.numNotifies == 0);
-
- // Free the first
- lockMgr.unlock(&request[0]);
-
- // Free the last
- lockMgr.unlock(&request[5]);
-
- // Free one in the middle
- lockMgr.unlock(&request[3]);
-
- // Free the remaining so the LockMgr does not compain about leaked locks
- lockMgr.unlock(&request[1]);
- lockMgr.unlock(&request[2]);
- lockMgr.unlock(&request[4]);
+ ASSERT(request[i].mode == MODE_S);
+ ASSERT(request[i].recursiveCount == 1);
}
- TEST(LockManager, GrantMultipleFIFOOrder) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ ASSERT(notify.numNotifies == 0);
- std::unique_ptr<MMAPV1LockerImpl> locker[6];
- for (int i = 0; i < 6; i++) {
- locker[i].reset(new MMAPV1LockerImpl());
- }
+ // Free the first
+ lockMgr.unlock(&request[0]);
- TrackingLockGrantNotification notify[6];
+ // Free the last
+ lockMgr.unlock(&request[5]);
- LockRequest request[6];
- for (int i = 0; i < 6; i++) {
- request[i].initNew(locker[i].get(), &notify[i]);
- lockMgr.lock(resId, &request[i], MODE_X);
+ // Free one in the middle
+ lockMgr.unlock(&request[3]);
- ASSERT(request[i].mode == MODE_X);
- ASSERT(request[i].recursiveCount == 1);
- }
+ // Free the remaining so the LockMgr does not compain about leaked locks
+ lockMgr.unlock(&request[1]);
+ lockMgr.unlock(&request[2]);
+ lockMgr.unlock(&request[4]);
+}
- // Release the last held lock and ensure the next one, based on time is granted
- for (int i = 0; i < 5; i++) {
- lockMgr.unlock(&request[i]);
-
- ASSERT(notify[i + 1].numNotifies == 1);
- ASSERT(notify[i + 1].lastResId == resId);
- ASSERT(notify[i + 1].lastResult == LOCK_OK);
- }
+TEST(LockManager, GrantMultipleFIFOOrder) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // Release the last one
- lockMgr.unlock(&request[5]);
+ std::unique_ptr<MMAPV1LockerImpl> locker[6];
+ for (int i = 0; i < 6; i++) {
+ locker[i].reset(new MMAPV1LockerImpl());
}
- TEST(LockManager, GrantRecursive) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ TrackingLockGrantNotification notify[6];
- MMAPV1LockerImpl locker;
- LockRequestCombo request(&locker);
+ LockRequest request[6];
+ for (int i = 0; i < 6; i++) {
+ request[i].initNew(locker[i].get(), &notify[i]);
+ lockMgr.lock(resId, &request[i], MODE_X);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 1);
- ASSERT(request.numNotifies == 0);
-
- // Acquire again, in the same mode
- ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 2);
- ASSERT(request.numNotifies == 0);
-
- // Release first acquire
- lockMgr.unlock(&request);
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 1);
-
- // Release second acquire
- lockMgr.unlock(&request);
- ASSERT(request.recursiveCount == 0);
+ ASSERT(request[i].mode == MODE_X);
+ ASSERT(request[i].recursiveCount == 1);
}
- TEST(LockManager, GrantRecursiveCompatibleConvertUp) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
-
- MMAPV1LockerImpl locker;
- LockRequestCombo request(&locker);
-
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_IS));
- ASSERT(request.mode == MODE_IS);
- ASSERT(request.recursiveCount == 1);
- ASSERT(request.numNotifies == 0);
+ // Release the last held lock and ensure the next one, based on time is granted
+ for (int i = 0; i < 5; i++) {
+ lockMgr.unlock(&request[i]);
- // Acquire again, in *compatible*, but stricter mode
- ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 2);
- ASSERT(request.numNotifies == 0);
-
- // Release the first acquire
- lockMgr.unlock(&request);
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 1);
-
- // Release the second acquire
- lockMgr.unlock(&request);
- ASSERT(request.recursiveCount == 0);
+ ASSERT(notify[i + 1].numNotifies == 1);
+ ASSERT(notify[i + 1].lastResId == resId);
+ ASSERT(notify[i + 1].lastResult == LOCK_OK);
}
- TEST(LockManager, GrantRecursiveNonCompatibleConvertUp) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
-
- MMAPV1LockerImpl locker;
- LockRequestCombo request(&locker);
-
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_S);
- ASSERT(request.recursiveCount == 1);
- ASSERT(request.numNotifies == 0);
-
- // Acquire again, in *non-compatible*, but stricter mode
- ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_X));
- ASSERT(request.mode == MODE_X);
- ASSERT(request.recursiveCount == 2);
- ASSERT(request.numNotifies == 0);
-
- // Release first acquire
- lockMgr.unlock(&request);
- ASSERT(request.mode == MODE_X);
- ASSERT(request.recursiveCount == 1);
+ // Release the last one
+ lockMgr.unlock(&request[5]);
+}
+
+TEST(LockManager, GrantRecursive) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker;
+ LockRequestCombo request(&locker);
+
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 1);
+ ASSERT(request.numNotifies == 0);
+
+ // Acquire again, in the same mode
+ ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 2);
+ ASSERT(request.numNotifies == 0);
+
+ // Release first acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 1);
+
+ // Release second acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.recursiveCount == 0);
+}
+
+TEST(LockManager, GrantRecursiveCompatibleConvertUp) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker;
+ LockRequestCombo request(&locker);
+
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_IS));
+ ASSERT(request.mode == MODE_IS);
+ ASSERT(request.recursiveCount == 1);
+ ASSERT(request.numNotifies == 0);
+
+ // Acquire again, in *compatible*, but stricter mode
+ ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 2);
+ ASSERT(request.numNotifies == 0);
+
+ // Release the first acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 1);
+
+ // Release the second acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.recursiveCount == 0);
+}
+
+TEST(LockManager, GrantRecursiveNonCompatibleConvertUp) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker;
+ LockRequestCombo request(&locker);
+
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_S);
+ ASSERT(request.recursiveCount == 1);
+ ASSERT(request.numNotifies == 0);
+
+ // Acquire again, in *non-compatible*, but stricter mode
+ ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_X));
+ ASSERT(request.mode == MODE_X);
+ ASSERT(request.recursiveCount == 2);
+ ASSERT(request.numNotifies == 0);
+
+ // Release first acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.mode == MODE_X);
+ ASSERT(request.recursiveCount == 1);
+
+ // Release second acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.recursiveCount == 0);
+}
+
+TEST(LockManager, GrantRecursiveNonCompatibleConvertDown) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker;
+ LockRequestCombo request(&locker);
+
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_X));
+ ASSERT(request.mode == MODE_X);
+ ASSERT(request.recursiveCount == 1);
+ ASSERT(request.numNotifies == 0);
+
+ // Acquire again, in *non-compatible*, but less strict mode
+ ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
+ ASSERT(request.mode == MODE_X);
+ ASSERT(request.recursiveCount == 2);
+ ASSERT(request.numNotifies == 0);
+
+ // Release first acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.mode == MODE_X);
+ ASSERT(request.recursiveCount == 1);
+
+ // Release second acquire
+ lockMgr.unlock(&request);
+ ASSERT(request.recursiveCount == 0);
+}
+
+TEST(LockManager, Conflict) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker1;
+ MMAPV1LockerImpl locker2;
+
+ LockRequestCombo request1(&locker1);
+ LockRequestCombo request2(&locker2);
+
+ // First request granted right away
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
+ ASSERT(request1.recursiveCount == 1);
+ ASSERT(request1.numNotifies == 0);
+
+ // Second request must block
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_X));
+ ASSERT(request2.mode == MODE_X);
+ ASSERT(request2.recursiveCount == 1);
+ ASSERT(request2.numNotifies == 0);
+
+ // Release first request
+ lockMgr.unlock(&request1);
+ ASSERT(request1.recursiveCount == 0);
+ ASSERT(request1.numNotifies == 0);
+
+ ASSERT(request2.mode == MODE_X);
+ ASSERT(request2.recursiveCount == 1);
+ ASSERT(request2.numNotifies == 1);
+ ASSERT(request2.lastResult == LOCK_OK);
+
+ // Release second acquire
+ lockMgr.unlock(&request2);
+ ASSERT(request2.recursiveCount == 0);
+
+ ASSERT(request1.numNotifies == 0);
+ ASSERT(request2.numNotifies == 1);
+}
+
+TEST(LockManager, MultipleConflict) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+
+ MMAPV1LockerImpl locker;
+ TrackingLockGrantNotification notify;
+
+ LockRequest request[6];
+ for (int i = 0; i < 6; i++) {
+ request[i].initNew(&locker, &notify);
+
+ if (i == 0) {
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request[i], MODE_X));
+ } else {
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request[i], MODE_X));
+ }
- // Release second acquire
- lockMgr.unlock(&request);
- ASSERT(request.recursiveCount == 0);
+ ASSERT(request[i].mode == MODE_X);
+ ASSERT(request[i].recursiveCount == 1);
}
- TEST(LockManager, GrantRecursiveNonCompatibleConvertDown) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
-
- MMAPV1LockerImpl locker;
- LockRequestCombo request(&locker);
-
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request, MODE_X));
- ASSERT(request.mode == MODE_X);
- ASSERT(request.recursiveCount == 1);
- ASSERT(request.numNotifies == 0);
-
- // Acquire again, in *non-compatible*, but less strict mode
- ASSERT(LOCK_OK == lockMgr.convert(resId, &request, MODE_S));
- ASSERT(request.mode == MODE_X);
- ASSERT(request.recursiveCount == 2);
- ASSERT(request.numNotifies == 0);
+ ASSERT(notify.numNotifies == 0);
- // Release first acquire
- lockMgr.unlock(&request);
- ASSERT(request.mode == MODE_X);
- ASSERT(request.recursiveCount == 1);
+ // Free them one by one and make sure they get granted in the correct order
+ for (int i = 0; i < 6; i++) {
+ lockMgr.unlock(&request[i]);
- // Release second acquire
- lockMgr.unlock(&request);
- ASSERT(request.recursiveCount == 0);
+ if (i < 5) {
+ ASSERT(notify.numNotifies == i + 1);
+ }
}
+}
- TEST(LockManager, Conflict) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
-
- MMAPV1LockerImpl locker1;
- MMAPV1LockerImpl locker2;
-
- LockRequestCombo request1(&locker1);
- LockRequestCombo request2(&locker2);
+TEST(LockManager, ConflictCancelWaiting) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // First request granted right away
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
- ASSERT(request1.recursiveCount == 1);
- ASSERT(request1.numNotifies == 0);
+ MMAPV1LockerImpl locker1;
+ TrackingLockGrantNotification notify1;
- // Second request must block
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_X));
- ASSERT(request2.mode == MODE_X);
- ASSERT(request2.recursiveCount == 1);
- ASSERT(request2.numNotifies == 0);
+ MMAPV1LockerImpl locker2;
+ TrackingLockGrantNotification notify2;
- // Release first request
- lockMgr.unlock(&request1);
- ASSERT(request1.recursiveCount == 0);
- ASSERT(request1.numNotifies == 0);
+ LockRequest request1;
+ request1.initNew(&locker1, &notify1);
- ASSERT(request2.mode == MODE_X);
- ASSERT(request2.recursiveCount == 1);
- ASSERT(request2.numNotifies == 1);
- ASSERT(request2.lastResult == LOCK_OK);
+ LockRequest request2;
+ request2.initNew(&locker2, &notify2);
- // Release second acquire
- lockMgr.unlock(&request2);
- ASSERT(request2.recursiveCount == 0);
-
- ASSERT(request1.numNotifies == 0);
- ASSERT(request2.numNotifies == 1);
- }
+ // First request granted right away
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
+ ASSERT(notify1.numNotifies == 0);
- TEST(LockManager, MultipleConflict) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_X));
- MMAPV1LockerImpl locker;
- TrackingLockGrantNotification notify;
+ // Release second request (which is still in the WAITING mode)
+ lockMgr.unlock(&request2);
+ ASSERT(notify2.numNotifies == 0);
- LockRequest request[6];
- for (int i = 0; i < 6; i++) {
- request[i].initNew(&locker, &notify);
+ ASSERT(request1.mode == MODE_S);
+ ASSERT(request1.recursiveCount == 1);
- if (i == 0) {
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request[i], MODE_X));
- }
- else {
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request[i], MODE_X));
- }
+ // Release second acquire
+ lockMgr.unlock(&request1);
+}
- ASSERT(request[i].mode == MODE_X);
- ASSERT(request[i].recursiveCount == 1);
- }
+TEST(LockManager, ConflictCancelMultipleWaiting) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- ASSERT(notify.numNotifies == 0);
+ MMAPV1LockerImpl locker;
+ TrackingLockGrantNotification notify;
- // Free them one by one and make sure they get granted in the correct order
- for (int i = 0; i < 6; i++) {
- lockMgr.unlock(&request[i]);
+ LockRequest request[6];
+ for (int i = 0; i < 6; i++) {
+ request[i].initNew(&locker, &notify);
+ lockMgr.lock(resId, &request[i], MODE_X);
- if (i < 5) {
- ASSERT(notify.numNotifies == i + 1);
- }
- }
+ ASSERT(request[i].mode == MODE_X);
+ ASSERT(request[i].recursiveCount == 1);
}
- TEST(LockManager, ConflictCancelWaiting) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
-
- MMAPV1LockerImpl locker1;
- TrackingLockGrantNotification notify1;
+ ASSERT(notify.numNotifies == 0);
- MMAPV1LockerImpl locker2;
- TrackingLockGrantNotification notify2;
+ // Free the second (waiting)
+ lockMgr.unlock(&request[1]);
- LockRequest request1;
- request1.initNew(&locker1, &notify1);
+ // Free the last
+ lockMgr.unlock(&request[5]);
- LockRequest request2;
- request2.initNew(&locker2, &notify2);
+ // Free one in the middle
+ lockMgr.unlock(&request[3]);
- // First request granted right away
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
- ASSERT(notify1.numNotifies == 0);
+ // Free the remaining so the LockMgr does not compain about leaked locks
+ lockMgr.unlock(&request[2]);
+ lockMgr.unlock(&request[4]);
+ lockMgr.unlock(&request[0]);
+}
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_X));
+TEST(LockManager, ConflictCancelWaitingConversion) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // Release second request (which is still in the WAITING mode)
- lockMgr.unlock(&request2);
- ASSERT(notify2.numNotifies == 0);
+ MMAPV1LockerImpl locker1;
+ MMAPV1LockerImpl locker2;
- ASSERT(request1.mode == MODE_S);
- ASSERT(request1.recursiveCount == 1);
+ LockRequestCombo request1(&locker1);
+ LockRequestCombo request2(&locker2);
- // Release second acquire
- lockMgr.unlock(&request1);
- }
+ // First request granted right away
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
+ ASSERT(request1.numNotifies == 0);
- TEST(LockManager, ConflictCancelMultipleWaiting) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ // Second request is granted right away
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
+ ASSERT(request2.numNotifies == 0);
- MMAPV1LockerImpl locker;
- TrackingLockGrantNotification notify;
+ // Convert second request to conflicting
+ ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request2, MODE_X));
+ ASSERT(request2.mode == MODE_S);
+ ASSERT(request2.convertMode == MODE_X);
+ ASSERT(request2.numNotifies == 0);
- LockRequest request[6];
- for (int i = 0; i < 6; i++) {
- request[i].initNew(&locker, &notify);
- lockMgr.lock(resId, &request[i], MODE_X);
+ // Cancel the conflicting upgrade
+ lockMgr.unlock(&request2);
+ ASSERT(request2.mode == MODE_S);
+ ASSERT(request2.convertMode == MODE_NONE);
+ ASSERT(request2.numNotifies == 0);
- ASSERT(request[i].mode == MODE_X);
- ASSERT(request[i].recursiveCount == 1);
- }
+ // Free the remaining locks so the LockManager destructor does not complain
+ lockMgr.unlock(&request1);
+ lockMgr.unlock(&request2);
+}
- ASSERT(notify.numNotifies == 0);
+TEST(LockManager, ConflictingConversion) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // Free the second (waiting)
- lockMgr.unlock(&request[1]);
+ MMAPV1LockerImpl locker1;
+ MMAPV1LockerImpl locker2;
- // Free the last
- lockMgr.unlock(&request[5]);
+ LockRequestCombo request1(&locker1);
+ LockRequestCombo request2(&locker2);
- // Free one in the middle
- lockMgr.unlock(&request[3]);
+ // The S requests are granted right away
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
+ ASSERT(request1.numNotifies == 0);
- // Free the remaining so the LockMgr does not compain about leaked locks
- lockMgr.unlock(&request[2]);
- lockMgr.unlock(&request[4]);
- lockMgr.unlock(&request[0]);
- }
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
+ ASSERT(request2.numNotifies == 0);
- TEST(LockManager, ConflictCancelWaitingConversion) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ // Convert first request to conflicting
+ ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request1, MODE_X));
+ ASSERT(request1.numNotifies == 0);
- MMAPV1LockerImpl locker1;
- MMAPV1LockerImpl locker2;
+ // Free the second lock and make sure the first is granted
+ lockMgr.unlock(&request2);
+ ASSERT(request1.mode == MODE_X);
+ ASSERT(request1.numNotifies == 1);
+ ASSERT(request2.numNotifies == 0);
- LockRequestCombo request1(&locker1);
- LockRequestCombo request2(&locker2);
+ // Frees the first reference, mode remains X
+ lockMgr.unlock(&request1);
+ ASSERT(request1.mode == MODE_X);
+ ASSERT(request1.recursiveCount == 1);
- // First request granted right away
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
- ASSERT(request1.numNotifies == 0);
+ lockMgr.unlock(&request1);
+}
- // Second request is granted right away
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
- ASSERT(request2.numNotifies == 0);
+TEST(LockManager, ConflictingConversionInTheMiddle) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // Convert second request to conflicting
- ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request2, MODE_X));
- ASSERT(request2.mode == MODE_S);
- ASSERT(request2.convertMode == MODE_X);
- ASSERT(request2.numNotifies == 0);
+ MMAPV1LockerImpl locker;
+ TrackingLockGrantNotification notify;
- // Cancel the conflicting upgrade
- lockMgr.unlock(&request2);
- ASSERT(request2.mode == MODE_S);
- ASSERT(request2.convertMode == MODE_NONE);
- ASSERT(request2.numNotifies == 0);
-
- // Free the remaining locks so the LockManager destructor does not complain
- lockMgr.unlock(&request1);
- lockMgr.unlock(&request2);
+ LockRequest request[3];
+ for (int i = 0; i < 3; i++) {
+ request[i].initNew(&locker, &notify);
+ lockMgr.lock(resId, &request[i], MODE_S);
}
- TEST(LockManager, ConflictingConversion) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ // Upgrade the one in the middle (not the first one)
+ ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request[1], MODE_X));
- MMAPV1LockerImpl locker1;
- MMAPV1LockerImpl locker2;
+ ASSERT(notify.numNotifies == 0);
- LockRequestCombo request1(&locker1);
- LockRequestCombo request2(&locker2);
+ // Release the two shared modes
+ lockMgr.unlock(&request[0]);
+ ASSERT(notify.numNotifies == 0);
- // The S requests are granted right away
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
- ASSERT(request1.numNotifies == 0);
+ lockMgr.unlock(&request[2]);
+ ASSERT(notify.numNotifies == 1);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
- ASSERT(request2.numNotifies == 0);
+ ASSERT(request[1].mode == MODE_X);
- // Convert first request to conflicting
- ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request1, MODE_X));
- ASSERT(request1.numNotifies == 0);
+ // Request 1 should be unlocked twice
+ lockMgr.unlock(&request[1]);
+ lockMgr.unlock(&request[1]);
+}
- // Free the second lock and make sure the first is granted
- lockMgr.unlock(&request2);
- ASSERT(request1.mode == MODE_X);
- ASSERT(request1.numNotifies == 1);
- ASSERT(request2.numNotifies == 0);
+TEST(LockManager, ConvertUpgrade) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- // Frees the first reference, mode remains X
- lockMgr.unlock(&request1);
- ASSERT(request1.mode == MODE_X);
- ASSERT(request1.recursiveCount == 1);
+ MMAPV1LockerImpl locker1;
+ LockRequestCombo request1(&locker1);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
- lockMgr.unlock(&request1);
- }
+ MMAPV1LockerImpl locker2;
+ LockRequestCombo request2(&locker2);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
- TEST(LockManager, ConflictingConversionInTheMiddle) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ // Upgrade the S lock to X
+ ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request1, MODE_X));
- MMAPV1LockerImpl locker;
- TrackingLockGrantNotification notify;
+ ASSERT(!lockMgr.unlock(&request1));
+ ASSERT(lockMgr.unlock(&request1));
- LockRequest request[3];
- for (int i = 0; i < 3; i++) {
- request[i].initNew(&locker, &notify);
- lockMgr.lock(resId, &request[i], MODE_S);
- }
+ ASSERT(lockMgr.unlock(&request2));
+}
- // Upgrade the one in the middle (not the first one)
- ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request[1], MODE_X));
+TEST(LockManager, Downgrade) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- ASSERT(notify.numNotifies == 0);
+ MMAPV1LockerImpl locker1;
+ LockRequestCombo request1(&locker1);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_X));
- // Release the two shared modes
- lockMgr.unlock(&request[0]);
- ASSERT(notify.numNotifies == 0);
+ MMAPV1LockerImpl locker2;
+ LockRequestCombo request2(&locker2);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_S));
- lockMgr.unlock(&request[2]);
- ASSERT(notify.numNotifies == 1);
+ // Downgrade the X request to S
+ lockMgr.downgrade(&request1, MODE_S);
- ASSERT(request[1].mode == MODE_X);
+ ASSERT(request2.numNotifies == 1);
+ ASSERT(request2.lastResult == LOCK_OK);
+ ASSERT(request2.recursiveCount == 1);
- // Request 1 should be unlocked twice
- lockMgr.unlock(&request[1]);
- lockMgr.unlock(&request[1]);
- }
+ ASSERT(lockMgr.unlock(&request1));
+ ASSERT(lockMgr.unlock(&request2));
+}
- TEST(LockManager, ConvertUpgrade) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- MMAPV1LockerImpl locker1;
- LockRequestCombo request1(&locker1);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_S));
+// Lock conflict matrix tests
+static void checkConflict(LockMode existingMode, LockMode newMode, bool hasConflict) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
- MMAPV1LockerImpl locker2;
- LockRequestCombo request2(&locker2);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_S));
+ MMAPV1LockerImpl lockerExisting;
+ TrackingLockGrantNotification notifyExisting;
+ LockRequest requestExisting;
+ requestExisting.initNew(&lockerExisting, &notifyExisting);
- // Upgrade the S lock to X
- ASSERT(LOCK_WAITING == lockMgr.convert(resId, &request1, MODE_X));
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestExisting, existingMode));
- ASSERT(!lockMgr.unlock(&request1));
- ASSERT(lockMgr.unlock(&request1));
+ MMAPV1LockerImpl lockerNew;
+ TrackingLockGrantNotification notifyNew;
+ LockRequest requestNew;
+ requestNew.initNew(&lockerNew, &notifyNew);
- ASSERT(lockMgr.unlock(&request2));
+ LockResult result = lockMgr.lock(resId, &requestNew, newMode);
+ if (hasConflict) {
+ ASSERT_EQUALS(LOCK_WAITING, result);
+ } else {
+ ASSERT_EQUALS(LOCK_OK, result);
}
- TEST(LockManager, Downgrade) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ lockMgr.unlock(&requestNew);
+ lockMgr.unlock(&requestExisting);
+}
- MMAPV1LockerImpl locker1;
- LockRequestCombo request1(&locker1);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_X));
+TEST(LockManager, ValidateConflictMatrix) {
+ checkConflict(MODE_IS, MODE_IS, false);
+ checkConflict(MODE_IS, MODE_IX, false);
+ checkConflict(MODE_IS, MODE_S, false);
+ checkConflict(MODE_IS, MODE_X, true);
- MMAPV1LockerImpl locker2;
- LockRequestCombo request2(&locker2);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_S));
+ checkConflict(MODE_IX, MODE_IS, false);
+ checkConflict(MODE_IX, MODE_IX, false);
+ checkConflict(MODE_IX, MODE_S, true);
+ checkConflict(MODE_IX, MODE_X, true);
- // Downgrade the X request to S
- lockMgr.downgrade(&request1, MODE_S);
+ checkConflict(MODE_S, MODE_IS, false);
+ checkConflict(MODE_S, MODE_IX, true);
+ checkConflict(MODE_S, MODE_S, false);
+ checkConflict(MODE_S, MODE_X, true);
- ASSERT(request2.numNotifies == 1);
- ASSERT(request2.lastResult == LOCK_OK);
- ASSERT(request2.recursiveCount == 1);
+ checkConflict(MODE_X, MODE_IS, true);
+ checkConflict(MODE_X, MODE_IX, true);
+ checkConflict(MODE_X, MODE_S, true);
+ checkConflict(MODE_X, MODE_X, true);
+}
- ASSERT(lockMgr.unlock(&request1));
- ASSERT(lockMgr.unlock(&request2));
- }
+TEST(LockManager, EnqueueAtFront) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ MMAPV1LockerImpl lockerX;
+ LockRequestCombo requestX(&lockerX);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestX, MODE_X));
- // Lock conflict matrix tests
- static void checkConflict(LockMode existingMode, LockMode newMode, bool hasConflict) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ // The subsequent request will block
+ MMAPV1LockerImpl lockerLow;
+ LockRequestCombo requestLow(&lockerLow);
- MMAPV1LockerImpl lockerExisting;
- TrackingLockGrantNotification notifyExisting;
- LockRequest requestExisting;
- requestExisting.initNew(&lockerExisting, &notifyExisting);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestLow, MODE_X));
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestExisting, existingMode));
+ // This is a "queue jumping request", which will go before locker 2 above
+ MMAPV1LockerImpl lockerHi;
+ LockRequestCombo requestHi(&lockerHi);
+ requestHi.enqueueAtFront = true;
- MMAPV1LockerImpl lockerNew;
- TrackingLockGrantNotification notifyNew;
- LockRequest requestNew;
- requestNew.initNew(&lockerNew, &notifyNew);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestHi, MODE_X));
- LockResult result = lockMgr.lock(resId, &requestNew, newMode);
- if (hasConflict) {
- ASSERT_EQUALS(LOCK_WAITING, result);
- }
- else {
- ASSERT_EQUALS(LOCK_OK, result);
- }
-
- lockMgr.unlock(&requestNew);
- lockMgr.unlock(&requestExisting);
- }
-
- TEST(LockManager, ValidateConflictMatrix) {
- checkConflict(MODE_IS, MODE_IS, false);
- checkConflict(MODE_IS, MODE_IX, false);
- checkConflict(MODE_IS, MODE_S, false);
- checkConflict(MODE_IS, MODE_X, true);
-
- checkConflict(MODE_IX, MODE_IS, false);
- checkConflict(MODE_IX, MODE_IX, false);
- checkConflict(MODE_IX, MODE_S, true);
- checkConflict(MODE_IX, MODE_X, true);
-
- checkConflict(MODE_S, MODE_IS, false);
- checkConflict(MODE_S, MODE_IX, true);
- checkConflict(MODE_S, MODE_S, false);
- checkConflict(MODE_S, MODE_X, true);
-
- checkConflict(MODE_X, MODE_IS, true);
- checkConflict(MODE_X, MODE_IX, true);
- checkConflict(MODE_X, MODE_S, true);
- checkConflict(MODE_X, MODE_X, true);
- }
+ // Once the X request is gone, lockerHi should be granted, because it's queue jumping
+ ASSERT(lockMgr.unlock(&requestX));
- TEST(LockManager, EnqueueAtFront) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_COLLECTION, std::string("TestDB.collection"));
+ ASSERT(requestHi.lastResId == resId);
+ ASSERT(requestHi.lastResult == LOCK_OK);
- MMAPV1LockerImpl lockerX;
- LockRequestCombo requestX(&lockerX);
+ // Finally lockerLow should be granted
+ ASSERT(lockMgr.unlock(&requestHi));
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestX, MODE_X));
+ ASSERT(requestLow.lastResId == resId);
+ ASSERT(requestLow.lastResult == LOCK_OK);
- // The subsequent request will block
- MMAPV1LockerImpl lockerLow;
- LockRequestCombo requestLow(&lockerLow);
+ // This avoids the lock manager asserting on leaked locks
+ ASSERT(lockMgr.unlock(&requestLow));
+}
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestLow, MODE_X));
+TEST(LockManager, CompatibleFirstImmediateGrant) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_GLOBAL, 0);
- // This is a "queue jumping request", which will go before locker 2 above
- MMAPV1LockerImpl lockerHi;
- LockRequestCombo requestHi(&lockerHi);
- requestHi.enqueueAtFront = true;
+ MMAPV1LockerImpl locker1;
+ LockRequestCombo request1(&locker1);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestHi, MODE_X));
+ MMAPV1LockerImpl locker2;
+ LockRequestCombo request2(&locker2);
+ request2.compatibleFirst = true;
- // Once the X request is gone, lockerHi should be granted, because it's queue jumping
- ASSERT(lockMgr.unlock(&requestX));
+ MMAPV1LockerImpl locker3;
+ LockRequestCombo request3(&locker3);
- ASSERT(requestHi.lastResId == resId);
- ASSERT(requestHi.lastResult == LOCK_OK);
+ // Lock all in IS mode
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_IS));
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_IS));
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &request3, MODE_IS));
- // Finally lockerLow should be granted
- ASSERT(lockMgr.unlock(&requestHi));
+ // Now an exclusive mode comes, which would block
+ MMAPV1LockerImpl lockerX;
+ LockRequestCombo requestX(&lockerX);
- ASSERT(requestLow.lastResId == resId);
- ASSERT(requestLow.lastResult == LOCK_OK);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
- // This avoids the lock manager asserting on leaked locks
- ASSERT(lockMgr.unlock(&requestLow));
+ // If an S comes, it should be granted, because of request2
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
}
- TEST(LockManager, CompatibleFirstImmediateGrant) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_GLOBAL, 0);
-
- MMAPV1LockerImpl locker1;
- LockRequestCombo request1(&locker1);
-
- MMAPV1LockerImpl locker2;
- LockRequestCombo request2(&locker2);
- request2.compatibleFirst = true;
-
- MMAPV1LockerImpl locker3;
- LockRequestCombo request3(&locker3);
-
- // Lock all in IS mode
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request1, MODE_IS));
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request2, MODE_IS));
- ASSERT(LOCK_OK == lockMgr.lock(resId, &request3, MODE_IS));
+ // If request1 goes away, the policy should still be compatible-first, because of request2
+ ASSERT(lockMgr.unlock(&request1));
- // Now an exclusive mode comes, which would block
- MMAPV1LockerImpl lockerX;
- LockRequestCombo requestX(&lockerX);
-
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
-
- // If an S comes, it should be granted, because of request2
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
-
- // If request1 goes away, the policy should still be compatible-first, because of request2
- ASSERT(lockMgr.unlock(&request1));
-
- // If S comes again, it should be granted, because of request2 still there
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
+ // If S comes again, it should be granted, because of request2 still there
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
+ }
- // With request2 gone the policy should go back to FIFO, even though request3 is active
- ASSERT(lockMgr.unlock(&request2));
+ // With request2 gone the policy should go back to FIFO, even though request3 is active
+ ASSERT(lockMgr.unlock(&request2));
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
-
- // Unlock request3 to keep the lock mgr not assert for leaked locks
- ASSERT(lockMgr.unlock(&request3));
- ASSERT(lockMgr.unlock(&requestX));
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
}
- TEST(LockManager, CompatibleFirstDelayedGrant) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_GLOBAL, 0);
-
- MMAPV1LockerImpl lockerXInitial;
- LockRequestCombo requestXInitial(&lockerXInitial);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestXInitial, MODE_X));
-
- MMAPV1LockerImpl locker1;
- LockRequestCombo request1(&locker1);
-
- MMAPV1LockerImpl locker2;
- LockRequestCombo request2(&locker2);
- request2.compatibleFirst = true;
-
- MMAPV1LockerImpl locker3;
- LockRequestCombo request3(&locker3);
-
- // Lock all in IS mode (should block behind the global lock)
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request1, MODE_IS));
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_IS));
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request3, MODE_IS));
-
- // Now an exclusive mode comes, which would block behind the IS modes
- MMAPV1LockerImpl lockerX;
- LockRequestCombo requestX(&lockerX);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
-
- // Free the first X lock so all IS modes are granted
- ASSERT(lockMgr.unlock(&requestXInitial));
- ASSERT(request1.lastResult == LOCK_OK);
- ASSERT(request2.lastResult == LOCK_OK);
- ASSERT(request3.lastResult == LOCK_OK);
-
- // If an S comes, it should be granted, because of request2
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
-
- // If request1 goes away, the policy should still be compatible-first, because of request2
- ASSERT(lockMgr.unlock(&request1));
+ // Unlock request3 to keep the lock mgr not assert for leaked locks
+ ASSERT(lockMgr.unlock(&request3));
+ ASSERT(lockMgr.unlock(&requestX));
+}
+
+TEST(LockManager, CompatibleFirstDelayedGrant) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_GLOBAL, 0);
+
+ MMAPV1LockerImpl lockerXInitial;
+ LockRequestCombo requestXInitial(&lockerXInitial);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestXInitial, MODE_X));
+
+ MMAPV1LockerImpl locker1;
+ LockRequestCombo request1(&locker1);
+
+ MMAPV1LockerImpl locker2;
+ LockRequestCombo request2(&locker2);
+ request2.compatibleFirst = true;
+
+ MMAPV1LockerImpl locker3;
+ LockRequestCombo request3(&locker3);
+
+ // Lock all in IS mode (should block behind the global lock)
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request1, MODE_IS));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request2, MODE_IS));
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &request3, MODE_IS));
+
+ // Now an exclusive mode comes, which would block behind the IS modes
+ MMAPV1LockerImpl lockerX;
+ LockRequestCombo requestX(&lockerX);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
+
+ // Free the first X lock so all IS modes are granted
+ ASSERT(lockMgr.unlock(&requestXInitial));
+ ASSERT(request1.lastResult == LOCK_OK);
+ ASSERT(request2.lastResult == LOCK_OK);
+ ASSERT(request3.lastResult == LOCK_OK);
+
+ // If an S comes, it should be granted, because of request2
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
+ }
- // If S comes again, it should be granted, because of request2 still there
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
+ // If request1 goes away, the policy should still be compatible-first, because of request2
+ ASSERT(lockMgr.unlock(&request1));
- // With request2 gone the policy should go back to FIFO, even though request3 is active
- ASSERT(lockMgr.unlock(&request2));
+ // If S comes again, it should be granted, because of request2 still there
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
+ }
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
+ // With request2 gone the policy should go back to FIFO, even though request3 is active
+ ASSERT(lockMgr.unlock(&request2));
- // Unlock request3 to keep the lock mgr not assert for leaked locks
- ASSERT(lockMgr.unlock(&request3));
- ASSERT(lockMgr.unlock(&requestX));
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
}
- TEST(LockManager, CompatibleFirstCancelWaiting) {
- LockManager lockMgr;
- const ResourceId resId(RESOURCE_GLOBAL, 0);
-
- MMAPV1LockerImpl lockerSInitial;
- LockRequestCombo requestSInitial(&lockerSInitial);
- ASSERT(LOCK_OK == lockMgr.lock(resId, &requestSInitial, MODE_S));
-
- MMAPV1LockerImpl lockerX;
- LockRequestCombo requestX(&lockerX);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
-
- MMAPV1LockerImpl lockerPending;
- LockRequestCombo requestPending(&lockerPending);
- requestPending.compatibleFirst = true;
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestPending, MODE_S));
-
- // S1 is not granted yet, so the policy should still be FIFO
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
+ // Unlock request3 to keep the lock mgr not assert for leaked locks
+ ASSERT(lockMgr.unlock(&request3));
+ ASSERT(lockMgr.unlock(&requestX));
+}
+
+TEST(LockManager, CompatibleFirstCancelWaiting) {
+ LockManager lockMgr;
+ const ResourceId resId(RESOURCE_GLOBAL, 0);
+
+ MMAPV1LockerImpl lockerSInitial;
+ LockRequestCombo requestSInitial(&lockerSInitial);
+ ASSERT(LOCK_OK == lockMgr.lock(resId, &requestSInitial, MODE_S));
+
+ MMAPV1LockerImpl lockerX;
+ LockRequestCombo requestX(&lockerX);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestX, MODE_X));
+
+ MMAPV1LockerImpl lockerPending;
+ LockRequestCombo requestPending(&lockerPending);
+ requestPending.compatibleFirst = true;
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestPending, MODE_S));
+
+ // S1 is not granted yet, so the policy should still be FIFO
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
+ }
- // Unlock S1, the policy should still be FIFO
- ASSERT(lockMgr.unlock(&requestPending));
+ // Unlock S1, the policy should still be FIFO
+ ASSERT(lockMgr.unlock(&requestPending));
- {
- MMAPV1LockerImpl lockerS;
- LockRequestCombo requestS(&lockerS);
- ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
- ASSERT(lockMgr.unlock(&requestS));
- }
-
- // Unlock remaining locks to keep the leak detection logic happy
- ASSERT(lockMgr.unlock(&requestSInitial));
- ASSERT(lockMgr.unlock(&requestX));
+ {
+ MMAPV1LockerImpl lockerS;
+ LockRequestCombo requestS(&lockerS);
+ ASSERT(LOCK_WAITING == lockMgr.lock(resId, &requestS, MODE_S));
+ ASSERT(lockMgr.unlock(&requestS));
}
-} // namespace mongo
+ // Unlock remaining locks to keep the leak detection logic happy
+ ASSERT(lockMgr.unlock(&requestSInitial));
+ ASSERT(lockMgr.unlock(&requestX));
+}
+
+} // namespace mongo