TimerWheel

Struct TimerWheel 

Source
pub struct TimerWheel<T> { /* private fields */ }
Expand description

High-performance hierarchical timing wheel

Uses a two-level hierarchy to efficiently handle timers across a wide time range:

  • L0 (Fast wheel): Handles near-term timers (0 to ~1 second)
    • Fine-grained resolution for accurate short-term scheduling
    • Polled frequently for expired timers
  • L1 (Medium wheel): Handles long-term timers (~1 second to ~18 minutes)
    • Coarser resolution to reduce memory overhead
    • Timers cascade down to L0 as their deadline approaches

The hierarchy allows O(1) scheduling and cancellation while supporting a wide range of timer durations without excessive memory usage.

Implementations§

Source§

impl<T> TimerWheel<T>

Source

pub fn new( tick_resolution: Duration, ticks_per_wheel: usize, worker_id: u32, ) -> Self

Create new hierarchical timer wheel

§Arguments
  • tick_resolution - L0 tick duration (must be power of 2 nanoseconds, typically 1.05ms)
  • ticks_per_wheel - Number of spokes per wheel (must be power of 2, typically 1024)
  • worker_id - Worker ID that owns this timer wheel
§Timer Deadlines

All timer deadlines are specified as nanoseconds elapsed since wheel creation.

Source

pub fn with_allocation( tick_resolution: Duration, ticks_per_wheel: usize, initial_tick_allocation: usize, worker_id: u32, ) -> Self

Create hierarchical timer wheel with custom initial allocation per tick

§Arguments
  • tick_resolution - L0 tick duration (must be power of 2 nanoseconds)
  • ticks_per_wheel - Number of spokes per wheel (must be power of 2)
  • initial_tick_allocation - Initial slots per tick (must be power of 2)
  • worker_id - Worker ID that owns this timer wheel
§Design Notes

The L1 tick resolution equals one full L0 rotation, creating a natural cascading relationship: when an L1 tick expires, all its timers are within L0’s coverage range and can be cascaded down.

Source

pub fn schedule_timer( &mut self, deadline_ns: u64, data: T, ) -> Result<u64, TimerWheelError>

Schedule a timer for an absolute deadline

The deadline is specified as nanoseconds since wheel creation. The timer is automatically placed in the appropriate wheel (L0 for near-term, L1 for long-term) based on the deadline value.

§Arguments
  • deadline_ns - Absolute deadline in nanoseconds (must be > 0 and in the future)
  • data - User data to associate with this timer
§Returns

Returns a timer ID that can be used to cancel the timer, or an error if the deadline is invalid or capacity is exceeded.

Source

pub fn cancel_timer( &mut self, timer_id: u64, ) -> Result<Option<T>, TimerWheelError>

Cancel a previously scheduled timer

O(1) operation - directly indexes into the wheel using the timer ID.

§Arguments
  • timer_id - Timer ID returned from schedule_timer()
§Returns

Returns the timer data if found and cancelled, or an error if the timer doesn’t exist or the timer ID is invalid.

Source

pub fn poll( &mut self, now_ns: u64, expiry_limit: usize, output: &mut Vec<(u64, u64, T)>, ) -> usize

Poll for expired timers

Checks for timers that have expired by the given now_ns time. First cascades L1 timers that are now within L0 coverage down to L0, then polls L0 for expired timers.

§Arguments
  • now_ns - Current time in nanoseconds
  • expiry_limit - Maximum number of expired timers to return
  • output - Buffer to write expired timer tuples: (timer_id, deadline_ns, data)
§Returns

Returns the number of expired timers found (may be less than expiry_limit)

Source

pub fn advance_to(&mut self, now_ns: u64)

Advance the wheel’s current tick position without polling

Useful for synchronizing the wheel’s position when time advances without immediately processing expired timers.

Source

pub fn current_tick_time_ns(&self) -> u64

Get the time corresponding to the next tick

Returns the absolute time (in nanoseconds) when the next tick will occur.

Source

pub fn timer_count(&self) -> u64

Get the total number of active timers across both wheels

Source

pub fn next_deadline(&mut self) -> Option<u64>

Get the earliest deadline among all active timers

Uses cached values when available for O(1) performance. Falls back to full wheel scans when cache is invalidated (O(ticks_per_wheel × tick_allocation)).

§Returns

Returns the earliest deadline in nanoseconds, or None if no timers are scheduled.

Source

pub fn now_ns(&self) -> u64

Source

pub fn set_now_ns(&mut self, now_ns: u64)

Source

pub fn worker_id(&self) -> u32

Source

pub fn clear(&mut self)

Auto Trait Implementations§

§

impl<T> !Freeze for TimerWheel<T>

§

impl<T> RefUnwindSafe for TimerWheel<T>
where T: RefUnwindSafe,

§

impl<T> Send for TimerWheel<T>
where T: Send,

§

impl<T> Sync for TimerWheel<T>
where T: Sync,

§

impl<T> Unpin for TimerWheel<T>
where T: Unpin,

§

impl<T> UnwindSafe for TimerWheel<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V