summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_asio_frontend_timer.h
blob: b7d6a63b46f114fb5debdd042138ef5be1b646fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#pragma once

#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/intrusive_ptr.hpp>

#include "common/ceph_time.h"

namespace rgw {

// a WaitHandler that closes a stream if the timeout expires
template <typename Stream>
struct timeout_handler {
  // this handler may outlive the timer/stream, so we need to hold a reference
  // to keep the stream alive
  boost::intrusive_ptr<Stream> stream;

  explicit timeout_handler(boost::intrusive_ptr<Stream> stream) noexcept
      : stream(std::move(stream)) {}

  void operator()(boost::system::error_code ec) {
    if (!ec) { // wait was not canceled
      boost::system::error_code ec_ignored;
      stream->close(ec_ignored);
    }
  }
};

// a timeout timer for stream operations
template <typename Clock, typename Executor, typename Stream>
class basic_timeout_timer {
 public:
  using clock_type = Clock;
  using duration = typename clock_type::duration;
  using executor_type = Executor;

  explicit basic_timeout_timer(const executor_type& ex, duration dur,
                               boost::intrusive_ptr<Stream> stream)
      : timer(ex), dur(dur), stream(std::move(stream))
  {}

  basic_timeout_timer(const basic_timeout_timer&) = delete;
  basic_timeout_timer& operator=(const basic_timeout_timer&) = delete;

  void start() {
    if (dur.count() > 0) {
      timer.expires_after(dur);
      timer.async_wait(timeout_handler{stream});
    }
  }

  void cancel() {
    if (dur.count() > 0) {
      timer.cancel();
    }
  }

 private:
  using Timer = boost::asio::basic_waitable_timer<clock_type,
        boost::asio::wait_traits<clock_type>, executor_type>;
  Timer timer;
  duration dur;
  boost::intrusive_ptr<Stream> stream;
};

} // namespace rgw