summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-01-27 13:01:45 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-02-11 08:50:52 -0500
commit6e2d6ae03be6592d95334c43a726cde10247bd24 (patch)
treed8a2b6191d9589591b292a783a1c306201f2abf3 /src/mongo/db
parent1c478891a220758259eff7fd6bb1dc0a253a9aa5 (diff)
downloadmongo-6e2d6ae03be6592d95334c43a726cde10247bd24.tar.gz
SERVER-17039 Re-add db.currentOp locking stats
This reintroduces the per-operation locking statistics. Also reverts commit 9b1392162e0f7564cfc3b1634ab78ec1a7f7c871.
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp37
-rw-r--r--src/mongo/db/concurrency/lock_state.h4
-rw-r--r--src/mongo/db/concurrency/lock_stats.cpp175
-rw-r--r--src/mongo/db/concurrency/lock_stats.h161
-rw-r--r--src/mongo/db/concurrency/lock_stats_test.cpp24
-rw-r--r--src/mongo/db/concurrency/locker.h11
-rw-r--r--src/mongo/db/concurrency/locker_noop.h2
-rw-r--r--src/mongo/db/currentop_command.cpp7
-rw-r--r--src/mongo/db/operation_context_impl.cpp6
-rw-r--r--src/mongo/db/stats/lock_server_status_section.cpp2
10 files changed, 261 insertions, 168 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
index eee634857f0..f1f59ca8e14 100644
--- a/src/mongo/db/concurrency/lock_state.cpp
+++ b/src/mongo/db/concurrency/lock_state.cpp
@@ -53,26 +53,22 @@ namespace {
PartitionedInstanceWideLockStats() { }
void recordAcquisition(LockerId id, ResourceId resId, LockMode mode) {
- LockStats& stats = _get(id);
- stats.recordAcquisition(resId, mode);
+ _get(id).recordAcquisition(resId, mode);
}
void recordWait(LockerId id, ResourceId resId, LockMode mode) {
- LockStats& stats = _get(id);
- stats.recordWait(resId, mode);
+ _get(id).recordWait(resId, mode);
}
void recordWaitTime(LockerId id, ResourceId resId, LockMode mode, uint64_t waitMicros) {
- LockStats& stats = _get(id);
- stats.recordWaitTime(resId, mode, waitMicros);
+ _get(id).recordWaitTime(resId, mode, waitMicros);
}
void recordDeadlock(ResourceId resId, LockMode mode) {
- LockStats& stats = _get(resId);
- stats.recordDeadlock(resId, mode);
+ _get(resId).recordDeadlock(resId, mode);
}
- void report(LockStats* outStats) const {
+ void report(SingleThreadedLockStats* outStats) const {
for (int i = 0; i < NumPartitions; i++) {
outStats->append(_partitions[i].stats);
}
@@ -87,16 +83,15 @@ namespace {
private:
// This alignment is a best effort approach to ensure that each partition falls on a
- // separate page/cache line in order to avoid false sharing. The 4096-byte alignment is
- // in an effort to play nicely with NUMA.
- struct MONGO_COMPILER_ALIGN_TYPE(4096) AlignedLockStats {
- LockStats stats;
+ // separate page/cache line in order to avoid false sharing.
+ struct MONGO_COMPILER_ALIGN_TYPE(128) AlignedLockStats {
+ AtomicLockStats stats;
};
enum { NumPartitions = 8 };
- LockStats& _get(LockerId id) {
+ AtomicLockStats& _get(LockerId id) {
return _partitions[id % NumPartitions].stats;
}
@@ -198,10 +193,13 @@ namespace {
}
template<bool IsForMMAPV1>
- void LockerImpl<IsForMMAPV1>::assertEmpty() const {
+ void LockerImpl<IsForMMAPV1>::assertEmptyAndReset() {
invariant(!inAWriteUnitOfWork());
invariant(_resourcesToUnlockAtEndOfUnitOfWork.empty());
invariant(_requests.empty());
+
+ // Reset the locking statistics so the object can be reused
+ _stats.reset();
}
template<bool IsForMMAPV1>
@@ -283,7 +281,7 @@ namespace {
// Cannot delete the Locker while there are still outstanding requests, because the
// LockManager may attempt to access deleted memory. Besides it is probably incorrect
// to delete with unaccounted locks anyways.
- assertEmpty();
+ assertEmptyAndReset();
}
template<bool IsForMMAPV1>
@@ -339,6 +337,11 @@ namespace {
LockRequest* globalLockRequest = _requests.find(resourceIdGlobal).objAddr();
invariant(globalLockRequest->mode == MODE_X);
invariant(globalLockRequest->recursiveCount == 1);
+
+ // Making this call here will record lock downgrades as acquisitions, which is acceptable
+ globalStats.recordAcquisition(_id, resourceIdGlobal, MODE_S);
+ _stats.recordAcquisition(resourceIdGlobal, MODE_S);
+
globalLockManager.downgrade(globalLockRequest, MODE_S);
if (IsForMMAPV1) {
@@ -863,7 +866,7 @@ namespace {
return &globalLockManager;
}
- void reportGlobalLockingStats(LockStats* outStats) {
+ void reportGlobalLockingStats(SingleThreadedLockStats* outStats) {
globalStats.report(outStats);
}
diff --git a/src/mongo/db/concurrency/lock_state.h b/src/mongo/db/concurrency/lock_state.h
index aaf2ad5fa1b..67ec8113310 100644
--- a/src/mongo/db/concurrency/lock_state.h
+++ b/src/mongo/db/concurrency/lock_state.h
@@ -209,7 +209,7 @@ namespace mongo {
// Per-locker locking statistics. Reported in the slow-query log message and through
// db.currentOp. Complementary to the per-instance locking statistics.
- LockStats _stats;
+ SingleThreadedLockStats _stats;
// Delays release of exclusive/intent-exclusive locked resources until the write unit of
// work completes. Value of 0 means we are not inside a write unit of work.
@@ -234,7 +234,7 @@ namespace mongo {
virtual bool isWriteLocked() const;
virtual bool isReadLocked() const;
- virtual void assertEmpty() const;
+ virtual void assertEmptyAndReset();
virtual bool hasLockPending() const { return getWaitingResource().isValid() || _lockPendingParallelWriter; }
diff --git a/src/mongo/db/concurrency/lock_stats.cpp b/src/mongo/db/concurrency/lock_stats.cpp
index 6293d32ada8..70d5a3da065 100644
--- a/src/mongo/db/concurrency/lock_stats.cpp
+++ b/src/mongo/db/concurrency/lock_stats.cpp
@@ -28,158 +28,131 @@
#include "mongo/platform/basic.h"
-#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/concurrency/lock_stats.h"
-namespace mongo {
-
- LockStats::LockStats() {
-
- }
-
- void LockStats::recordAcquisition(ResourceId resId, LockMode mode) {
- PerModeAtomicLockStats& stat = get(resId);
- stat.stats[mode].numAcquisitions.addAndFetch(1);
- }
-
- void LockStats::recordWait(ResourceId resId, LockMode mode) {
- PerModeAtomicLockStats& stat = get(resId);
- stat.stats[mode].numWaits.addAndFetch(1);
- }
-
- void LockStats::recordWaitTime(ResourceId resId, LockMode mode, uint64_t waitMicros) {
- PerModeAtomicLockStats& stat = get(resId);
- stat.stats[mode].combinedWaitTimeMicros.addAndFetch(waitMicros);
- }
-
- void LockStats::recordDeadlock(ResourceId resId, LockMode mode) {
- PerModeAtomicLockStats& stat = get(resId);
- stat.stats[mode].numDeadlocks.addAndFetch(1);
- }
-
- void LockStats::append(const LockStats& other) {
- // Append all lock stats
- for (int i = 0; i < ResourceTypesCount; i++) {
- for (int mode = 0; mode < LockModesCount; mode++) {
- const AtomicLockStats& otherStats = other._stats[i].stats[mode];
-
- AtomicLockStats& thisStats = _stats[i].stats[mode];
- thisStats.append(otherStats);
- }
- }
+#include "mongo/bson/bsonobjbuilder.h"
- // Append the oplog stats
- for (int mode = 0; mode < LockModesCount; mode++) {
- const AtomicLockStats& otherStats = other._oplogStats.stats[mode];
+namespace mongo {
- AtomicLockStats& thisStats = _oplogStats.stats[mode];
- thisStats.append(otherStats);
- }
+ template<typename CounterType>
+ LockStats<CounterType>::LockStats() {
+ reset();
}
- void LockStats::report(BSONObjBuilder* builder) const {
+ template<typename CounterType>
+ void LockStats<CounterType>::report(BSONObjBuilder* builder) const {
// All indexing below starts from offset 1, because we do not want to report/account
// position 0, which is a sentinel value for invalid resource/no lock.
-
for (int i = 1; i < ResourceTypesCount; i++) {
- BSONObjBuilder resBuilder(builder->subobjStart(
- resourceTypeName(static_cast<ResourceType>(i))));
-
- _report(&resBuilder, _stats[i]);
-
- resBuilder.done();
+ _report(builder, resourceTypeName(static_cast<ResourceType>(i)), _stats[i]);
}
- BSONObjBuilder resBuilder(builder->subobjStart("oplog"));
- _report(&resBuilder, _oplogStats);
- resBuilder.done();
+ _report(builder, "oplog", _oplogStats);
}
- void LockStats::_report(BSONObjBuilder* builder,
- const PerModeAtomicLockStats& stat) const {
+ template<typename CounterType>
+ void LockStats<CounterType>::_report(BSONObjBuilder* builder,
+ const char* sectionName,
+ const PerModeLockStatCounters& stat) const {
+
+ boost::scoped_ptr<BSONObjBuilder> section;
// All indexing below starts from offset 1, because we do not want to report/account
// position 0, which is a sentinel value for invalid resource/no lock.
// Num acquires
{
- BSONObjBuilder numAcquires(builder->subobjStart("acquireCount"));
+ boost::scoped_ptr<BSONObjBuilder> numAcquires;
for (int mode = 1; mode < LockModesCount; mode++) {
- numAcquires.append(legacyModeName(static_cast<LockMode>(mode)),
- stat.stats[mode].numAcquisitions.load());
+ const long long value = CounterOps::get(stat.modeStats[mode].numAcquisitions);
+ if (value > 0) {
+ if (!numAcquires) {
+ if (!section) {
+ section.reset(new BSONObjBuilder(builder->subobjStart(sectionName)));
+ }
+
+ numAcquires.reset(
+ new BSONObjBuilder(section->subobjStart("acquireCount")));
+ }
+ numAcquires->append(legacyModeName(static_cast<LockMode>(mode)), value);
+ }
}
- numAcquires.done();
}
// Num waits
{
- BSONObjBuilder numWaits(builder->subobjStart("acquireWaitCount"));
+ boost::scoped_ptr<BSONObjBuilder> numWaits;
for (int mode = 1; mode < LockModesCount; mode++) {
- numWaits.append(legacyModeName(static_cast<LockMode>(mode)),
- stat.stats[mode].numWaits.load());
+ const long long value = CounterOps::get(stat.modeStats[mode].numWaits);
+ if (value > 0) {
+ if (!numWaits) {
+ if (!section) {
+ section.reset(new BSONObjBuilder(builder->subobjStart(sectionName)));
+ }
+
+ numWaits.reset(
+ new BSONObjBuilder(section->subobjStart("acquireWaitCount")));
+ }
+ numWaits->append(legacyModeName(static_cast<LockMode>(mode)), value);
+ }
}
- numWaits.done();
}
// Total time waiting
{
- BSONObjBuilder timeAcquiring(builder->subobjStart("timeAcquiringMicros"));
+ boost::scoped_ptr<BSONObjBuilder> timeAcquiring;
for (int mode = 1; mode < LockModesCount; mode++) {
- timeAcquiring.append(legacyModeName(static_cast<LockMode>(mode)),
- stat.stats[mode].combinedWaitTimeMicros.load());
+ const long long value = CounterOps::get(stat.modeStats[mode].combinedWaitTimeMicros);
+ if (value > 0) {
+ if (!timeAcquiring) {
+ if (!section) {
+ section.reset(new BSONObjBuilder(builder->subobjStart(sectionName)));
+ }
+
+ timeAcquiring.reset(
+ new BSONObjBuilder(section->subobjStart("timeAcquiringMicros")));
+ }
+ timeAcquiring->append(legacyModeName(static_cast<LockMode>(mode)), value);
+ }
}
- timeAcquiring.done();
}
// Deadlocks
{
- BSONObjBuilder deadlockCount(builder->subobjStart("deadlockCount"));
+ boost::scoped_ptr<BSONObjBuilder> deadlockCount;
for (int mode = 1; mode < LockModesCount; mode++) {
- deadlockCount.append(legacyModeName(static_cast<LockMode>(mode)),
- stat.stats[mode].numDeadlocks.load());
+ const long long value = CounterOps::get(stat.modeStats[mode].numDeadlocks);
+ if (value > 0) {
+ if (!deadlockCount) {
+ if (!section) {
+ section.reset(new BSONObjBuilder(builder->subobjStart(sectionName)));
+ }
+
+ deadlockCount.reset(
+ new BSONObjBuilder(section->subobjStart("deadlockCount")));
+ }
+ deadlockCount->append(legacyModeName(static_cast<LockMode>(mode)), value);
+ }
}
- deadlockCount.done();
}
}
- void LockStats::reset() {
+ template<typename CounterType>
+ void LockStats<CounterType>::reset() {
for (int i = 0; i < ResourceTypesCount; i++) {
for (int mode = 0; mode < LockModesCount; mode++) {
- _stats[i].stats[mode].reset();
+ _stats[i].modeStats[mode].reset();
}
}
for (int mode = 0; mode < LockModesCount; mode++) {
- _oplogStats.stats[mode].reset();
- }
- }
-
- LockStats::PerModeAtomicLockStats& LockStats::get(ResourceId resId) {
- if (resId == resourceIdOplog) {
- return _oplogStats;
- }
- else {
- return _stats[resId.getType()];
+ _oplogStats.modeStats[mode].reset();
}
}
- //
- // AtomicLockStats
- //
-
- void LockStats::AtomicLockStats::append(const AtomicLockStats& other) {
- numAcquisitions.addAndFetch(other.numAcquisitions.load());
- numWaits.addAndFetch(other.numWaits.load());
- combinedWaitTimeMicros.addAndFetch(other.combinedWaitTimeMicros.load());
- numDeadlocks.addAndFetch(other.numDeadlocks.load());
- }
-
- void LockStats::AtomicLockStats::reset() {
- numAcquisitions.store(0);
- numWaits.store(0);
- combinedWaitTimeMicros.store(0);
- numDeadlocks.store(0);
- }
+ // Ensures that there are instances compiled for LockStats for AtomicInt64 and int64_t
+ template class LockStats<int64_t>;
+ template class LockStats<AtomicInt64>;
} // namespace mongo
diff --git a/src/mongo/db/concurrency/lock_stats.h b/src/mongo/db/concurrency/lock_stats.h
index 2e58ac17e83..2994fb99e3e 100644
--- a/src/mongo/db/concurrency/lock_stats.h
+++ b/src/mongo/db/concurrency/lock_stats.h
@@ -35,61 +35,166 @@ namespace mongo {
class BSONObjBuilder;
+
+ /**
+ * Operations for manipulating the lock statistics abstracting whether they are atomic or not.
+ */
+ struct CounterOps {
+ static int64_t get(const int64_t& counter) {
+ return counter;
+ }
+
+ static int64_t get(const AtomicInt64& counter) {
+ return counter.load();
+ }
+
+ static void set(int64_t& counter, int64_t value) {
+ counter = value;
+ }
+
+ static void set(AtomicInt64& counter, int64_t value) {
+ counter.store(value);
+ }
+
+ static void add(int64_t& counter, int64_t value) {
+ counter += value;
+ }
+
+ static void add(int64_t& counter, const AtomicInt64& value) {
+ counter += value.load();
+ }
+
+ static void add(AtomicInt64& counter, int64_t value) {
+ counter.addAndFetch(value);
+ }
+ };
+
+
+ /**
+ * Bundle of locking statistics values.
+ */
+ template<typename CounterType>
+ struct LockStatCounters {
+
+ template<typename OtherType>
+ void append(const LockStatCounters<OtherType>& other) {
+ CounterOps::add(numAcquisitions, other.numAcquisitions);
+ CounterOps::add(numWaits, other.numWaits);
+ CounterOps::add(combinedWaitTimeMicros, other.combinedWaitTimeMicros);
+ CounterOps::add(numDeadlocks, other.numDeadlocks);
+ }
+
+ void reset() {
+ CounterOps::set(numAcquisitions, 0);
+ CounterOps::set(numWaits, 0);
+ CounterOps::set(combinedWaitTimeMicros, 0);
+ CounterOps::set(numDeadlocks, 0);
+ }
+
+
+ CounterType numAcquisitions;
+ CounterType numWaits;
+ CounterType combinedWaitTimeMicros;
+ CounterType numDeadlocks;
+ };
+
+
+ /**
+ * Templatized lock statistics management class, which can be specialized with atomic integers
+ * for the global stats and with regular integers for the per-locker stats.
+ */
+ template<typename CounterType>
class LockStats {
public:
+ // Declare the type for the lock counters bundle
+ typedef LockStatCounters<CounterType> LockStatCountersType;
/**
- * Locking statistics for the top level locks.
+ * Initializes the locking statistics with zeroes (calls reset).
*/
- struct AtomicLockStats {
- AtomicLockStats() {
- reset();
- }
+ LockStats();
- void append(const AtomicLockStats& other);
- void reset();
+ void recordAcquisition(ResourceId resId, LockMode mode) {
+ CounterOps::add(get(resId, mode).numAcquisitions, 1);
+ }
- AtomicInt64 numAcquisitions;
- AtomicInt64 numWaits;
- AtomicInt64 combinedWaitTimeMicros;
- AtomicInt64 numDeadlocks;
- };
+ void recordWait(ResourceId resId, LockMode mode) {
+ CounterOps::add(get(resId, mode).numWaits, 1);
+ }
- // Keep the per-mode lock stats next to each other in case we want to do fancy operations
- // such as atomic operations on 128-bit values.
- struct PerModeAtomicLockStats {
- AtomicLockStats stats[LockModesCount];
- };
+ void recordWaitTime(ResourceId resId, LockMode mode, int64_t waitMicros) {
+ CounterOps::add(get(resId, mode).combinedWaitTimeMicros, waitMicros);
+ }
+ void recordDeadlock(ResourceId resId, LockMode mode) {
+ CounterOps::add(get(resId, mode).numDeadlocks, 1);
+ }
- LockStats();
+ LockStatCountersType& get(ResourceId resId, LockMode mode) {
+ if (resId == resourceIdOplog) {
+ return _oplogStats.modeStats[mode];
+ }
- void recordAcquisition(ResourceId resId, LockMode mode);
- void recordWait(ResourceId resId, LockMode mode);
- void recordWaitTime(ResourceId resId, LockMode mode, uint64_t waitMicros);
- void recordDeadlock(ResourceId resId, LockMode mode);
+ return _stats[resId.getType()].modeStats[mode];
+ }
- PerModeAtomicLockStats& get(ResourceId resId);
+ template<typename OtherType>
+ void append(const LockStats<OtherType>& other) {
+ typedef LockStatCounters<OtherType> OtherLockStatCountersType;
+
+ // Append all lock stats
+ for (int i = 0; i < ResourceTypesCount; i++) {
+ for (int mode = 0; mode < LockModesCount; mode++) {
+ const OtherLockStatCountersType& otherStats = other._stats[i].modeStats[mode];
+ LockStatCountersType& thisStats = _stats[i].modeStats[mode];
+ thisStats.append(otherStats);
+ }
+ }
+
+ // Append the oplog stats
+ for (int mode = 0; mode < LockModesCount; mode++) {
+ const OtherLockStatCountersType& otherStats = other._oplogStats.modeStats[mode];
+ LockStatCountersType& thisStats = _oplogStats.modeStats[mode];
+ thisStats.append(otherStats);
+ }
+ }
- void append(const LockStats& other);
void report(BSONObjBuilder* builder) const;
void reset();
private:
+ // Necessary for the append call, which accepts argument of type different than our
+ // template parameter.
+ template<typename T>
+ friend class LockStats;
+
+
+ // Keep the per-mode lock stats next to each other in case we want to do fancy operations
+ // such as atomic operations on 128-bit values.
+ struct PerModeLockStatCounters {
+ LockStatCountersType modeStats[LockModesCount];
+ };
+
+
+ void _report(BSONObjBuilder* builder,
+ const char* sectionName,
+ const PerModeLockStatCounters& stat) const;
- void _report(BSONObjBuilder* builder, const PerModeAtomicLockStats& stat) const;
// Split the lock stats per resource type and special-case the oplog so we can collect
// more detailed stats for it.
- PerModeAtomicLockStats _stats[ResourceTypesCount];
- PerModeAtomicLockStats _oplogStats;
+ PerModeLockStatCounters _stats[ResourceTypesCount];
+ PerModeLockStatCounters _oplogStats;
};
+ typedef LockStats<int64_t> SingleThreadedLockStats;
+ typedef LockStats<AtomicInt64> AtomicLockStats;
+
/**
* Reports instance-wide locking statistics, which can then be converted to BSON or logged.
*/
- void reportGlobalLockingStats(LockStats* outStats);
+ void reportGlobalLockingStats(SingleThreadedLockStats* outStats);
/**
* Currently used for testing only.
diff --git a/src/mongo/db/concurrency/lock_stats_test.cpp b/src/mongo/db/concurrency/lock_stats_test.cpp
index 5a38ee4455b..9b148e606bd 100644
--- a/src/mongo/db/concurrency/lock_stats_test.cpp
+++ b/src/mongo/db/concurrency/lock_stats_test.cpp
@@ -44,12 +44,12 @@ namespace mongo {
locker.unlock(resId);
// Make sure that the waits/blocks are zero
- LockStats stats;
+ SingleThreadedLockStats stats;
reportGlobalLockingStats(&stats);
- ASSERT_EQUALS(1, stats.get(resId).stats[MODE_X].numAcquisitions.load());
- ASSERT_EQUALS(0, stats.get(resId).stats[MODE_X].numWaits.load());
- ASSERT_EQUALS(0, stats.get(resId).stats[MODE_X].combinedWaitTimeMicros.load());
+ ASSERT_EQUALS(1, stats.get(resId, MODE_X).numAcquisitions);
+ ASSERT_EQUALS(0, stats.get(resId, MODE_X).numWaits);
+ ASSERT_EQUALS(0, stats.get(resId, MODE_X).combinedWaitTimeMicros);
}
TEST(LockStats, Wait) {
@@ -70,16 +70,16 @@ namespace mongo {
}
// Make sure that the waits/blocks are non-zero
- LockStats stats;
+ SingleThreadedLockStats stats;
reportGlobalLockingStats(&stats);
- ASSERT_EQUALS(1, stats.get(resId).stats[MODE_X].numAcquisitions.load());
- ASSERT_EQUALS(0, stats.get(resId).stats[MODE_X].numWaits.load());
- ASSERT_EQUALS(0, stats.get(resId).stats[MODE_X].combinedWaitTimeMicros.load());
+ ASSERT_EQUALS(1, stats.get(resId, MODE_X).numAcquisitions);
+ ASSERT_EQUALS(0, stats.get(resId, MODE_X).numWaits);
+ ASSERT_EQUALS(0, stats.get(resId, MODE_X).combinedWaitTimeMicros);
- ASSERT_EQUALS(1, stats.get(resId).stats[MODE_S].numAcquisitions.load());
- ASSERT_EQUALS(1, stats.get(resId).stats[MODE_S].numWaits.load());
- ASSERT_GREATER_THAN(stats.get(resId).stats[MODE_S].combinedWaitTimeMicros.load(), 0);
+ ASSERT_EQUALS(1, stats.get(resId, MODE_S).numAcquisitions);
+ ASSERT_EQUALS(1, stats.get(resId, MODE_S).numWaits);
+ ASSERT_GREATER_THAN(stats.get(resId, MODE_S).combinedWaitTimeMicros, 0);
}
TEST(LockStats, Reporting) {
@@ -92,7 +92,7 @@ namespace mongo {
locker.unlock(resId);
// Make sure that the waits/blocks are zero
- LockStats stats;
+ SingleThreadedLockStats stats;
reportGlobalLockingStats(&stats);
BSONObjBuilder builder;
diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h
index 99bbf5c8a7c..d88042f0d69 100644
--- a/src/mongo/db/concurrency/locker.h
+++ b/src/mongo/db/concurrency/locker.h
@@ -207,7 +207,7 @@ namespace mongo {
ResourceId waitingResource;
// Lock timing statistics
- LockStats stats;
+ SingleThreadedLockStats stats;
};
virtual void getLockerInfo(LockerInfo* lockerInfo) const = 0;
@@ -262,9 +262,12 @@ namespace mongo {
virtual bool isWriteLocked() const = 0;
virtual bool isReadLocked() const = 0;
- // This asserts we're not in a WriteUnitOfWork, and there are no requests on the Locker,
- // so it would be safe to call the destructor or reuse the Locker.
- virtual void assertEmpty() const = 0;
+ /**
+ * Asserts that the Locker is effectively not in use and resets the locking statistics.
+ * This means, there should be no locks on it, no WUOW, etc, so it would be safe to call
+ * the destructor or reuse the Locker.
+ */
+ virtual void assertEmptyAndReset() = 0;
/**
* Pending means we are currently trying to get a lock (could be the parallel batch writer
diff --git a/src/mongo/db/concurrency/locker_noop.h b/src/mongo/db/concurrency/locker_noop.h
index 5076ec09320..be834cbc71f 100644
--- a/src/mongo/db/concurrency/locker_noop.h
+++ b/src/mongo/db/concurrency/locker_noop.h
@@ -150,7 +150,7 @@ namespace mongo {
invariant(false);
}
- virtual void assertEmpty() const {
+ virtual void assertEmptyAndReset() {
invariant(false);
}
diff --git a/src/mongo/db/currentop_command.cpp b/src/mongo/db/currentop_command.cpp
index 90ee02b1503..1dd1b784201 100644
--- a/src/mongo/db/currentop_command.cpp
+++ b/src/mongo/db/currentop_command.cpp
@@ -170,6 +170,13 @@ namespace mongo {
// "waitingForLock" section
infoBuilder.append("waitingForLock", lockerInfo.waitingResource.isValid());
+
+ // "lockStats" section
+ {
+ BSONObjBuilder lockStats(infoBuilder.subobjStart("lockStats"));
+ lockerInfo.stats.report(&lockStats);
+ lockStats.done();
+ }
}
} // namespace mongo
diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp
index be86fb419c8..6d95e494d5d 100644
--- a/src/mongo/db/operation_context_impl.cpp
+++ b/src/mongo/db/operation_context_impl.cpp
@@ -50,15 +50,17 @@ namespace mongo {
OperationContextImpl::OperationContextImpl()
: _client(currentClient.get()),
_locker(_client->getLocker()) {
+
invariant(_locker);
+
StorageEngine* storageEngine = getGlobalEnvironment()->getGlobalStorageEngine();
- invariant(storageEngine);
_recovery.reset(storageEngine->newRecoveryUnit());
+
_client->setOperationContext(this);
}
OperationContextImpl::~OperationContextImpl() {
- _locker->assertEmpty();
+ _locker->assertEmptyAndReset();
_client->resetOperationContext();
}
diff --git a/src/mongo/db/stats/lock_server_status_section.cpp b/src/mongo/db/stats/lock_server_status_section.cpp
index b2abd4ce89a..84d1ce53df5 100644
--- a/src/mongo/db/stats/lock_server_status_section.cpp
+++ b/src/mongo/db/stats/lock_server_status_section.cpp
@@ -132,7 +132,7 @@ namespace {
const BSONElement& configElement) const {
BSONObjBuilder ret;
- LockStats stats;
+ SingleThreadedLockStats stats;
reportGlobalLockingStats(&stats);
stats.report(&ret);