proxygen
proxygen::AsyncTimeoutSet Class Reference

#include <AsyncTimeoutSet.h>

Inheritance diagram for proxygen::AsyncTimeoutSet:
folly::AsyncTimeout folly::DelayedDestruction folly::DelayedDestructionBase

Classes

class  Callback
 
class  TimeoutClock
 

Public Types

using UniquePtr = std::unique_ptr< AsyncTimeoutSet, Destructor >
 

Public Member Functions

 AsyncTimeoutSet (folly::TimeoutManager *timeoutManager, std::chrono::milliseconds intervalMS, std::chrono::milliseconds atMostEveryN=std::chrono::milliseconds(0), TimeoutClock *timeoutClock=nullptr)
 
 AsyncTimeoutSet (folly::TimeoutManager *timeoutManager, InternalEnum internal, std::chrono::milliseconds intervalMS, std::chrono::milliseconds atMostEveryN=std::chrono::milliseconds(0))
 
void destroy () override
 
std::chrono::milliseconds getInterval () const
 
void scheduleTimeout (Callback *callback)
 
void fireAtMostEvery (const std::chrono::milliseconds &ms)
 
Callbackfront ()
 
const Callbackfront () const
 
- Public Member Functions inherited from folly::DelayedDestruction
bool getDestroyPending () const
 
- Public Member Functions inherited from folly::DelayedDestructionBase
virtual ~DelayedDestructionBase ()=default
 

Protected Member Functions

 ~AsyncTimeoutSet () override
 
- Protected Member Functions inherited from folly::DelayedDestruction
 ~DelayedDestruction () override=default
 
 DelayedDestruction ()
 
- Protected Member Functions inherited from folly::DelayedDestructionBase
 DelayedDestructionBase ()
 
uint32_t getDestructorGuardCount () const
 

Private Member Functions

 AsyncTimeoutSet (AsyncTimeoutSet const &)=delete
 
AsyncTimeoutSetoperator= (AsyncTimeoutSet const &)=delete
 
void headChanged ()
 
void timeoutExpired () noexceptoverride
 
- Private Member Functions inherited from folly::AsyncTimeout
 AsyncTimeout (TimeoutManager *timeoutManager)
 
 AsyncTimeout (EventBase *eventBase)
 
 AsyncTimeout (TimeoutManager *timeoutManager, InternalEnum internal)
 
 AsyncTimeout (EventBase *eventBase, InternalEnum internal)
 
 AsyncTimeout ()
 
virtual ~AsyncTimeout ()
 
bool scheduleTimeout (uint32_t milliseconds)
 
bool scheduleTimeout (TimeoutManager::timeout_type timeout)
 
void cancelTimeout ()
 
bool isScheduled () const
 
void attachTimeoutManager (TimeoutManager *timeoutManager, InternalEnum internal=InternalEnum::NORMAL)
 
void attachEventBase (EventBase *eventBase, InternalEnum internal=InternalEnum::NORMAL)
 
void detachTimeoutManager ()
 
void detachEventBase ()
 
const TimeoutManagergetTimeoutManager ()
 
struct event * getEvent ()
 

Private Attributes

TimeoutClocktimeoutClock_
 
Callbackhead_
 
Callbacktail_
 
std::chrono::milliseconds interval_
 
std::chrono::milliseconds atMostEveryN_
 
bool inTimeoutExpired_ {false}
 

Additional Inherited Members

- Private Types inherited from folly::AsyncTimeout
typedef TimeoutManager::InternalEnum InternalEnum
 
- Static Private Member Functions inherited from folly::AsyncTimeout
template<typename TCallback >
static std::unique_ptr< AsyncTimeoutmake (TimeoutManager &manager, TCallback &&callback)
 
template<typename TCallback >
static std::unique_ptr< AsyncTimeoutschedule (TimeoutManager::timeout_type timeout, TimeoutManager &manager, TCallback &&callback)
 

Detailed Description

AsyncTimeoutSet exists for efficiently managing a group of timeouts events that always have the same timeout interval.

