Legend:
Library
Module
Module type
Parameter
Class
Class type
A timing wheel in which time is represented by Time.t, i.e., by a floating-point number of seconds since the epoch. This is a wrapper around Timing_wheel_ns, which is preferable both because it has better performance and because it avoids issues having to do with floating point (im)precision.
The implementation uses Timing_wheel_ns and rounds all Time.t values to the nearest microsecond before feeding them to the underlying timing wheel. Thus, it is possible that Time.( < ) (Alarm.at t (add t ~at a)) at, with the alarm's at being up to a microsecond earlier than requested. However, because the alarm precision of the underlying timing wheel is an integer number of microseconds, we are still guaranteed when an alarm fires that at < now t, i.e., the timing-wheel's clock is beyond the time requested for the alarm to fire.
Due to floating-point arithmetic, the guarantee that alarms don't fire too late needs to be weakened slightly to use >= rather than > . For all alarms a in t:
create ~config ~start creates a new timing wheel with current time start. create raises if start < Time.epoch. For a fixed level_bits, a smaller (i.e. more precise) alarm_precision decreases the representable range of times/keys and increases the constant factor for advance_clock.
interval_num t time returns the number of the interval that time is in, where 0 is the interval that starts at Time.epoch. interval_num raises if Time.( <
) time Time.epoch.
val advance_clock :
'at->to_:Time.t->handle_fired:('aAlarm.t->Base.Unit.t)->Base.Unit.t
advance_clock t ~to_ ~handle_fired advances t's clock to to_. It fires and removes all alarms a in t with Time.(<) (Alarm.at t a) (interval_start t to_), applying handle_fired to each such a.
If to_ <= now t, then advance_clock does nothing.
advance_clock fails if to_ is too far in the future to represent.
Behavior is unspecified if handle_fired accesses t in any way other than Alarm functions.
val fire_past_alarms :
'at->handle_fired:('aAlarm.t->Base.Unit.t)->Base.Unit.t
fire_past_alarms t ~handle_fired fires and removes all alarms a in t with Time.( <= ) (Alarm.at t a) (now t), applying handle_fired to each such a.
fire_past_alarms visits all alarms in interval now_interval_num, to check their Alarm.at.
Behavior is unspecified if handle_fired accesses t in any way other than Alarm functions.
alarm_upper_bound t returns the upper bound on an at that can be supplied to add. alarm_upper_bound t is not constant; its value increases as now t increases.
add t ~at a adds a new value a to t and returns an alarm that can later be supplied to remove the alarm from t. add raises if interval_num t at <
now_interval_num t || at >= alarm_upper_bound t.
add_at_interval_num t ~at a is equivalent to add t ~at:(interval_num_start t at)
a.
reschedule t alarm ~at mutates alarm so that it will fire at at, i.e. so that Alarm.at t alarm = at. reschedule raises if not (mem t alarm) or if at is an invalid time for t, in the same situations that add raises.
reschedule_at_interval_num t alarm ~at is equivalent to:
val min_alarm_interval_num : _t->Interval_num.tBase.Option.t
min_alarm_interval_num t is the minimum Alarm.interval_num of all alarms in t. min_alarm_interval_num_exn t is the same, except it raises if is_empty
t.
val max_alarm_time_in_min_interval : 'at->Time.tBase.Option.t
max_alarm_time_in_min_interval t returns the maximum Alarm.at over all alarms in t whose Alarm.interval_num is min_alarm_interval_num t.
max_alarm_time_in_min_interval_exn t is the same as max_alarm_time_in_min_interval, except that it raises if is_empty t.
This function is useful for advancing to the min_alarm_interval_num of a timing wheel and then calling fire_past_alarms to fire the alarms in that interval. That is useful when simulating time, to ensure that alarms are processed in order.
val max_alarm_time_in_min_interval_exn : 'at->Time.t
next_alarm_fires_at t returns the minimum time to which the clock can be advanced such that an alarm will fire, or None if t has no alarms. If next_alarm_fires_at t = Some next, then for the minimum alarm time min that occurs in t, it is guaranteed that: next - alarm_precision t <= min < next.
next_alarm_fires_at_exn is the same as next_alarm_fires_at, except that it raises if is_empty t.
The rest of this interface is not intended to be used with Timing_wheel, but is a separate data structure used to implement Timing_wheel, and may find use elsewhere.
Timing wheel is implemented as a priority queue in which the keys are non-negative integers corresponding to the intervals of time. The priority queue is unlike a typical priority queue in that rather than having a "delete min" operation, it has a nondecreasing minimum allowed key, which corresponds to the current time, and an increase_min_allowed_key operation, which implements advance_clock. increase_min_allowed_key as a side effect removes all elements from the timing wheel whose key is smaller than the new minimum, which implements firing the alarms whose time has expired.