Skip to main content

kestrel_timer/
lib.rs

1//! # High-Performance Async Timer System
2//!
3//! High-performance async timer based on Timing Wheel algorithm, supports tokio runtime
4//!
5//! ## Features
6//!
7//! - **High Performance**: Uses timing wheel algorithm, insert and delete operations are O(1)
8//! - **Large-Scale Support**: Efficiently manages 10000+ concurrent timers
9//! - **Async Support**: Based on tokio async runtime
10//! - **Thread-Safe**: Uses parking_lot for high-performance locking mechanism
11//!
12//!
13//! # 高性能异步定时器库
14//!
15//! 基于分层时间轮算法的高性能异步定时器库,支持 tokio 运行时
16//!
17//! ## 特性
18//!
19//! - **高性能**: 使用时间轮算法,插入和删除操作均为 O(1)
20//! - **大规模支持**: 高效管理 10000+ 并发定时器
21//! - **异步支持**: 基于 tokio 异步运行时
22//! - **线程安全**: 使用 parking_lot 提供高性能的锁机制
23//!
24//! ## Quick Start (快速开始)
25//!
26//! ```no_run
27//! use kestrel_timer::{TimerWheel, CallbackWrapper, TimerTask};
28//! use std::time::Duration;
29//! use std::sync::Arc;
30//!
31//! #[tokio::main]
32//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
33//!     // Create timer manager (创建定时器管理器)
34//!     let timer = TimerWheel::with_defaults();
35//!     
36//!     // Step 1: Allocate handle to get task_id (分配 handle 获取 task_id)
37//!     let handle = timer.allocate_handle();
38//!     let task_id = handle.task_id();
39//!     
40//!     // Step 2: Create timer task (创建定时器任务)
41//!     let callback = Some(CallbackWrapper::new(|| async {
42//!         println!("Timer fired after 1 second!");
43//!     }));
44//!     let task = TimerTask::new_oneshot(Duration::from_secs(1), callback);
45//!     
46//!     // Step 3: Register timer task and get completion notification (注册定时器任务并获取完成通知)
47//!     let timer_handle = timer.register(handle, task).unwrap();
48//!     
49//!     // Wait for timer completion (等待定时器完成)
50//!     use kestrel_timer::CompletionReceiver;
51//!     let (rx, _handle) = timer_handle.into_parts();
52//!     match rx {
53//!         CompletionReceiver::OneShot(receiver) => {
54//!             receiver.recv().await.unwrap();
55//!         },
56//!         _ => {}
57//!     }
58//!     Ok(())
59//! }
60//! ```
61//!
62//! ## English Architecture Description
63//!
64//! ### Timing Wheel Algorithm
65//!
66//! Uses hierarchical timing wheel algorithm with L0 and L1 layers:
67//!
68//! - **L0 Layer (Bottom)**: Handles short delay tasks
69//!   - Slot count: Default 512, configurable, must be power of 2
70//!   - Time precision: Default 10ms, configurable
71//!   - Maximum time span: 5.12 seconds
72//!
73//! - **L1 Layer (Upper)**: Handles long delay tasks
74//!   - Slot count: Default 64, configurable, must be power of 2
75//!   - Time precision: Default 1 second, configurable
76//!   - Maximum time span: 64 seconds
77//!
78//! - **Round Mechanism**: Tasks beyond L1 range use round counting
79//!
80//! ### Task Indexing with DeferredMap
81//!
82//! Uses `DeferredMap` (a generational arena) for efficient task management:
83//!
84//! - **Two-Step Registration**:
85//!   1. Allocate handle to get task ID (cheap, no value needed)
86//!   2. Insert task using the handle (with completion notifiers)
87//!
88//! - **Generational Safety**: Each task ID includes:
89//!   - Owning timing wheel identity: prevents cross-wheel operations
90//!   - Lower 32 bits: Slot index
91//!   - Upper 32 bits: Generation counter
92//!   - Prevents use-after-free and ABA problems
93//!
94//! - **Memory Efficiency**: Slots use union-based storage
95//!   - Occupied slots: Store task data
96//!   - Vacant slots: Store free-list pointer
97//!
98//! ### Performance Optimization
99//!
100//! - Uses `parking_lot::Mutex` instead of standard library Mutex for better performance
101//! - Uses `DeferredMap` (generational arena) for task indexing:
102//!   - O(1) task lookup, insertion, and removal
103//!   - Generational indices prevent use-after-free bugs
104//!   - Memory-efficient slot reuse with union-based storage
105//!   - Deferred insertion allows getting task ID before inserting task
106//! - Slot count is power of 2, uses bitwise operations to optimize modulo
107//! - Task execution in separate tokio tasks to avoid blocking timing wheel advancement
108//!
109//!
110//!
111//! ## 中文架构说明
112//!
113//! ### 时间轮算法
114//!
115//! 采用分层时间轮(Hierarchical Timing Wheel)算法,包含 L0 和 L1 两层:
116//!
117//! - **L0 层(底层)**: 处理短延迟任务
118//!   - 槽位数量: 默认 512 个(可配置,必须是 2 的幂次方)
119//!   - 时间精度: 默认 10ms(可配置)
120//!   - 最大时间跨度: 5.12 秒
121//!
122//! - **L1 层(高层)**: 处理长延迟任务
123//!   - 槽位数量: 默认 64 个(可配置,必须是 2 的幂次方)
124//!   - 时间精度: 默认 1 秒(可配置)
125//!   - 最大时间跨度: 64 秒
126//!
127//! - **轮次机制**: 超出 L1 层范围的任务使用轮次计数处理
128//!
129//! ### 基于 DeferredMap 的任务索引
130//!
131//! 使用 `DeferredMap`(代数竞技场)实现高效任务管理:
132//!
133//! - **两步注册流程**:
134//!   1. 分配 handle 获取任务 ID(轻量操作,无需准备任务值)
135//!   2. 使用 handle 插入任务(携带完成通知器)
136//!
137//! - **代数安全**: 每个任务 ID 包含:
138//!   - 所属时间轮身份:阻止跨时间轮操作
139//!   - 低 32 位:槽位索引
140//!   - 高 32 位:代数计数器
141//!   - 防止释放后使用和 ABA 问题
142//!
143//! - **内存高效**: 槽位使用联合体存储
144//!   - 已占用槽位:存储任务数据
145//!   - 空闲槽位:存储空闲链表指针
146//!
147//! ### 性能优化
148//!
149//! - 使用 `parking_lot::Mutex` 替代标准库的 Mutex,提供更好的性能
150//! - 使用 `DeferredMap`(代数竞技场)进行任务索引:
151//!   - O(1) 任务查找、插入和删除
152//!   - 代数索引防止释放后使用(use-after-free)错误
153//!   - 基于联合体的槽位存储,内存高效复用
154//!   - 延迟插入允许在插入任务前获取任务 ID
155//! - 槽位数量为 2 的幂次方,使用位运算优化取模操作
156//! - 任务执行在独立的 tokio 任务中,避免阻塞时间轮推进
157//!
158
159pub mod config;
160pub mod error;
161mod service;
162pub mod task;
163pub mod timer;
164pub mod wheel;
165
166#[doc(hidden)]
167pub mod readme_docs;
168
169#[cfg(test)]
170mod tests;
171
172// Re-export public API
173pub use error::TimerError;
174pub use lite_sync::spsc;
175pub use service::{TaskNotification, TimerService};
176pub use task::CompletionReceiver;
177pub use task::{CallbackWrapper, TaskCompletion, TaskId, TimerTask};
178pub use timer::TimerWheel;
179pub use timer::handle::{
180    BatchHandle, BatchHandleWithCompletion, TimerHandle, TimerHandleWithCompletion,
181};
182
183#[cfg(test)]
184mod integration_tests {
185    use super::*;
186    use std::sync::Arc;
187    use std::sync::atomic::{AtomicU32, Ordering};
188    use std::time::Duration;
189
190    #[tokio::test]
191    async fn test_basic_timer() {
192        let timer = TimerWheel::with_defaults();
193        let counter = Arc::new(AtomicU32::new(0));
194        let counter_clone = Arc::clone(&counter);
195
196        let handle = timer.allocate_handle();
197        let task = TimerTask::new_oneshot(
198            Duration::from_millis(50),
199            Some(CallbackWrapper::new(move || {
200                let counter = Arc::clone(&counter_clone);
201                async move {
202                    counter.fetch_add(1, Ordering::SeqCst);
203                }
204            })),
205        );
206        timer.register(handle, task).unwrap();
207
208        tokio::time::sleep(Duration::from_millis(100)).await;
209        assert_eq!(counter.load(Ordering::SeqCst), 1);
210    }
211
212    #[tokio::test]
213    async fn test_multiple_timers() {
214        let timer = TimerWheel::with_defaults();
215        let counter = Arc::new(AtomicU32::new(0));
216
217        // Create 10 timers
218        for i in 0..10 {
219            let counter_clone = Arc::clone(&counter);
220            let handle = timer.allocate_handle();
221            let task = TimerTask::new_oneshot(
222                Duration::from_millis(10 * (i + 1)),
223                Some(CallbackWrapper::new(move || {
224                    let counter = Arc::clone(&counter_clone);
225                    async move {
226                        counter.fetch_add(1, Ordering::SeqCst);
227                    }
228                })),
229            );
230            timer.register(handle, task).unwrap();
231        }
232
233        tokio::time::sleep(Duration::from_millis(200)).await;
234        assert_eq!(counter.load(Ordering::SeqCst), 10);
235    }
236
237    #[tokio::test]
238    async fn test_timer_cancellation() {
239        let timer = TimerWheel::with_defaults();
240        let counter = Arc::new(AtomicU32::new(0));
241
242        // Create 5 timers
243        let mut handles = Vec::new();
244        for _ in 0..5 {
245            let counter_clone = Arc::clone(&counter);
246            let alloc_handle = timer.allocate_handle();
247            let task = TimerTask::new_oneshot(
248                Duration::from_millis(100),
249                Some(CallbackWrapper::new(move || {
250                    let counter = Arc::clone(&counter_clone);
251                    async move {
252                        counter.fetch_add(1, Ordering::SeqCst);
253                    }
254                })),
255            );
256            let handle = timer.register(alloc_handle, task).unwrap();
257            handles.push(handle);
258        }
259
260        // Cancel first 3 timers
261        for handle in handles.iter().take(3) {
262            let cancel_result = handle.cancel().unwrap();
263            assert!(cancel_result);
264        }
265
266        tokio::time::sleep(Duration::from_millis(200)).await;
267        // Only 2 timers should be triggered
268        assert_eq!(counter.load(Ordering::SeqCst), 2);
269    }
270
271    #[tokio::test]
272    async fn test_completion_notification_once() {
273        let timer = TimerWheel::with_defaults();
274        let counter = Arc::new(AtomicU32::new(0));
275        let counter_clone = Arc::clone(&counter);
276
277        let alloc_handle = timer.allocate_handle();
278        let task = TimerTask::new_oneshot(
279            Duration::from_millis(50),
280            Some(CallbackWrapper::new(move || {
281                let counter = Arc::clone(&counter_clone);
282                async move {
283                    counter.fetch_add(1, Ordering::SeqCst);
284                }
285            })),
286        );
287        let handle = timer.register(alloc_handle, task).unwrap();
288
289        // Wait for completion notification
290        let (rx, _handle) = handle.into_parts();
291        match rx {
292            task::CompletionReceiver::OneShot(receiver) => {
293                receiver.recv().await.unwrap();
294            }
295            _ => panic!("Expected OneShot completion receiver"),
296        }
297
298        // Verify callback has been executed (wait a moment to ensure callback execution is complete)
299        tokio::time::sleep(Duration::from_millis(20)).await;
300        assert_eq!(counter.load(Ordering::SeqCst), 1);
301    }
302
303    #[tokio::test]
304    async fn test_notify_only_timer_once() {
305        let timer = TimerWheel::with_defaults();
306
307        let alloc_handle = timer.allocate_handle();
308        let task = TimerTask::new_oneshot(Duration::from_millis(50), None);
309        let handle = timer.register(alloc_handle, task).unwrap();
310
311        // Wait for completion notification (no callback, only notification)
312        let (rx, _handle) = handle.into_parts();
313        match rx {
314            task::CompletionReceiver::OneShot(receiver) => {
315                receiver.recv().await.unwrap();
316            }
317            _ => panic!("Expected OneShot completion receiver"),
318        }
319    }
320
321    #[tokio::test]
322    async fn test_batch_completion_notifications() {
323        let timer = TimerWheel::with_defaults();
324        let counter = Arc::new(AtomicU32::new(0));
325
326        // Step 1: Allocate handles
327        let handles = timer.allocate_handles(5);
328
329        // Step 2: Create batch callbacks
330        let tasks: Vec<_> = (0..5)
331            .map(|i| {
332                let counter = Arc::clone(&counter);
333                let delay = Duration::from_millis(50 + i as u64 * 10);
334                let callback = CallbackWrapper::new(move || {
335                    let counter = Arc::clone(&counter);
336                    async move {
337                        counter.fetch_add(1, Ordering::SeqCst);
338                    }
339                });
340                TimerTask::new_oneshot(delay, Some(callback))
341            })
342            .collect();
343
344        // Step 3: Batch register
345        let batch = timer
346            .register_batch(handles, tasks)
347            .expect("register_batch should succeed");
348        let (receivers, _batch_handle) = batch.into_parts();
349
350        // Wait for all completion notifications
351        for rx in receivers {
352            match rx {
353                task::CompletionReceiver::OneShot(receiver) => {
354                    receiver.recv().await.unwrap();
355                }
356                _ => panic!("Expected OneShot completion receiver"),
357            }
358        }
359
360        // Wait a moment to ensure callback execution is complete
361        tokio::time::sleep(Duration::from_millis(50)).await;
362
363        // Verify all callbacks have been executed
364        assert_eq!(counter.load(Ordering::SeqCst), 5);
365    }
366
367    #[tokio::test]
368    async fn test_completion_reason_expired() {
369        let timer = TimerWheel::with_defaults();
370
371        let alloc_handle = timer.allocate_handle();
372        let task = TimerTask::new_oneshot(Duration::from_millis(50), None);
373        let handle = timer.register(alloc_handle, task).unwrap();
374
375        // Wait for completion notification and verify reason is Expired
376        let (rx, _handle) = handle.into_parts();
377        let result = match rx {
378            task::CompletionReceiver::OneShot(receiver) => receiver.recv().await.unwrap(),
379            _ => panic!("Expected OneShot completion receiver"),
380        };
381        assert_eq!(result, TaskCompletion::Called);
382    }
383
384    #[tokio::test]
385    async fn test_completion_reason_cancelled() {
386        let timer = TimerWheel::with_defaults();
387
388        let alloc_handle = timer.allocate_handle();
389        let task = TimerTask::new_oneshot(Duration::from_secs(10), None);
390        let handle = timer.register(alloc_handle, task).unwrap();
391
392        // Cancel task
393        let cancelled = handle.cancel().unwrap();
394        assert!(cancelled);
395
396        // Wait for completion notification and verify reason is Cancelled
397        let (rx, _handle) = handle.into_parts();
398        let result = match rx {
399            task::CompletionReceiver::OneShot(receiver) => receiver.recv().await.unwrap(),
400            _ => panic!("Expected OneShot completion receiver"),
401        };
402        assert_eq!(result, TaskCompletion::Cancelled);
403    }
404
405    #[tokio::test]
406    async fn test_batch_completion_reasons() {
407        let timer = TimerWheel::with_defaults();
408
409        // Step 1: Allocate handles
410        let handles = timer.allocate_handles(5);
411
412        // Step 2: Create 5 tasks with 10 seconds delay
413        let tasks: Vec<_> = (0..5)
414            .map(|_| TimerTask::new_oneshot(Duration::from_secs(10), None))
415            .collect();
416
417        // Step 3: Batch register
418        let batch = timer
419            .register_batch(handles, tasks)
420            .expect("register_batch should succeed");
421        let task_ids: Vec<_> = batch.task_ids().to_vec();
422        let (mut receivers, _batch_handle) = batch.into_parts();
423
424        // Cancel first 3 tasks
425        timer.cancel_batch(&task_ids[0..3]).unwrap();
426
427        // Verify first 3 tasks received Cancelled notification
428        for rx in receivers.drain(0..3) {
429            let result = match rx {
430                task::CompletionReceiver::OneShot(receiver) => receiver.recv().await.unwrap(),
431                _ => panic!("Expected OneShot completion receiver"),
432            };
433            assert_eq!(result, TaskCompletion::Cancelled);
434        }
435
436        // Cancel remaining tasks and verify
437        timer.cancel_batch(&task_ids[3..5]).unwrap();
438        for rx in receivers {
439            let result = match rx {
440                task::CompletionReceiver::OneShot(receiver) => receiver.recv().await.unwrap(),
441                _ => panic!("Expected OneShot completion receiver"),
442            };
443            assert_eq!(result, TaskCompletion::Cancelled);
444        }
445    }
446
447    #[tokio::test]
448    async fn test_task_ids_and_handles_are_bound_to_their_wheel() {
449        let source = TimerWheel::with_defaults();
450        let target = TimerWheel::with_defaults();
451
452        let foreign_handle = source.allocate_handle();
453        let foreign_id = foreign_handle.task_id();
454        let registration = target.register(
455            foreign_handle,
456            TimerTask::new_oneshot(Duration::from_secs(10), None),
457        );
458        assert!(matches!(registration, Err(TimerError::WrongWheel)));
459
460        let target_handle = target.allocate_handle();
461        let target_id = target_handle.task_id();
462        let target_timer = target
463            .register(
464                target_handle,
465                TimerTask::new_oneshot(Duration::from_secs(10), None),
466            )
467            .unwrap();
468
469        assert_eq!(foreign_id.raw(), target_id.raw());
470        assert_ne!(foreign_id, target_id);
471        assert!(matches!(
472            target.cancel(foreign_id),
473            Err(TimerError::WrongWheel)
474        ));
475        assert!(matches!(
476            target.postpone(foreign_id, Duration::from_secs(1), None),
477            Err(TimerError::WrongWheel)
478        ));
479        assert!(target.cancel(target_id).unwrap());
480        drop(target_timer);
481
482        // Dropping the rejected handle must not poison future allocations in
483        // its original wheel.
484        let _next_handle = source.allocate_handle();
485    }
486
487    #[tokio::test]
488    async fn test_batch_operations_reject_foreign_task_ids_atomically() {
489        let source = TimerWheel::with_defaults();
490        let target = TimerWheel::with_defaults();
491
492        let source_handle = source.allocate_handle();
493        let source_id = source_handle.task_id();
494        source
495            .register(
496                source_handle,
497                TimerTask::new_oneshot(Duration::from_secs(10), None),
498            )
499            .unwrap();
500
501        let target_handle = target.allocate_handle();
502        let target_id = target_handle.task_id();
503        let target_timer = target
504            .register(
505                target_handle,
506                TimerTask::new_oneshot(Duration::from_secs(10), None),
507            )
508            .unwrap();
509
510        assert!(matches!(
511            target.cancel_batch(&[target_id, source_id]),
512            Err(TimerError::WrongWheel)
513        ));
514        assert!(matches!(
515            target.postpone_batch(vec![
516                (target_id, Duration::from_secs(1)),
517                (source_id, Duration::from_secs(1)),
518            ]),
519            Err(TimerError::WrongWheel)
520        ));
521        assert!(target.cancel(target_id).unwrap());
522        drop(target_timer);
523        assert!(source.cancel(source_id).unwrap());
524    }
525}