use HHWheelTimer for EventBase::runAfterDelay
authorJames Sedgwick <jsedgwick@fb.com>
Wed, 16 Sep 2015 17:38:01 +0000 (10:38 -0700)
committerfacebook-github-bot-9 <folly-bot@fb.com>
Wed, 16 Sep 2015 18:20:21 +0000 (11:20 -0700)
Summary: For the perfs - big improvement on one fd per timeout.

Reviewed By: @djwatson, @fugalh

Differential Revision: D2379210

folly/io/async/EventBase.cpp
folly/io/async/EventBase.h

index 12991a03970b64dd5939dc4cd732282f213de278..e73bdb3e58aaffa91f8332aaf4d95288a5f9e4a3 100644 (file)
@@ -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;
 }
 
index 65b6a45f5c42711fb2bd7b8b78f1f8182fddd168..47697fde34835612be6e6f6855bebebd0915abcd 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <glog/logging.h>
 #include <folly/io/async/AsyncTimeout.h>
+#include <folly/io/async/HHWheelTimer.h>
 #include <folly/io/async/TimeoutManager.h>
 #include <folly/io/async/Request.h>
 #include <folly/Executor.h>
@@ -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<boost::intrusive::auto_unlink> > ListHook;
-
-    ListHook hook;
-
-    typedef boost::intrusive::list<
-      CobTimeout,
-      boost::intrusive::member_hook<CobTimeout, ListHook, &CobTimeout::hook>,
-      boost::intrusive::constant_time_size<false> > 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_;