AsyncTimeoutSet takes advantage of the fact that the timeouts are always scheduled in sorted order. (Since each timeout has the same interval, when a new timeout is scheduled it will always be the last timeout in the set.) This avoids the need to perform any additional sorting of the timeouts within a single AsyncTimeoutSet.

AsyncTimeoutSet is useful whenever you have a large group of objects that each need their own timeout, but with the same interval for each object. For example, managing idle timeouts for thousands of connection, or scheduling health checks for a large group of servers.

Note, this class may not be needed given libevent's event_base_init_common_timeout(). We should look into using that.

Definition at line 40 of file AsyncTimeoutSet.h.

Member Typedef Documentation

Definition at line 43 of file AsyncTimeoutSet.h.

Constructor & Destructor Documentation

proxygen::AsyncTimeoutSet::AsyncTimeoutSet ( folly::TimeoutManager timeoutManager,
std::chrono::milliseconds  intervalMS,
std::chrono::milliseconds  atMostEveryN = std::chrono::milliseconds(0),
TimeoutClock timeoutClock = nullptr 
)

Create a new AsyncTimeoutSet with the specified interval.

If timeout clock is unspecified, it will use the default (system clock)

Referenced by proxygen::AsyncTimeoutSet::Callback::cancelTimeoutImpl().

proxygen::AsyncTimeoutSet::AsyncTimeoutSet ( folly::TimeoutManager timeoutManager,
InternalEnum  internal,
std::chrono::milliseconds  intervalMS,
std::chrono::milliseconds  atMostEveryN = std::chrono::milliseconds(0) 
)

Create a new AsyncTimeoutSet with the given 'internal' settting. For details on what the InternalEnum specifies, see the documentation in AsyncTimeout.h

proxygen::AsyncTimeoutSet::~AsyncTimeoutSet ( )
overrideprotected

Protected destructor.

Use destroy() instead. See the comments in DelayedDestruction for more details.

Definition at line 100 of file AsyncTimeoutSet.cpp.

Referenced by front().

100  {
101  // DelayedDestruction should ensure that we are never destroyed while inside
102  // a call to timeoutExpired().
103  assert(!inTimeoutExpired_);
104 
105  // destroy() should have already cleared out the timeout list.
106  // It's a bug if anyone tries to keep using the AsyncTimeoutSet after
107  // calling destroy, so no new timeouts may have been scheduled since then.
108  assert(head_ == nullptr);
109  assert(tail_ == nullptr);
110 }
proxygen::AsyncTimeoutSet::AsyncTimeoutSet ( AsyncTimeoutSet const &  )
privatedelete

Member Function Documentation

void proxygen::AsyncTimeoutSet::destroy ( )
overridevirtual

Destroy the AsyncTimeoutSet.

Normally a AsyncTimeoutSet should only be destroyed when there are no more callbacks pending in the set. If there are timeout callbacks pending for this set, destroying the AsyncTimeoutSet will automatically cancel them. If you destroy a AsyncTimeoutSet with callbacks pending, your callback code needs to be aware that the callbacks will never be invoked.

Reimplemented from folly::DelayedDestruction.

Definition at line 112 of file AsyncTimeoutSet.cpp.

References destroy().

Referenced by proxygen::AsyncTimeoutSet::TimeoutClock::~TimeoutClock().

112  {
113  // If there are any timeout callbacks pending, get rid of them without ever
114  // invoking them. This is somewhat undesirable from the callback's
115  // perspective (how is it supposed to know that it will never get invoked?).
116  // Most users probably only want to destroy a AsyncTimeoutSet when it has no
117  // callbacks remaining. Otherwise they need to implement their own code to
118  // take care of cleaning up the callbacks that will never be invoked.
119 
120  // cancel from tail to head, to avoid extra calls to headChanged
121  while (tail_ != nullptr) {
122  tail_->cancelTimeout();
123  }
124 
126 }
static void destroy()
void proxygen::AsyncTimeoutSet::fireAtMostEvery ( const std::chrono::milliseconds &  ms)
inline

Limit how frequently this AsyncTimeoutSet will fire.

