diff options
author | Ian Whalen <ian.whalen@gmail.com> | 2014-10-23 15:11:20 -0400 |
---|---|---|
committer | Ian Whalen <ian.whalen@gmail.com> | 2014-10-23 15:11:20 -0400 |
commit | f9b55402aa1155d9a3f2130110d25f9f0322c5a9 (patch) | |
tree | 98a63c9944b37d88f0f6579756f3ce65ea114900 /src | |
parent | 5f4cc63e737af5a4fa19d2f0cf33599c231ef1e4 (diff) | |
download | mongo-f9b55402aa1155d9a3f2130110d25f9f0322c5a9.tar.gz |
Revert "SERVER-15541 Simplify the save/restore lock state code"
This reverts commit 5f4cc63e737af5a4fa19d2f0cf33599c231ef1e4.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 58 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state_test.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker.h | 8 |
3 files changed, 58 insertions, 9 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 7168b2529a9..de5ed8ccf63 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -396,6 +396,9 @@ namespace mongo { globalLockManager.downgrade(globalLockRequest, MODE_S); if (IsForMMAPV1) { + LockRequest* flushLockRequest = _requests.find(resourceIdMMAPV1Flush).objAddr(); + invariant(flushLockRequest->mode == MODE_X); + invariant(flushLockRequest->recursiveCount == 1); invariant(unlock(resourceIdMMAPV1Flush)); } } @@ -557,6 +560,7 @@ namespace mongo { // Clear out whatever is in stateOut. stateOut->locks.clear(); stateOut->globalMode = MODE_NONE; + stateOut->globalRecursiveCount = 0; // First, we look at the global lock. There is special handling for this (as the flush // lock goes along with it) so we store it separately from the more pedestrian locks. @@ -574,15 +578,27 @@ namespace mongo { return false; } - // The global lock must have been acquired just once + // The global lock has been acquired just once. + invariant(1 == globalRequest->recursiveCount); stateOut->globalMode = globalRequest->mode; - invariant(unlock(resourceIdGlobal)); - invariant(unlock(resourceIdMMAPV1Flush)); + stateOut->globalRecursiveCount = globalRequest->recursiveCount; + + // Flush lock state is inferred from the global state so we don't bother to store it. // Next, the non-global locks. for (LockRequestsMap::Iterator it = _requests.begin(); !it.finished(); it.next()) { const ResourceId& resId = it.key(); + // This is handled separately from normal locks as mentioned above. + if (resourceIdGlobal == resId) { + continue; + } + + // This is an internal lock that is obtained when the global lock is locked. + if (IsForMMAPV1 && (resourceIdMMAPV1Flush == resId)) { + continue; + } + // We don't support saving and restoring document-level locks. invariant(RESOURCE_DATABASE == resId.getType() || RESOURCE_COLLECTION == resId.getType()); @@ -591,15 +607,33 @@ namespace mongo { Locker::LockSnapshot::OneLock info; info.resourceId = resId; info.mode = it->mode; + info.recursiveCount = it->recursiveCount; stateOut->locks.push_back(info); - - invariant(unlock(resId)); } // Sort locks from coarsest to finest. They'll later be acquired in this order. std::sort(stateOut->locks.begin(), stateOut->locks.end(), SortByGranularity()); + // Unlock everything. + + // Step 1: Unlock all requests that are not-flush and not-global. + for (size_t i = 0; i < stateOut->locks.size(); ++i) { + for (size_t j = 0; j < stateOut->locks[i].recursiveCount; ++j) { + invariant(unlock(stateOut->locks[i].resourceId)); + } + } + + // Step 2: Unlock the global lock. + for (size_t i = 0; i < stateOut->globalRecursiveCount; ++i) { + invariant(unlock(resourceIdGlobal)); + } + + // Step 3: Unlock flush. It's only acquired on the first global lock acquisition + // so we only unlock it once. + if (IsForMMAPV1) { + invariant(unlock(resourceIdMMAPV1Flush)); + } return true; } @@ -608,11 +642,17 @@ namespace mongo { // We shouldn't be saving and restoring lock state from inside a WriteUnitOfWork. invariant(!inAWriteUnitOfWork()); - lockGlobal(state.globalMode); + // We expect to be able to unlock each lock 'recursiveCount' number of times. + // So, we relock each lock that number of times. + + for (size_t i = 0; i < state.globalRecursiveCount; ++i) { + lockGlobal(state.globalMode); + } - std::vector<LockSnapshot::OneLock>::const_iterator it = state.locks.begin(); - for (; it != state.locks.end(); it++) { - invariant(LOCK_OK == lock(it->resourceId, it->mode)); + for (size_t i = 0; i < state.locks.size(); ++i) { + for (size_t j = 0; j < state.locks[i].recursiveCount; ++j) { + invariant(LOCK_OK == lock(state.locks[i].resourceId, state.locks[i].mode)); + } } } diff --git a/src/mongo/db/concurrency/lock_state_test.cpp b/src/mongo/db/concurrency/lock_state_test.cpp index 13f313e9852..64facbee781 100644 --- a/src/mongo/db/concurrency/lock_state_test.cpp +++ b/src/mongo/db/concurrency/lock_state_test.cpp @@ -187,6 +187,7 @@ namespace mongo { locker.saveLockStateAndUnlock(&lockInfo); ASSERT(!locker.isLocked()); ASSERT_EQUALS(MODE_IX, lockInfo.globalMode); + ASSERT_EQUALS(1U, lockInfo.globalRecursiveCount); // Restore the lock(s) we had. locker.restoreLockState(lockInfo); diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h index 9af24522a25..170c582ed5d 100644 --- a/src/mongo/db/concurrency/locker.h +++ b/src/mongo/db/concurrency/locker.h @@ -159,12 +159,20 @@ namespace mongo { // The global lock is handled differently from all other locks. LockMode globalMode; + // One can acquire the global lock repeatedly. + unsigned globalRecursiveCount; + struct OneLock { // What lock resource is held? ResourceId resourceId; // In what mode is it held? LockMode mode; + + // What's the recursive count of this lock? Note that we don't store any state + // about how we got this lock (eg upgrade), just how many times we've locked it + // in this mode. + unsigned recursiveCount; }; // The non-global non-flush locks held, sorted by granularity. That is, locks[i] is |