summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@mongodb.com>2021-06-14 21:41:37 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-08-20 17:41:09 +0000
commit18315d2e163ce47d0d7ca7503961c4566e04d70a (patch)
tree6717195272f81dc8957a9beea7c433e50d916ab8
parentdcca76b8c10312a88ae4e6ae43c69cfbea0a1b1a (diff)
downloadmongo-18315d2e163ce47d0d7ca7503961c4566e04d70a.tar.gz
SERVER-57360 Log additional debug info for invariant(_requests.empty()) in ~LockerImpl
(cherry picked from commit a260a07648a984acaa54ab8cb1d18b37434d1b97)
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp20
-rw-r--r--src/mongo/db/concurrency/lock_state.h5
-rw-r--r--src/mongo/db/concurrency/lock_state_test.cpp17
-rw-r--r--src/mongo/db/concurrency/locker_noop.h3
4 files changed, 44 insertions, 1 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
index b684416b445..0b4a5dce0c9 100644
--- a/src/mongo/db/concurrency/lock_state.cpp
+++ b/src/mongo/db/concurrency/lock_state.cpp
@@ -205,6 +205,21 @@ void LockerImpl::dump() const {
log() << ss.str();
}
+void LockerImpl::_dumpLockerAndLockManagerRequests() {
+ // Log the _requests that this locker holds. This will provide identifying information to cross
+ // reference with the LockManager dump below for extra information.
+ dump();
+
+ // Log the LockManager's lock information. Given the locker 'dump()' above, we should be able to
+ // easily cross reference to find the lock info matching this operation. The LockManager can
+ // safely access (under internal locks) the LockRequest data that the locker cannot.
+ BSONObjBuilder builder;
+ auto lockToClientMap = LockManager::getLockToClientMap(getGlobalServiceContext());
+ getGlobalLockManager()->getLockInfoBSON(lockToClientMap, &builder);
+ auto lockInfo = builder.done();
+ LOG(0) << "Operation ending while holding locks. LockInfo" << redact(lockInfo.toString());
+}
+
//
// CondVarLockGrantNotification
@@ -286,7 +301,12 @@ LockerImpl::~LockerImpl() {
// to delete with unaccounted locks anyways.
invariant(!inAWriteUnitOfWork());
invariant(_numResourcesToUnlockAtEndUnitOfWork == 0);
+
+ if (!_requests.empty()) {
+ _dumpLockerAndLockManagerRequests();
+ }
invariant(_requests.empty());
+
invariant(_modeForTicket == MODE_NONE);
// Reset the locking statistics so the object can be reused
diff --git a/src/mongo/db/concurrency/lock_state.h b/src/mongo/db/concurrency/lock_state.h
index 386ea3aa196..dfa0e709d77 100644
--- a/src/mongo/db/concurrency/lock_state.h
+++ b/src/mongo/db/concurrency/lock_state.h
@@ -321,6 +321,11 @@ private:
*/
bool _acquireTicket(OperationContext* opCtx, LockMode mode, Date_t deadline);
+ /**
+ * Calls dump() on this locker instance and the lock manager.
+ */
+ void _dumpLockerAndLockManagerRequests();
+
// Used to disambiguate different lockers
const LockerId _id;
diff --git a/src/mongo/db/concurrency/lock_state_test.cpp b/src/mongo/db/concurrency/lock_state_test.cpp
index 00297be4d37..35658b02284 100644
--- a/src/mongo/db/concurrency/lock_state_test.cpp
+++ b/src/mongo/db/concurrency/lock_state_test.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/concurrency/lock_manager_test_help.h"
#include "mongo/db/concurrency/locker.h"
#include "mongo/db/service_context_test_fixture.h"
+#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
@@ -1143,4 +1144,20 @@ TEST_F(LockerImplTest, ConvertLockPendingUnlockAndUnlock) {
locker.unlockGlobal();
}
+// This test exercises the lock dumping code in ~LockerImpl in case locks are held on destruction.
+DEATH_TEST_F(LockerImplTest,
+ LocksHeldOnDestructionCausesALocksDump,
+ "Operation ending while holding locks.") {
+ const ResourceId resId(RESOURCE_COLLECTION, "TestDB.collection"_sd);
+
+ LockerImpl locker;
+ locker.lockGlobal(MODE_IX);
+ locker.lock(resId, MODE_X);
+
+ ASSERT(locker.isLockHeldForMode(resId, MODE_X));
+ ASSERT(locker.isLockHeldForMode(resId, MODE_S));
+
+ // 'locker' destructor should invariant because locks are still held.
+}
+
} // namespace mongo
diff --git a/src/mongo/db/concurrency/locker_noop.h b/src/mongo/db/concurrency/locker_noop.h
index 3780e4f5c0b..0dc626e7ec7 100644
--- a/src/mongo/db/concurrency/locker_noop.h
+++ b/src/mongo/db/concurrency/locker_noop.h
@@ -51,7 +51,8 @@ public:
}
virtual LockerId getId() const {
- MONGO_UNREACHABLE;
+ // For unit testing.
+ return -7;
}
stdx::thread::id getThreadId() const override {