diff options
author | Rahul Sundararaman <rahul.sundararaman@10gen.com> | 2019-08-20 15:54:09 -0400 |
---|---|---|
committer | Rahul Sundararaman <rahul.sundararaman@10gen.com> | 2019-08-20 16:35:36 -0400 |
commit | 18a3e230c7d1d1cbe3e54e584c7dcc8c9052b422 (patch) | |
tree | 182a34cf3a2678cef3edcd95a53ad889626d0c2c /src/mongo/platform | |
parent | 8438390a20540402f1a2a51a4c08a75ea1b3392d (diff) | |
download | mongo-18a3e230c7d1d1cbe3e54e584c7dcc8c9052b422.tar.gz |
SERVER-42492 Attach DiagnosticInfo on long mongo::ConditionVariable::wait()
Diffstat (limited to 'src/mongo/platform')
-rw-r--r-- | src/mongo/platform/condition_variable.cpp | 8 | ||||
-rw-r--r-- | src/mongo/platform/condition_variable.h | 132 |
2 files changed, 105 insertions, 35 deletions
diff --git a/src/mongo/platform/condition_variable.cpp b/src/mongo/platform/condition_variable.cpp index 76de1ca6d2b..79a465b09f5 100644 --- a/src/mongo/platform/condition_variable.cpp +++ b/src/mongo/platform/condition_variable.cpp @@ -30,9 +30,6 @@ #include "mongo/platform/condition_variable.h" namespace mongo { -void ConditionVariable::wait(lock_t& lock) { - _condvar.wait(lock); -} void ConditionVariable::notify_one() noexcept { _condvar.notify_one(); @@ -41,4 +38,9 @@ void ConditionVariable::notify_one() noexcept { void ConditionVariable::notify_all() noexcept { _condvar.notify_all(); } + +void ConditionVariable::setConditionVariableActions( + std::unique_ptr<ConditionVariableActions> actions) { + _conditionVariableActions = std::move(actions); +} } // namespace mongo diff --git a/src/mongo/platform/condition_variable.h b/src/mongo/platform/condition_variable.h index 5b5f2f3c79b..82b68fd8484 100644 --- a/src/mongo/platform/condition_variable.h +++ b/src/mongo/platform/condition_variable.h @@ -32,72 +32,140 @@ #include "mongo/platform/mutex.h" #include "mongo/stdx/condition_variable.h" -#include "mongo/util/diagnostic_info.h" - +#include "mongo/util/scopeguard.h" namespace mongo { -class ConditionVariable : private stdx::condition_variable_any { - using lock_t = stdx::unique_lock<Mutex>; + +class Mutex; + +class ConditionVariableActions { +public: + virtual ~ConditionVariableActions() = default; + virtual void onUnfulfilledConditionVariable(const StringData& name) = 0; + virtual void onFulfilledConditionVariable() = 0; +}; + +class ConditionVariable { + friend class ::mongo::Waitable; public: - void wait(lock_t& lock); + static constexpr Milliseconds kUnfulfilledConditionVariableTimeout = Milliseconds(100); - template <class Predicate> - void wait(lock_t& lock, Predicate pred); + template <class Lock> + void wait(Lock& lock); - template <class Rep, class Period> - stdx::cv_status wait_for(lock_t& lock, const stdx::chrono::duration<Rep, Period>& rel_time); + template <class Lock, class Predicate> + void wait(Lock& lock, Predicate pred); - template <class Rep, class Period, class Predicate> - bool wait_for(lock_t& lock, - const stdx::chrono::duration<Rep, Period>& rel_time, - Predicate pred); + template <class Lock, class Rep, class Period> + stdx::cv_status wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time); - template <class Clock, class Duration> - stdx::cv_status wait_until(lock_t& lock, + template <class Lock, class Rep, class Period, class Predicate> + bool wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time, Predicate pred); + + template <class Lock, class Clock, class Duration> + stdx::cv_status wait_until(Lock& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time); - template <class Clock, class Duration, class Predicate> - bool wait_until(lock_t& lock, + template <class Lock, class Clock, class Duration, class Predicate> + bool wait_until(Lock& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time, Predicate pred); void notify_one() noexcept; void notify_all() noexcept; + static void setConditionVariableActions(std::unique_ptr<ConditionVariableActions> actions); + +protected: + template <typename Callback> + void _runWithNotifyable(Notifyable& notifyable, Callback&& cb) noexcept { + _condvar._runWithNotifyable(notifyable, cb); + } + private: + const Seconds _conditionVariableTimeout = Seconds(604800); stdx::condition_variable_any _condvar; + + inline static std::unique_ptr<ConditionVariableActions> _conditionVariableActions; + + template <class Lock, class Duration> + auto _wait(Lock& lock, const Duration& rel_time) { + const auto guard = makeGuard([&] { + if (_conditionVariableActions) { + _conditionVariableActions->onFulfilledConditionVariable(); + } + }); + + if (auto cvstatus = _condvar.wait_for( + lock, std::min(rel_time, kUnfulfilledConditionVariableTimeout.toSystemDuration())); + cvstatus == stdx::cv_status::no_timeout || + rel_time <= kUnfulfilledConditionVariableTimeout.toSystemDuration()) { + return cvstatus; + } + + if (_conditionVariableActions) { + if constexpr (std::is_same<decltype(lock), Mutex>::value) { + _conditionVariableActions->onUnfulfilledConditionVariable(lock.getName()); + } else { + _conditionVariableActions->onUnfulfilledConditionVariable("AnonymousLock"); + } + } + + if (auto cvstatus = _condvar.wait_for( + lock, rel_time - kUnfulfilledConditionVariableTimeout.toSystemDuration()); + cvstatus == stdx::cv_status::no_timeout) { + return cvstatus; + } + + uasserted(ErrorCodes::InternalError, "Unable to take latch, wait time exceeds set timeout"); + } + + template <class Lock, class Duration, class Predicate> + auto _waitWithPredicate(Lock& lock, const Duration& rel_time, Predicate pred) { + while (!pred()) { + if (_wait(lock, rel_time) == std::cv_status::timeout) { + return pred(); + } + } + return true; + } }; -template <class Predicate> -void ConditionVariable::wait(lock_t& lock, Predicate pred) { - _condvar.wait(lock, pred); +template <class Lock> +void ConditionVariable::wait(Lock& lock) { + _wait(lock, _conditionVariableTimeout.toSystemDuration()); +} + +template <class Lock, class Predicate> +void ConditionVariable::wait(Lock& lock, Predicate pred) { + _waitWithPredicate(lock, _conditionVariableTimeout.toSystemDuration(), std::move(pred)); } -template <class Rep, class Period> -stdx::cv_status ConditionVariable::wait_for(lock_t& lock, +template <class Lock, class Rep, class Period> +stdx::cv_status ConditionVariable::wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time) { - return _condvar.wait_for(lock, rel_time); + return _wait(lock, rel_time); } -template <class Rep, class Period, class Predicate> -bool ConditionVariable::wait_for(lock_t& lock, +template <class Lock, class Rep, class Period, class Predicate> +bool ConditionVariable::wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time, Predicate pred) { - return _condvar.wait_for(lock, rel_time, pred); + return _waitWithPredicate(lock, rel_time, pred); } -template <class Clock, class Duration> +template <class Lock, class Clock, class Duration> stdx::cv_status ConditionVariable::wait_until( - lock_t& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time) { - return _condvar.wait_until(lock, timeout_time); + Lock& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time) { + return _wait(lock, timeout_time - stdx::chrono::steady_clock::now()); } -template <class Clock, class Duration, class Predicate> -bool ConditionVariable::wait_until(lock_t& lock, +template <class Lock, class Clock, class Duration, class Predicate> +bool ConditionVariable::wait_until(Lock& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time, Predicate pred) { - return _condvar.wait_until(lock, timeout_time, pred); + return _waitWithPredicate(lock, timeout_time - stdx::chrono::steady_clock::now(), pred); } } // namespace mongo |