rippled
test/csf/Scheduler.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
21 #define RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
22 
23 #include <ripple/basics/ByteUtilities.h>
24 #include <ripple/beast/clock/manual_clock.h>
25 
26 #include <boost/container/pmr/monotonic_buffer_resource.hpp>
27 #include <boost/intrusive/set.hpp>
28 
29 #include <type_traits>
30 #include <utility>
31 
32 namespace ripple {
33 namespace test {
34 namespace csf {
35 
47 class Scheduler
48 {
49 public:
51 
52  using duration = typename clock_type::duration;
53 
55 
56 private:
57  using by_when_hook = boost::intrusive::set_base_hook<
58  boost::intrusive::link_mode<boost::intrusive::normal_link>>;
59 
61  {
63 
64  event(event const&) = delete;
65  event&
66  operator=(event const&) = delete;
67 
68  virtual ~event() = default;
69 
70  // Called to perform the event
71  virtual void
72  operator()() const = 0;
73 
74  event(time_point when_) : when(when_)
75  {
76  }
77 
78  bool
79  operator<(event const& other) const
80  {
81  return when < other.when;
82  }
83  };
84 
85  template <class Handler>
86  class event_impl : public event
87  {
88  Handler const h_;
89 
90  public:
91  event_impl(event_impl const&) = delete;
92 
93  event_impl&
94  operator=(event_impl const&) = delete;
95 
96  template <class DeducedHandler>
97  event_impl(time_point when_, DeducedHandler&& h)
98  : event(when_), h_(std::forward<DeducedHandler>(h))
99  {
100  }
101 
102  void
103  operator()() const override
104  {
105  h_();
106  }
107  };
108 
110  {
111  private:
112  using by_when_set = typename boost::intrusive::make_multiset<
113  event,
114  boost::intrusive::constant_time_size<false>>::type;
115  // alloc_ is owned by the scheduler
116  boost::container::pmr::monotonic_buffer_resource* alloc_;
118 
119  public:
120  using iterator = typename by_when_set::iterator;
121 
122  queue_type(queue_type const&) = delete;
123  queue_type&
124  operator=(queue_type const&) = delete;
125 
126  explicit queue_type(
127  boost::container::pmr::monotonic_buffer_resource* alloc);
128 
129  ~queue_type();
130 
131  bool
132  empty() const;
133 
134  iterator
135  begin();
136 
137  iterator
138  end();
139 
140  template <class Handler>
141  typename by_when_set::iterator
142  emplace(time_point when, Handler&& h);
143 
144  iterator
145  erase(iterator iter);
146  };
147 
148  boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
150 
151  // Aged containers that rely on this clock take a non-const reference =(
153 
154 public:
155  Scheduler(Scheduler const&) = delete;
156  Scheduler&
157  operator=(Scheduler const&) = delete;
158 
159  Scheduler();
160 
162  clock_type&
163  clock() const;
164 
169  time_point
170  now() const;
171 
172  // Used to cancel timers
173  struct cancel_token;
174 
183  template <class Function>
185  at(time_point const& when, Function&& f);
186 
195  template <class Function>
197  in(duration const& delay, Function&& f);
198 
206  void
207  cancel(cancel_token const& token);
208 
218  bool
219  step_one();
220 
230  bool
231  step();
232 
246  template <class Function>
247  bool
248  step_while(Function&& func);
249 
259  bool
260  step_until(time_point const& until);
261 
271  template <class Period, class Rep>
272  bool
274 };
275 
276 //------------------------------------------------------------------------------
277 
279  boost::container::pmr::monotonic_buffer_resource* alloc)
280  : alloc_(alloc)
281 {
282 }
283 
285 {
286  for (auto iter = by_when_.begin(); iter != by_when_.end();)
287  {
288  auto e = &*iter;
289  ++iter;
290  e->~event();
291  alloc_->deallocate(e, sizeof(e));
292  }
293 }
294 
295 inline bool
297 {
298  return by_when_.empty();
299 }
300 
301 inline auto
303 {
304  return by_when_.begin();
305 }
306 
307 inline auto
309 {
310  return by_when_.end();
311 }
312 
313 template <class Handler>
314 inline auto
316  typename by_when_set::iterator
317 {
318  using event_type = event_impl<std::decay_t<Handler>>;
319  auto const p = alloc_->allocate(sizeof(event_type));
320  auto& e = *new (p) event_type(when, std::forward<Handler>(h));
321  return by_when_.insert(e);
322 }
323 
324 inline auto
325 Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
326 {
327  auto& e = *iter;
328  auto next = by_when_.erase(iter);
329  e.~event();
330  alloc_->deallocate(&e, sizeof(e));
331  return next;
332 }
333 
334 //-----------------------------------------------------------------------------
336 {
337 private:
339 
340 public:
341  cancel_token() = delete;
342  cancel_token(cancel_token const&) = default;
343  cancel_token&
344  operator=(cancel_token const&) = default;
345 
346 private:
347  friend class Scheduler;
348  cancel_token(typename queue_type::iterator iter) : iter_(iter)
349  {
350  }
351 };
352 
353 //------------------------------------------------------------------------------
355 {
356 }
357 
358 inline auto
360 {
361  return clock_;
362 }
363 
364 inline auto
366 {
367  return clock_.now();
368 }
369 
370 template <class Function>
371 inline auto
372 Scheduler::at(time_point const& when, Function&& f) -> cancel_token
373 {
374  return queue_.emplace(when, std::forward<Function>(f));
375 }
376 
377 template <class Function>
378 inline auto
379 Scheduler::in(duration const& delay, Function&& f) -> cancel_token
380 {
381  return at(clock_.now() + delay, std::forward<Function>(f));
382 }
383 
384 inline void
386 {
387  queue_.erase(token.iter_);
388 }
389 
390 inline bool
392 {
393  if (queue_.empty())
394  return false;
395  auto const iter = queue_.begin();
396  clock_.set(iter->when);
397  (*iter)();
398  queue_.erase(iter);
399  return true;
400 }
401 
402 inline bool
404 {
405  if (!step_one())
406  return false;
407  for (;;)
408  if (!step_one())
409  break;
410  return true;
411 }
412 
413 template <class Function>
414 inline bool
416 {
417  bool ran = false;
418  while (f() && step_one())
419  ran = true;
420  return ran;
421 }
422 
423 inline bool
425 {
426  // VFALCO This routine needs optimizing
427  if (queue_.empty())
428  {
429  clock_.set(until);
430  return false;
431  }
432  auto iter = queue_.begin();
433  if (iter->when > until)
434  {
435  clock_.set(until);
436  return true;
437  }
438  do
439  {
440  step_one();
441  iter = queue_.begin();
442  } while (iter != queue_.end() && iter->when <= until);
443  clock_.set(until);
444  return iter != queue_.end();
445 }
446 
447 template <class Period, class Rep>
448 inline bool
450 {
451  return step_until(now() + amount);
452 }
453 
454 } // namespace csf
455 } // namespace test
456 } // namespace ripple
457 
458 #endif
ripple::test::csf::Scheduler::queue_type::queue_type
queue_type(queue_type const &)=delete
utility
ripple::test::csf::Scheduler::queue_type::emplace
by_when_set::iterator emplace(time_point when, Handler &&h)
ripple::test::csf::Scheduler::event::event
event(event const &)=delete
ripple::test::csf::Scheduler::cancel
void cancel(cancel_token const &token)
Cancel a timer.
Definition: test/csf/Scheduler.h:385
ripple::test::csf::Scheduler::event::operator=
event & operator=(event const &)=delete
ripple::test::csf::Scheduler::queue_type::end
iterator end()
Definition: test/csf/Scheduler.h:308
ripple::test::csf::Scheduler::step_while
bool step_while(Function &&func)
Run the scheduler while a condition is true.
Definition: test/csf/Scheduler.h:415
ripple::test::csf::Scheduler::clock
clock_type & clock() const
Return the clock.
Definition: test/csf/Scheduler.h:359
ripple::test::csf::Scheduler
Simulated discrete-event scheduler.
Definition: test/csf/Scheduler.h:47
std::chrono::duration
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
beast::manual_clock::set
void set(time_point const &when)
Set the current time of the manual clock.
Definition: manual_clock.h:62
ripple::test::csf::Scheduler::time_point
typename clock_type::time_point time_point
Definition: test/csf/Scheduler.h:54
ripple::test::csf::Scheduler::queue_type::iterator
typename by_when_set::iterator iterator
Definition: test/csf/Scheduler.h:120
ripple::test::csf::Scheduler::queue_type
Definition: test/csf/Scheduler.h:109
ripple::test::csf::Scheduler::queue_type::operator=
queue_type & operator=(queue_type const &)=delete
ripple::test::csf::Scheduler::cancel_token::iter_
queue_type::iterator iter_
Definition: test/csf/Scheduler.h:338
ripple::test::csf::Scheduler::event_impl::event_impl
event_impl(time_point when_, DeducedHandler &&h)
Definition: test/csf/Scheduler.h:97
ripple::test::csf::Scheduler::step_one
bool step_one()
Run the scheduler for up to one event.
Definition: test/csf/Scheduler.h:391
ripple::test::csf::Scheduler::alloc_
boost::container::pmr::monotonic_buffer_resource alloc_
Definition: test/csf/Scheduler.h:148
ripple::test::csf::Scheduler::cancel_token
Definition: test/csf/Scheduler.h:335
ripple::test::csf::Scheduler::in
cancel_token in(duration const &delay, Function &&f)
Schedule an event after a specified duration passes.
ripple::test::csf::Scheduler::queue_type::erase
iterator erase(iterator iter)
Definition: test/csf/Scheduler.h:325
ripple::test::csf::Scheduler::duration
typename clock_type::duration duration
Definition: test/csf/Scheduler.h:52
ripple::test::csf::Scheduler::event::operator<
bool operator<(event const &other) const
Definition: test/csf/Scheduler.h:79
ripple::test::csf::Scheduler::by_when_hook
boost::intrusive::set_base_hook< boost::intrusive::link_mode< boost::intrusive::normal_link > > by_when_hook
Definition: test/csf/Scheduler.h:58
ripple::test::csf::Scheduler::event_impl::h_
const Handler h_
Definition: test/csf/Scheduler.h:88
ripple::test::csf::Scheduler::cancel_token::cancel_token
cancel_token(typename queue_type::iterator iter)
Definition: test/csf/Scheduler.h:348
ripple::test::csf::Scheduler::queue_type::begin
iterator begin()
Definition: test/csf/Scheduler.h:302
ripple::test::csf::Scheduler::Scheduler
Scheduler()
Definition: test/csf/Scheduler.h:354
ripple::test::csf::Scheduler::queue_type::empty
bool empty() const
Definition: test/csf/Scheduler.h:296
ripple::test::csf::Scheduler::event_impl::operator=
event_impl & operator=(event_impl const &)=delete
ripple::test::csf::Scheduler::event::event
event(time_point when_)
Definition: test/csf/Scheduler.h:74
ripple::test::csf::Scheduler::event_impl
Definition: test/csf/Scheduler.h:86
ripple::test::csf::Scheduler::event_impl::operator()
void operator()() const override
Definition: test/csf/Scheduler.h:103
ripple::test::csf::Scheduler::step_until
bool step_until(time_point const &until)
Run the scheduler until the specified time.
Definition: test/csf/Scheduler.h:424
ripple::test::csf::Scheduler::queue_
queue_type queue_
Definition: test/csf/Scheduler.h:149
beast::manual_clock::now
time_point now() const override
Returns the current time.
Definition: manual_clock.h:55
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::csf::Scheduler::at
cancel_token at(time_point const &when, Function &&f)
Schedule an event at a specific time.
ripple::test::csf::Scheduler::queue_type::by_when_
by_when_set by_when_
Definition: test/csf/Scheduler.h:117
ripple::test::csf::Scheduler::step
bool step()
Run the scheduler until no events remain.
Definition: test/csf/Scheduler.h:403
ripple::test::csf::Scheduler::event
Definition: test/csf/Scheduler.h:60
std
STL namespace.
ripple::test::csf::Scheduler::event::~event
virtual ~event()=default
ripple::test::csf::Scheduler::queue_type::~queue_type
~queue_type()
Definition: test/csf/Scheduler.h:284
ripple::test::csf::Scheduler::event::operator()
virtual void operator()() const =0
ripple::test::csf::Scheduler::queue_type::by_when_set
typename boost::intrusive::make_multiset< event, boost::intrusive::constant_time_size< false > >::type by_when_set
Definition: test/csf/Scheduler.h:114
ripple::test::csf::Scheduler::queue_type::alloc_
boost::container::pmr::monotonic_buffer_resource * alloc_
Definition: test/csf/Scheduler.h:116
ripple::test::csf::Scheduler::operator=
Scheduler & operator=(Scheduler const &)=delete
beast::manual_clock< std::chrono::steady_clock >
ripple::test::csf::Scheduler::clock_
clock_type clock_
Definition: test/csf/Scheduler.h:152
ripple::test::csf::Scheduler::now
time_point now() const
Return the current network time.
Definition: test/csf/Scheduler.h:365
ripple::test::csf::Scheduler::step_for
bool step_for(std::chrono::duration< Period, Rep > const &amount)
Run the scheduler until time has elapsed.
Definition: test/csf/Scheduler.h:449
beast::abstract_clock< std::chrono::steady_clock >::time_point
typename std::chrono::steady_clock ::time_point time_point
Definition: abstract_clock.h:63
ripple::test::csf::Scheduler::event::when
time_point when
Definition: test/csf/Scheduler.h:62
type_traits
beast::abstract_clock< std::chrono::steady_clock >::duration
typename std::chrono::steady_clock ::duration duration
Definition: abstract_clock.h:62
ripple::test::csf::Scheduler::event_impl::event_impl
event_impl(event_impl const &)=delete