diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-01-27 13:01:45 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-02-11 08:50:52 -0500 |
commit | 6e2d6ae03be6592d95334c43a726cde10247bd24 (patch) | |
tree | d8a2b6191d9589591b292a783a1c306201f2abf3 /src/mongo/db | |
parent | 1c478891a220758259eff7fd6bb1dc0a253a9aa5 (diff) | |
download | mongo-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.cpp | 37 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.h | 4 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_stats.cpp | 175 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_stats.h | 161 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_stats_test.cpp | 24 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker.h | 11 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker_noop.h | 2 | ||||
-rw-r--r-- | src/mongo/db/currentop_command.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/stats/lock_server_status_section.cpp | 2 |
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); |