Give each eventbase a wheeltimer
authorScott Michelson <sdmich@fb.com>
Thu, 30 Jun 2016 00:57:13 +0000 (17:57 -0700)
committerFacebook Github Bot 4 <facebook-github-bot-4-bot@fb.com>
Thu, 30 Jun 2016 01:08:25 +0000 (18:08 -0700)
Summary:
This gives each eventbase a wheeltimer. Construction is on demand, so there's no penalty if it isn't used. Why do this? 3 immediate reasons:

1) some clients already do this outside of the interface: diffusion/FBS/browse/master/fbcode/servicerouter/client/common/ThriftDispatcher.h$302,607?view=highlighted
2) inefficient timers can be easily avoided: diffusion/FBS/browse/master/fbcode/thrift/lib/cpp2/async/HeaderClientChannel.h;64fb260ea4bd235ba79414a78002fd68cf0453a8$319
3) D2379210 indicates we can do a better job with this than cob timeout

Reviewed By: andriigrynenko, djwatson

Differential Revision: D3460792

fbshipit-source-id: a7bb6fdd90ca95b6aef8af952d7a66dd0dc260c1

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

index 89e89fd1b1765bf0d2b77bf98641a47d3dd46941..507e8beb7463fdad45dce7aa7eba048109628749 100644 (file)
@@ -40,6 +40,7 @@
 #include <folly/experimental/ExecutionObserver.h>
 #include <folly/futures/DrivableExecutor.h>
 #include <folly/io/async/AsyncTimeout.h>
+#include <folly/io/async/HHWheelTimer.h>
 #include <folly/io/async/Request.h>
 #include <folly/io/async/TimeoutManager.h>
 #include <folly/portability/PThread.h>
@@ -493,6 +494,13 @@ class EventBase : private boost::noncopyable,
       loopThread_.load(std::memory_order_relaxed), pthread_self());
   }
 
+  HHWheelTimer& timer() {
+    if (!wheelTimer_) {
+      wheelTimer_ = HHWheelTimer::newTimer(this, std::chrono::milliseconds(1));
+    }
+    return *wheelTimer_.get();
+  }
+
   // --------- interface to underlying libevent base ------------
   // Avoid using these functions if possible.  These functions are not
   // guaranteed to always be present if we ever provide alternative EventBase
@@ -665,6 +673,9 @@ class EventBase : private boost::noncopyable,
 
   void initNotificationQueue();
 
+  // should only be accessed through public getter
+  HHWheelTimer::UniquePtr wheelTimer_;
+
   CobTimeout::List pendingCobTimeouts_;
 
   LoopCallbackList loopCallbacks_;
index 90b260be9e31834a627d67c323c6d017848b2184..85ce3e838ab6767dd99dcfe6bd271954e0e9868c 100644 (file)
@@ -110,7 +110,7 @@ TEST_F(HHWheelTimerTest, FireOnce) {
  * Test scheduling a timeout from another timeout callback.
  */
 TEST_F(HHWheelTimerTest, TestSchedulingWithinCallback) {
-  StackWheelTimer t(&eventBase, milliseconds(10));
+  HHWheelTimer& t = eventBase.timer();
 
   TestTimeout t1;
   // Delayed to simulate the steady_clock counter lagging
@@ -135,7 +135,7 @@ TEST_F(HHWheelTimerTest, TestSchedulingWithinCallback) {
  */
 
 TEST_F(HHWheelTimerTest, CancelTimeout) {
-  StackWheelTimer t(&eventBase, milliseconds(1));
+  HHWheelTimer& t = eventBase.timer();
 
   // Create several timeouts that will all fire in 5ms.
   TestTimeout t5_1(&t, milliseconds(5));
@@ -350,7 +350,7 @@ TEST_F(HHWheelTimerTest, AtMostEveryN) {
  */
 
 TEST_F(HHWheelTimerTest, SlowLoop) {
-  StackWheelTimer t(&eventBase, milliseconds(1));
+  HHWheelTimer& t = eventBase.timer();
 
   TestTimeout t1;
   TestTimeout t2;
@@ -429,7 +429,7 @@ TEST_F(HHWheelTimerTest, DefaultTimeout) {
 }
 
 TEST_F(HHWheelTimerTest, lambda) {
-  StackWheelTimer t(&eventBase, milliseconds(1));
+  HHWheelTimer& t = eventBase.timer();
   size_t count = 0;
   t.scheduleTimeoutFn([&]{ count++; }, milliseconds(1));
   eventBase.loop();
@@ -439,14 +439,14 @@ TEST_F(HHWheelTimerTest, lambda) {
 // shouldn't crash because we swallow and log the error (you'll have to look
 // at the console to confirm logging)
 TEST_F(HHWheelTimerTest, lambdaThrows) {
-  StackWheelTimer t(&eventBase, milliseconds(1));
+  HHWheelTimer& t = eventBase.timer();
   t.scheduleTimeoutFn([&]{ throw std::runtime_error("expected"); },
                       milliseconds(1));
   eventBase.loop();
 }
 
 TEST_F(HHWheelTimerTest, cancelAll) {
-  StackWheelTimer t(&eventBase);
+  HHWheelTimer& t = eventBase.timer();
   TestTimeout tt;
   t.scheduleTimeout(&tt, std::chrono::minutes(1));
   EXPECT_EQ(1, t.cancelAll());