38class CountdownSwitch {
45 std::int64_t refresh_numerator = 1,
46 std::int64_t refresh_denominator = 3) noexcept
48 period_ns_(window_ms_ <= 0
50 : std::
max<std::int64_t>(
52 window_ms_ * 1'000'000 * std::
max<std::int64_t>(1, refresh_numerator) /
53 std::
max<std::int64_t>(1, refresh_denominator))) {}
56 static constexpr std::int64_t
kMinPeriodNs = 500'000'000;
58 [[nodiscard]]
bool enabled() const noexcept {
return window_ms_ > 0; }
59 [[nodiscard]] std::int64_t
window_ms() const noexcept {
return window_ms_; }
64 [[nodiscard]]
bool due(std::int64_t now_ns)
const noexcept {
65 return enabled() && (last_attempt_ns_ == 0 || now_ns - last_attempt_ns_ >= period_ns_);
69 void attempted(std::int64_t now_ns)
noexcept { last_attempt_ns_ = now_ns == 0 ? 1 : now_ns; }
71 void armed(std::int64_t now_ns)
noexcept { last_armed_ns_ = now_ns == 0 ? 1 : now_ns; }
79 [[nodiscard]]
bool expired(std::int64_t now_ns)
const noexcept {
80 return enabled() && last_armed_ns_ != 0 && now_ns - last_armed_ns_ >= window_ms_ * 1'000'000;
82 [[nodiscard]]
bool ever_armed() const noexcept {
return last_armed_ns_ != 0; }
91 std::int64_t window_ms_ = 0;
92 std::int64_t period_ns_ = 0;
93 std::int64_t last_attempt_ns_ = 0;
94 std::int64_t last_armed_ns_ = 0;
116class CountdownDriver {
122 std::int64_t refresh_numerator = 1,
123 std::int64_t refresh_denominator = 3) noexcept
124 : clock_(
window_ms, refresh_numerator, refresh_denominator) {}
126 [[nodiscard]]
bool enabled() const noexcept {
return clock_.
enabled(); }
128 [[nodiscard]]
bool lapsed() const noexcept {
return lapsed_; }
133 [[nodiscard]]
Step poll(std::int64_t now_ns)
noexcept {
145 [[nodiscard]] std::uint32_t
begin_round(std::int64_t now_ns, std::uint32_t parts)
noexcept {
147 round_ns_ = now_ns == 0 ? 1 : now_ns;
148 round_parts_ = parts;
149 round_confirmed_ = 0;
158 void confirmed(std::uint32_t round)
noexcept {
159 if (round != round_ || lapsed_ || round_confirmed_ >= round_parts_)
return;
160 if (++round_confirmed_ == round_parts_) clock_.
armed(round_ns_);
164 [[nodiscard]]
bool needs_stop() const noexcept {
return clock_.
enabled() && ever_sent_; }
167 void reset() noexcept {
173 round_confirmed_ = 0;
178 bool lapsed_ =
false;
179 bool ever_sent_ =
false;
180 std::uint32_t round_ = 0;
181 std::uint32_t round_parts_ = 0;
182 std::uint32_t round_confirmed_ = 0;
183 std::int64_t round_ns_ = 0;
void confirmed(std::uint32_t round) noexcept
The venue confirmed one part of round round.
Definition dead_mans_switch.hpp:160
CountdownDriver()=default
bool ever_armed() const noexcept
Definition dead_mans_switch.hpp:131
Step
Definition dead_mans_switch.hpp:120
void went_out() noexcept
Definition dead_mans_switch.hpp:154
std::uint32_t begin_round(std::int64_t now_ns, std::uint32_t parts) noexcept
A refresh round of parts requests starts now; the token goes with each part's reply.
Definition dead_mans_switch.hpp:147
std::int64_t window_ms() const noexcept
Definition dead_mans_switch.hpp:129
void reset() noexcept
The session ended (after the stop): the next connect starts from scratch.
Definition dead_mans_switch.hpp:169
const CountdownSwitch & clock() const noexcept
Definition dead_mans_switch.hpp:132
bool enabled() const noexcept
Definition dead_mans_switch.hpp:128
bool lapsed() const noexcept
Definition dead_mans_switch.hpp:130
bool needs_stop() const noexcept
Whether the shutdown has to stop the venue's countdown.
Definition dead_mans_switch.hpp:166
Step poll(std::int64_t now_ns) noexcept
From the housekeeping timer. Lapsed is returned once per session.
Definition dead_mans_switch.hpp:135
Refresh clock for a countdown dead man's switch.
Definition dead_mans_switch.hpp:40
bool enabled() const noexcept
Definition dead_mans_switch.hpp:60
CountdownSwitch()=default
void attempted(std::int64_t now_ns) noexcept
A refresh was written to the venue.
Definition dead_mans_switch.hpp:71
void disarm() noexcept
The session ended, or the kill already fired: the next due() starts from scratch.
Definition dead_mans_switch.hpp:87
static constexpr std::int64_t kMinPeriodNs
A refresh sent more often than this is wasted rate limit whatever the window is.
Definition dead_mans_switch.hpp:58
bool ever_armed() const noexcept
Definition dead_mans_switch.hpp:84
void armed(std::int64_t now_ns) noexcept
The venue accepted the refresh: the countdown is running from here.
Definition dead_mans_switch.hpp:73
std::int64_t window_ms() const noexcept
Definition dead_mans_switch.hpp:61
bool due(std::int64_t now_ns) const noexcept
True when a refresh has to go out now.
Definition dead_mans_switch.hpp:66
bool expired(std::int64_t now_ns) const noexcept
The window has run out since the last refresh the venue confirmed: it has cancelled our orders,...
Definition dead_mans_switch.hpp:81
std::int64_t refresh_period_ns() const noexcept
Definition dead_mans_switch.hpp:62
constexpr Fixed< T > max(Fixed< T > a, Fixed< T > b) noexcept
Definition fixed_point.hpp:418