summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan Whalen <ian.whalen@gmail.com>2014-10-23 15:11:20 -0400
committerIan Whalen <ian.whalen@gmail.com>2014-10-23 15:11:20 -0400
commitf9b55402aa1155d9a3f2130110d25f9f0322c5a9 (patch)
tree98a63c9944b37d88f0f6579756f3ce65ea114900 /src
parent5f4cc63e737af5a4fa19d2f0cf33599c231ef1e4 (diff)
downloadmongo-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.cpp58
-rw-r--r--src/mongo/db/concurrency/lock_state_test.cpp1
-rw-r--r--src/mongo/db/concurrency/locker.h8
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