Definition at line 179 of file AsyncTimeoutSet.h.

References atMostEveryN_.

179  {
180  atMostEveryN_ = ms;
181  }
std::chrono::milliseconds atMostEveryN_
Callback* proxygen::AsyncTimeoutSet::front ( )
inline

Get a pointer to the next Callback scheduled to be invoked (may be null).

Definition at line 186 of file AsyncTimeoutSet.h.

References head_.

Referenced by TestTimeout::_scheduleNext().

186 { return head_; }
std::chrono::milliseconds proxygen::AsyncTimeoutSet::getInterval ( ) const
inline

Get the interval for this AsyncTimeoutSet.

Returns the timeout interval in milliseconds. All callbacks scheduled with scheduleTimeout() will be invoked after this amount of time has passed since the call to scheduleTimeout().

Definition at line 163 of file AsyncTimeoutSet.h.

References interval_, and scheduleTimeout().

163  {
164  return interval_;
165  }
std::chrono::milliseconds interval_
void proxygen::AsyncTimeoutSet::headChanged ( )
private

Definition at line 158 of file AsyncTimeoutSet.cpp.

References folly::AsyncTimeout::cancelTimeout(), and folly::AsyncTimeout::scheduleTimeout().

Referenced by front().

158  {
159  if (inTimeoutExpired_) {
160  // timeoutExpired() will always update the scheduling correctly before it
161  // returns. No need to change the state now, since we are just going to
162  // change it again later.
163  return;
164  }
165 
166  if (!head_) {
168  } else {
169  milliseconds delta =
171  this->folly::AsyncTimeout::scheduleTimeout(delta.count());
172  }
173 }
virtual std::chrono::milliseconds millisecondsSinceEpoch()=0
std::chrono::milliseconds getTimeRemaining(std::chrono::milliseconds now) const
bool scheduleTimeout(uint32_t milliseconds)
AsyncTimeoutSet& proxygen::AsyncTimeoutSet::operator= ( AsyncTimeoutSet const &  )
privatedelete

Referenced by front().

void proxygen::AsyncTimeoutSet::scheduleTimeout ( Callback callback)

Schedule the specified Callback to be invoked after the AsyncTimeoutSet's specified timeout interval.

If the callback is already scheduled, this cancels the existing timeout before scheduling the new timeout.

Definition at line 128 of file AsyncTimeoutSet.cpp.

References proxygen::AsyncTimeoutSet::Callback::cancelTimeout(), proxygen::AsyncTimeoutSet::Callback::context_, proxygen::AsyncTimeoutSet::Callback::next_, proxygen::AsyncTimeoutSet::Callback::prev_, folly::RequestContext::saveContext(), folly::AsyncTimeout::scheduleTimeout(), and proxygen::AsyncTimeoutSet::Callback::setScheduled().

Referenced by TestTimeout::_scheduleNext(), and getInterval().

128  {
129  // Cancel the callback if it happens to be scheduled already.
130  callback->cancelTimeout();
131  assert(callback->prev_ == nullptr);
132  assert(callback->next_ == nullptr);
133 
134  callback->context_ = folly::RequestContext::saveContext();
135 
136  Callback* old_tail = tail_;
137  if (head_ == nullptr) {
138  // We don't have any timeouts scheduled already. We have to schedule
139  // ourself.
140  assert(tail_ == nullptr);
141  assert(!isScheduled());
142  if (!inTimeoutExpired_) {
144  }
145  head_ = callback;
146  tail_ = callback;
147  } else {
148  assert(inTimeoutExpired_ || isScheduled());
149  assert(tail_->next_ == nullptr);
150  tail_->next_ = callback;
151  tail_ = callback;
152  }
153 
154  // callback->prev_ = tail_;
155  callback->setScheduled(this, old_tail);
156 }
static std::shared_ptr< RequestContext > saveContext()
Definition: Request.h:196
bool scheduleTimeout(uint32_t milliseconds)
void setScheduled(AsyncTimeoutSet *timeoutSet, Callback *prev)
bool isScheduled() const
std::chrono::milliseconds interval_
void proxygen::AsyncTimeoutSet::timeoutExpired ( )
overrideprivatevirtualnoexcept

