diff options
author | Ben Caimano <ben.caimano@10gen.com> | 2020-01-29 18:34:54 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-01-30 00:07:42 +0000 |
commit | 28d4d9cb69b68c759a76851675390cec29855a28 (patch) | |
tree | c551c33cb8ebdd3fab9fe56b6366f18c8b5b0039 /src/mongo/platform | |
parent | 84dc6fcc49eb679c7fe7a5614f496c65e95576fb (diff) | |
download | mongo-28d4d9cb69b68c759a76851675390cec29855a28.tar.gz |
Revert "SERVER-45793 Improve mongo::Mutex contract"
This reverts commit 695146e648e032e04d97bb0b4de873272c242f04.
Diffstat (limited to 'src/mongo/platform')
-rw-r--r-- | src/mongo/platform/mutex.cpp | 31 | ||||
-rw-r--r-- | src/mongo/platform/mutex.h | 153 |
2 files changed, 83 insertions, 101 deletions
diff --git a/src/mongo/platform/mutex.cpp b/src/mongo/platform/mutex.cpp index fd5a5dd212f..cd24a87a84b 100644 --- a/src/mongo/platform/mutex.cpp +++ b/src/mongo/platform/mutex.cpp @@ -77,10 +77,22 @@ StringData Mutex::getName() const { return StringData(_data->identity().name()); } +void Mutex::addLockListener(LockListener* listener) { + auto& state = _getListenerState(); + + invariant(!state.isFinalized.load()); + state.listeners.push_back(listener); +} + +void Mutex::finalizeLockListeners() { + auto& state = _getListenerState(); + state.isFinalized.store(true); +} + void Mutex::_onContendedLock() noexcept { _data->counts().contended.fetchAndAdd(1); - auto& state = latch_detail::getDiagnosticListenerState(); + auto& state = _getListenerState(); if (!state.isFinalized.load()) { return; } @@ -93,7 +105,7 @@ void Mutex::_onContendedLock() noexcept { void Mutex::_onQuickLock() noexcept { _data->counts().acquired.fetchAndAdd(1); - auto& state = latch_detail::getDiagnosticListenerState(); + auto& state = _getListenerState(); if (!state.isFinalized.load()) { return; } @@ -106,7 +118,7 @@ void Mutex::_onQuickLock() noexcept { void Mutex::_onSlowLock() noexcept { _data->counts().acquired.fetchAndAdd(1); - auto& state = latch_detail::getDiagnosticListenerState(); + auto& state = _getListenerState(); if (!state.isFinalized.load()) { return; } @@ -119,7 +131,7 @@ void Mutex::_onSlowLock() noexcept { void Mutex::_onUnlock() noexcept { _data->counts().released.fetchAndAdd(1); - auto& state = latch_detail::getDiagnosticListenerState(); + auto& state = _getListenerState(); if (!state.isFinalized.load()) { return; } @@ -130,13 +142,12 @@ void Mutex::_onUnlock() noexcept { } /** - * Any MONGO_INITIALIZER that adds a DiagnosticListener will want to list - * FinalizeDiagnosticListeners as a dependent initializer. This means that all DiagnosticListeners - * are certified to be added before main and no DiagnosticListeners are ever invoked before main. + * Any MONGO_INITIALIZER that adds a LockListener will want to list FinalizeLockListeners as + * a dependent initializer. This means that all LockListeners are certified to be added before main + * and no LockListeners are ever invoked before main. */ -MONGO_INITIALIZER(FinalizeDiagnosticListeners)(InitializerContext* context) { - auto& state = latch_detail::getDiagnosticListenerState(); - state.isFinalized.store(true); +MONGO_INITIALIZER(FinalizeLockListeners)(InitializerContext* context) { + Mutex::finalizeLockListeners(); return Status::OK(); } diff --git a/src/mongo/platform/mutex.h b/src/mongo/platform/mutex.h index 25ad8f04a7a..5165d239bdc 100644 --- a/src/mongo/platform/mutex.h +++ b/src/mongo/platform/mutex.h @@ -41,7 +41,6 @@ #include "mongo/platform/source_location.h" #include "mongo/stdx/mutex.h" #include "mongo/util/assert_util.h" -#include "mongo/util/concepts.h" #include "mongo/util/decorable.h" #include "mongo/util/duration.h" #include "mongo/util/hierarchical_acquisition.h" @@ -59,9 +58,6 @@ static constexpr auto kAnonymousName = "AnonymousLatch"_sd; /** * An Identity encapsulates the context around a latch - * - * Identities are intended to be constructed rarely and utilized via constant reference or pointer. - * Once an Identity is visible in a multithreaded context, it will be effectively constant. */ class Identity { public: @@ -129,74 +125,6 @@ private: }; /** - * A set of actions to happen upon notable events on a Lockable-conceptualized type - * - * The event handlers on this type will be invoked extremely frequently and can substantially affect - * the efficiency and overall health of the process. As a general rule, avoid logging, disk io, and - * networking in any DiagnosticListener functions. System functions not related to those activities - * should be avoided as much as possible. For example, the overhead of taking an elementary stack - * trace voa backtrace_symbols_fd(3) proved too heavyweight to be used in a DiagnosticListener. - * Additionally, in parts of our system, Mutexes can outlive the invocation of main() and, indeed, - * certain process global variables. DiagnosticListeners usually need to be dynamically allocated - * and leaked. - * - * In short, HERE BE DRAGONS. DO NOT IMPLEMENT NON-DIAGNOSTIC FUNCTIONALITY USING THIS CLASS. - */ -class DiagnosticListener { - friend class Mutex; - -public: - using Identity = latch_detail::Identity; - - virtual ~DiagnosticListener() = default; - - /** - * Action to do when a lock cannot be immediately acquired - */ - virtual void onContendedLock(const Identity& id) = 0; - - /** - * Action to do when a lock was acquired without blocking - */ - virtual void onQuickLock(const Identity& id) = 0; - - /** - * Action to do when a lock was acquired after blocking - */ - virtual void onSlowLock(const Identity& id) = 0; - - /** - * Action to do when a lock is unlocked - */ - virtual void onUnlock(const Identity& id) = 0; -}; - - -inline auto& getDiagnosticListenerState() noexcept { - struct State { - AtomicWord<bool> isFinalized{false}; - std::vector<latch_detail::DiagnosticListener*> listeners; - }; - static State state; - return state; -} - -/** - * Creates a DiagnosticListener subclass and adds it to the triggers for certain actions. - * - * DiagnosticListeners can only be added and not removed. If you wish to deactivate a - * DiagnosticListeners subclass, please provide the switch on that subclass to noop its - * functions. It is only safe to add a DiagnosticListener during a MONGO_INITIALIZER. - */ -TEMPLATE(typename ListenerT) -REQUIRES(std::is_base_of_v<DiagnosticListener, ListenerT>) -void installDiagnosticListener() { - auto& state = getDiagnosticListenerState(); - state.listeners.push_back(new ListenerT()); - invariant(!state.isFinalized.load()); -} - -/** * This class holds working data for a latchable resource * * All member data is either i) synchronized or ii) constant. @@ -233,7 +161,7 @@ private: }; /** - * latch_details::Catalog holds a set of Data objects for use with Mutexes + * latch_details::Catalog holds a collection of Data objects for use with Mutexes * * All rules for LockFreeCollection apply: * - Synchronization is provided internally @@ -248,7 +176,7 @@ public: }; /** - * Simple registration object that takes an Identity and provides access to a Data + * Simple registration object that construct with an Identity and provides access to a Data * * This object actually owns the Data object to make lifetime management simpler. */ @@ -290,14 +218,6 @@ inline auto defaultData() { } } // namespace latch_detail -/** - * Latch is an abstract base class that implements the Lockable concept - * - * This class is useful for designing function APIs that take stdx::unique_lock around an - * ambiguously defined resource. A stdx::unique_lock<Latch> can be constructed from a Mutex. - * A stdx::unique_lock<Latch> cannot be constructed from a stdx::unique_lock<Mutex>. Sometimes, - * standard types are not as powerful as we would like them to be. - */ class Latch { public: virtual ~Latch() = default; @@ -316,17 +236,11 @@ public: * * This class is intended to be used wherever a stdx::mutex would previously be used. It provides * a generic event-listener interface for instrumenting around lock()/unlock()/try_lock(). - * Conceptually, this type is similar to most unique_lock and timed_mutex implementations. - * - * If you believe that you need syncronization with absolutely no additional nanosecond latency or - * need to exist at a very core level (e.g. code living in the base folder), please excuse yourself - * from the linter and use a stdx::mutex. - * - * If you believe that you need logical synchronization at a user-facing level, you may need - * a database Lock instead. Talk to Storage Execution. */ -class Mutex final : public Latch { +class Mutex : public Latch { public: + class LockListener; + void lock() override; void unlock() override; bool try_lock() override; @@ -337,7 +251,32 @@ public: ~Mutex(); + /** + * This function adds a LockListener subclass to the triggers for certain actions. + * + * LockListeners can only be added and not removed. If you wish to deactivate a LockListeners + * subclass, please provide the switch on that subclass to noop its functions. It is only safe + * to add a LockListener during a MONGO_INITIALIZER. + */ + static void addLockListener(LockListener* listener); + + /** + * This function finalizes the list of LockListener subclasses and prevents more from being + * added. + */ + static void finalizeLockListeners(); + private: + static auto& _getListenerState() noexcept { + struct State { + AtomicWord<bool> isFinalized{false}; + std::vector<LockListener*> listeners; + }; + + static State state; + return state; + } + void _onContendedLock() noexcept; void _onQuickLock() noexcept; void _onSlowLock() noexcept; @@ -349,6 +288,38 @@ private: bool _isLocked = false; }; +/** + * A set of actions to happen upon notable events on a Lockable-conceptualized type + */ +class Mutex::LockListener { + friend class Mutex; + +public: + using Identity = latch_detail::Identity; + + virtual ~LockListener() = default; + + /** + * Action to do when a lock cannot be immediately acquired + */ + virtual void onContendedLock(const Identity& id) = 0; + + /** + * Action to do when a lock was acquired without blocking + */ + virtual void onQuickLock(const Identity& id) = 0; + + /** + * Action to do when a lock was acquired after blocking + */ + virtual void onSlowLock(const Identity& id) = 0; + + /** + * Action to do when a lock is unlocked + */ + virtual void onUnlock(const Identity& id) = 0; +}; + } // namespace mongo /** |