From 621cc26e0a5033f3bddf8c70c65bc0096b0e099b Mon Sep 17 00:00:00 2001 From: James Sedgwick Date: Wed, 16 Sep 2015 10:38:01 -0700 Subject: [PATCH] use HHWheelTimer for EventBase::runAfterDelay Summary: For the perfs - big improvement on one fd per timeout. Reviewed By: @djwatson, @fugalh Differential Revision: D2379210 --- folly/io/async/EventBase.cpp | 26 +++++++++++++++----------- folly/io/async/EventBase.h | 23 +++++++---------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/folly/io/async/EventBase.cpp b/folly/io/async/EventBase.cpp index 12991a03..e73bdb3e 100644 --- a/folly/io/async/EventBase.cpp +++ b/folly/io/async/EventBase.cpp @@ -123,7 +123,13 @@ void EventBase::CobTimeout::timeoutExpired() noexcept { } // The CobTimeout object was allocated on the heap by runAfterDelay(), - // so delete it now that the it has fired. + // so delete it now that it has fired. + delete this; +} + +void EventBase::CobTimeout::callbackCanceled() noexcept { + // The CobTimeout object was allocated on the heap by runAfterDelay(), + // so delete it now that it has been canceled. delete this; } @@ -175,6 +181,7 @@ EventBase::EventBase(bool enableTimeMeasurement) } VLOG(5) << "EventBase(): Created."; initNotificationQueue(); + wheelTimer_ = HHWheelTimer::UniquePtr(new HHWheelTimer(this)); RequestContext::saveContext(); } @@ -201,6 +208,7 @@ EventBase::EventBase(event_base* evb, bool enableTimeMeasurement) throw std::invalid_argument("EventBase(): event base cannot be nullptr"); } initNotificationQueue(); + wheelTimer_ = HHWheelTimer::UniquePtr(new HHWheelTimer(this)); RequestContext::saveContext(); } @@ -216,10 +224,7 @@ EventBase::~EventBase() { // (Note that we don't fire them. The caller is responsible for cleaning up // its own data structures if it destroys the EventBase with unfired events // remaining.) - while (!pendingCobTimeouts_.empty()) { - CobTimeout* timeout = &pendingCobTimeouts_.front(); - delete timeout; - } + wheelTimer_->cancelAll(); while (!runBeforeLoopCallbacks_.empty()) { delete &runBeforeLoopCallbacks_.front(); @@ -654,12 +659,11 @@ void EventBase::runAfterDelay(const Cob& cob, bool EventBase::tryRunAfterDelay(const Cob& cob, int milliseconds, TimeoutManager::InternalEnum in) { - CobTimeout* timeout = new CobTimeout(this, cob, in); - if (!timeout->scheduleTimeout(milliseconds)) { - delete timeout; - return false; - } - pendingCobTimeouts_.push_back(*timeout); + // A previous implementation could fail, and the API is retained for + // backwards compatibility. + wheelTimer_->scheduleTimeout( + new CobTimeout(cob), + std::chrono::milliseconds(milliseconds)); return true; } diff --git a/folly/io/async/EventBase.h b/folly/io/async/EventBase.h index 65b6a45f..47697fde 100644 --- a/folly/io/async/EventBase.h +++ b/folly/io/async/EventBase.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -649,26 +650,16 @@ class EventBase : private boost::noncopyable, // small object used as a callback arg with enough info to execute the // appropriate client-provided Cob - class CobTimeout : public AsyncTimeout { + class CobTimeout : public HHWheelTimer::Callback { public: - CobTimeout(EventBase* b, const Cob& c, TimeoutManager::InternalEnum in) - : AsyncTimeout(b, in), cob_(c) {} + explicit CobTimeout(const Cob& c) : cob_(c) {} - virtual void timeoutExpired() noexcept; + void timeoutExpired() noexcept override; + + void callbackCanceled() noexcept override; private: Cob cob_; - - public: - typedef boost::intrusive::list_member_hook< - boost::intrusive::link_mode > ListHook; - - ListHook hook; - - typedef boost::intrusive::list< - CobTimeout, - boost::intrusive::member_hook, - boost::intrusive::constant_time_size > List; }; typedef LoopCallback::List LoopCallbackList; @@ -681,7 +672,7 @@ class EventBase : private boost::noncopyable, void initNotificationQueue(); - CobTimeout::List pendingCobTimeouts_; + HHWheelTimer::UniquePtr wheelTimer_; LoopCallbackList loopCallbacks_; LoopCallbackList runBeforeLoopCallbacks_; -- 2.34.1