timeoutExpired() is invoked when the timeout period has expired.

Implements folly::AsyncTimeout.

Definition at line 175 of file AsyncTimeoutSet.cpp.

References proxygen::AsyncTimeoutSet::Callback::cancelTimeout(), proxygen::AsyncTimeoutSet::Callback::context_, now(), folly::AsyncTimeout::scheduleTimeout(), SCOPE_EXIT, folly::RequestContext::setContext(), and proxygen::AsyncTimeoutSet::Callback::timeoutExpired().

175  {
176  // If destroy() is called inside timeoutExpired(), delay actual destruction
177  // until timeoutExpired() returns
178  DestructorGuard dg(this);
179 
180  // timeoutExpired() can only be invoked directly from the event base loop.
181  // It should never be invoked recursively.
182  //
183  // Set inTimeoutExpired_ to true, so that we won't bother rescheduling the
184  // main AsyncTimeout inside timeoutExpired(). We'll always make sure this
185  // is up-to-date before we return. This simply prevents us from
186  // unnecessarily modifying the main timeout heap multiple times before we
187  // return.
188  assert(!inTimeoutExpired_);
189  inTimeoutExpired_ = true;
190  SCOPE_EXIT { inTimeoutExpired_ = false; };
191 
192  // Get the current time.
193  // For now we only compute the current time at the start of the loop.
194  // If a callback takes a very long time to execute its timeoutExpired()
195  // method, this value could potentially get stale.
196  //
197  // However, this should be rare, and it doesn't seem worth the overhead of
198  // recomputing the current time each time around the loop. If the value does
199  // go stale, we won't invoke as many callbacks as we could. They will have
200  // to wait until the next call to timeoutExpired(). However, we could also
201  // end up rescheduling the next timeoutExpired() call a bit late if now gets
202  // stale. If we find that this becomes a problem in practice we could be
203  // more smart about when we recompute the current time.
205 
206  while (head_ != nullptr) {
207  milliseconds delta = head_->getTimeRemaining(now);
208  if (delta > milliseconds(0)) {
209  if (delta < atMostEveryN_) {
210  delta = atMostEveryN_;
211  }
212  this->folly::AsyncTimeout::scheduleTimeout(delta.count());
213  break;
214  }
215 
216  // Remember the callback to invoke, since calling cancelTimeout()
217  // on it will modify head_.
218  Callback* cb = head_;
219  head_->cancelTimeout();
220  auto old_ctx =
221  folly::RequestContext::setContext(cb->context_);
222  cb->timeoutExpired();
224  }
225 }
static std::shared_ptr< RequestContext > setContext(std::shared_ptr< RequestContext > ctx)
Definition: Request.cpp:227
std::chrono::steady_clock::time_point now()
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
virtual std::chrono::milliseconds millisecondsSinceEpoch()=0
std::chrono::milliseconds atMostEveryN_
std::chrono::milliseconds getTimeRemaining(std::chrono::milliseconds now) const
bool scheduleTimeout(uint32_t milliseconds)

Member Data Documentation

std::chrono::milliseconds proxygen::AsyncTimeoutSet::atMostEveryN_
private

Definition at line 213 of file AsyncTimeoutSet.h.

Referenced by fireAtMostEvery().

Callback* proxygen::AsyncTimeoutSet::head_
private

Definition at line 210 of file AsyncTimeoutSet.h.

Referenced by front().

std::chrono::milliseconds proxygen::AsyncTimeoutSet::interval_
private

Definition at line 212 of file AsyncTimeoutSet.h.

Referenced by getInterval().

bool proxygen::AsyncTimeoutSet::inTimeoutExpired_ {false}
private

Definition at line 214 of file AsyncTimeoutSet.h.

Callback* proxygen::AsyncTimeoutSet::tail_
private

Definition at line 211 of file AsyncTimeoutSet.h.

TimeoutClock& proxygen::AsyncTimeoutSet::timeoutClock_
private

The documentation for this class was generated from the following files: