Module Timing_wheel_float

A timing wheel in which time is represented by Time.t, i.e. a floating-point number of seconds since the epoch.

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:

      Alarm.at a >= now t - alarm_precision t


include Core_kernel.Timing_wheel_intf.Timing_wheel with module Time = Time
module Time = Time
type 'a t
val sexp_of_t : ('a -> Sexplib.Sexp.t) -> 'a t -> Sexplib.Sexp.t
type 'a timing_wheel = 'a t
type 'a t_now = 'a t

<:sexp_of< _ t_now >> displays only now t, not all the alarms.

val sexp_of_t_now : ('a -> Sexplib.Sexp.t) -> 'a t_now -> Sexplib.Sexp.t
module Alarm : sig .. end
include Core_kernel.Invariant.S1 with type 'a t := 'a t
type 'a t
val invariant : 'a Invariant_intf.inv -> 'a t Invariant_intf.inv
module Level_bits : sig .. end
module Config : sig .. end
val create : config:Config.t -> start:Time.t -> 'a t

create ~config ~start creates a new timing wheel with current time start.

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.

val alarm_precision : _ t -> Time.Span.t


val now : _ t -> Time.t
val start : _ t -> Time.t
val is_empty : _ t -> bool

One can think of a timing wheel as a set of alarms. Here are various container functions along those lines.

val length : _ t -> int
val iter : 'a t -> f:('a Alarm.t -> unit) -> unit
val interval_num : _ t -> Time.t -> Interval_num.t

interval_num t time returns the number of the interval that time is in, where 0 is the interval that starts at start. interval_num raises if time is too far in the past or future to represent.

now_interval_num t equals interval_num t (now t).

val now_interval_num : _ t -> Interval_num.t
val interval_num_start : _ t -> Interval_num.t -> Time.t

interval_num_start t n is the start of the n'th interval in t, i.e.:

        start t + n * alarm_precision t

interval_start t time is the start of the half-open interval containing time, i.e.:

        interval_num_start t (interval_num t time)

interval_start raises in the same cases that interval_num does.

val interval_start : _ t -> Time.t -> Time.t
val advance_clock : 'a t -> to_:Time.t -> handle_fired:('a Alarm.t -> unit) -> unit

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 : 'a t -> handle_fired:('a Alarm.t -> unit) -> unit

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.

val alarm_upper_bound : _ t -> Time.t

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.

val add : 'a t -> at:Time.t -> 'a -> 'a Alarm.t

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.

val add_at_interval_num : 'a t -> at:Interval_num.t -> 'a -> 'a Alarm.t
val mem : 'a t -> 'a Alarm.t -> bool
val remove : 'a t -> 'a Alarm.t -> unit

remove t alarm removes alarm from t. remove raises if not (mem t alarm).

val reschedule : 'a t -> 'a Alarm.t -> at:Time.t -> unit

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:

        reschedule t alarm ~at:(interval_num_start t at)
val reschedule_at_interval_num : 'a t -> 'a Alarm.t -> at:Interval_num.t -> unit
val clear : _ t -> unit

clear t removes all alarms from t.

val next_alarm_fires_at : _ t -> Time.t option

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.

val next_alarm_fires_at_exn : _ t -> Time.t
Implementation details

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.

module Priority_queue : sig .. end
Timing wheel is implemented as a priority queue in which the keys are non-negative integers corresponding to the intervals of time.