-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | A timer wheel
--
-- This library provides a timer wheel data structure for
--
--
-- - (Almost) O(1) registering IO actions to fire after
-- a given amount of time
-- - O(1) canceling registered actions
--
--
-- It is similar to TimerManager from GHC.Event, but
-- supports recurring timers, can scale to handle many more registered
-- timers.
@package timer-wheel
@version 0.4.0.1
-- | A simple, hashed timer wheel.
module TimerWheel
-- | A timer wheel is a vector-of-collections-of timers to fire. It is
-- configured with a spoke count and resolution. Timers may
-- be scheduled arbitrarily far in the future. A timeout thread is
-- spawned to step through the timer wheel and fire expired timers at
-- regular intervals.
--
--
-- - The spoke count determines the size of the timer
-- vector.
- A larger spoke count will result in less
-- insert contention at each spoke and will require more
-- memory to store the timer wheel.
- A smaller spoke
-- count will result in more insert contention at each spoke
-- and will require less memory to store the timer
-- wheel.
-- - The resolution determines both the duration of time that
-- each spoke corresponds to, and how often the timeout thread wakes. For
-- example, with a resolution of 1s, a timer that expires
-- at 2.5s will not fire until the timeout thread wakes
-- at 3s.
- A larger resolution will result
-- in more insert contention at each spoke, less accurate
-- timers, and will require fewer wakeups by the timeout
-- thread.
- A smaller resolution will result in less
-- insert contention at each spoke, more accurate timers, and
-- will require more wakeups by the timeout thread.
-- - The timeout thread has some important properties:
- There is
-- only one, and it fires expired timers synchronously. If your timer
-- actions execute quicky, register them directly. Otherwise,
-- consider registering an action that enqueues the real action to
-- be performed on a job queue.
- Synchronous exceptions thrown by
-- enqueued IO actions will bring the thread down, and the
-- exception will be propagated to the thread that created the timer
-- wheel. If you want to catch exceptions and log them, for example, you
-- will have to bake this into the registered actions
-- yourself.
--
--
-- As an example, below is a depiction of a timer wheel with 6
-- timers inserted across 8 spokes, and a resolution of
-- .1s. It depicts a cursor at .3s, which indicates
-- where the timeout thread currently is.
--
--
-- 0 .1 .2 .3 .4 .5 .6 .7
-- ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
-- │ │ A⁰ │ │ B¹ C⁰ │ D⁰ │ │ │ E² F⁰ │
-- └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
-- ↑
--
--
-- After .1s, the timeout thread will advance to the next spoke
-- and process all of the timers it passed over. In this case, C
-- will fire, and B will be put back with its count decremented to
-- 0. This is how the timer wheel can schedule a timer to fire
-- arbitrarily far in the future: its count is simply the number of times
-- its delay wraps the entire duration of the timer wheel.
--
--
-- 0 .1 .2 .3 .4 .5 .6 .7
-- ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
-- │ │ A⁰ │ │ B⁰ │ D⁰ │ │ │ E² F⁰ │
-- └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
-- ↑
--
data TimerWheel
-- | Create a timer wheel in a scope.
--
-- Throws.
--
--
-- - Calls error if the config is invalid
--
create :: Scope -> Config -> IO TimerWheel
-- | Perform an action with a timer wheel.
--
-- Throws.
--
--
-- - Calls error if the config is invalid
-- - Throws the exception the given action throws, if any
-- - Throws the exception the timer wheel thread throws, if any
--
with :: Config -> (TimerWheel -> IO a) -> IO a
-- | Timer wheel config.
--
--
-- - spokes must be ∈ [1, maxBound]
-- - resolution must ∈ (0, ∞]
--
data Config
Config :: {-# UNPACK #-} !Int -> !Fixed E6 -> Config
-- | Spoke count.
[spokes] :: Config -> {-# UNPACK #-} !Int
-- | Resolution, in seconds.
[resolution] :: Config -> !Fixed E6
-- | register wheel delay action registers an action
-- action in timer wheel wheel to fire
-- after delay seconds.
--
-- Returns an action that, when called, attempts to cancel the timer, and
-- returns whether or not it was successful (False means the
-- timer has already fired, or was already cancelled).
register :: TimerWheel -> Fixed E6 -> IO () -> IO (IO Bool)
-- | Like register, but for when you don't intend to cancel the
-- timer.
register_ :: TimerWheel -> Fixed E6 -> IO () -> IO ()
-- | recurring wheel action delay registers an action
-- action in timer wheel wheel to fire
-- every delay seconds.
--
-- Returns an action that, when called, cancels the recurring timer.
recurring :: TimerWheel -> Fixed E6 -> IO () -> IO (IO ())
-- | Like recurring, but for when you don't intend to cancel the
-- timer.
recurring_ :: TimerWheel -> Fixed E6 -> IO () -> IO ()