Skip to content

Deterministic hashed wheel timer with keyed deduplication.

Notifications You must be signed in to change notification settings

markbrosalin/okee-wheel-timer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

okee-wheel-timer

Deterministic hashed wheel timer with keyed deduplication.

Features

  • HashedWheelTimer<T>: core single-level hashed wheel timer.
  • KeyedHashedWheelTimer<T, K, F>: keyed dedup wrapper over the core timer.
  • Stable pop ordering by (tick, delta_tick, event_id).

Installation

[dependencies]
okee-wheel-timer = "0.1.0"

How It Works

use okee_wheel_timer::HashedWheelTimer;

// 8 buckets in one wheel cycle.
let mut wheel = HashedWheelTimer::new(8);
  • new(8) means one wheel cycle has 8 buckets.
  • Time is tracked by tick.
  • step() advances one tick and moves to the next bucket.
  • Events are stored with (tick, delta_tick).
    • tick is the absolute time when the event is eligible.
    • delta_tick is the wave index inside the same tick.

delta_tick prevents processing newly scheduled "same tick" events in the same wave.

Core Timer Example

use okee_wheel_timer::HashedWheelTimer;

let mut wheel = HashedWheelTimer::new(8);
let created = wheel.schedule(0, "payload");

let first_wave = wheel.pop_events();
assert_eq!(first_wave.len(), 1);
assert_eq!(first_wave[0].id(), created.id);
assert_eq!(first_wave[0].tick(), 0);
assert_eq!(first_wave[0].data(), &"payload");

Keyed Timer Example

HashedWheelTimer always creates a new event ID. KeyedHashedWheelTimer can replace an existing event by your dedup key.

use okee_wheel_timer::KeyedHashedWheelTimer;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Job {
    user_id: u64,
    queue: u8,
    payload: i32,
}

let mut wheel = KeyedHashedWheelTimer::new(8, |job: &Job| (job.user_id, job.queue));

let first = wheel.schedule(
    10,
    Job {
        user_id: 42,
        queue: 1,
        payload: 100,
    },
);

let second = wheel.schedule(
    12,
    Job {
        user_id: 42, // same user_id and queue as previous
        queue: 1,
        payload: 200,
    },
);

assert_eq!(second.replaced_id, Some(first.id));
assert!(!wheel.contains_by_id(first.id));
assert!(wheel.contains_by_id(second.id));

Dedup Key Design

  • In keyed mode, you are responsible for dedup semantics.
  • The dedup key is produced from &T (Fn(&T) -> K).
  • If timing should affect uniqueness, include timing fields in your payload T and key them explicitly.

Processing Contract

  • Call pop_events() while has_events_in_current_tick() is true.
  • Call step() to move to the next tick.
  • Typical loop:
while wheel.has_events_in_current_tick() {
    let events = wheel.pop_events();
    // process events
}
wheel.step();

Benchmarks

Benchmarks are implemented with Criterion in benches/wheel.rs.

# run all timer benchmarks
cargo bench --bench wheel

# save current results as baseline
cargo bench --bench wheel -- --save-baseline v1

# compare current run with a saved baseline
cargo bench --bench wheel -- --baseline v1

HTML reports are generated in target/criterion/report/index.html.

About

Deterministic hashed wheel timer with keyed deduplication.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages