Skip to main content

kestrel_timer/
wheel.rs

1use crate::CallbackWrapper;
2use crate::config::{BatchConfig, WheelConfig};
3use crate::error::TimerError;
4use crate::task::{
5    TaskCompletion, TaskHandle, TaskId, TaskLocation, TaskTypeWithCompletionNotifier,
6    TimerTaskForWheel, TimerTaskWithCompletionNotifier, WheelOwner,
7};
8use deferred_map::DeferredMap;
9use std::time::Duration;
10use tokio::time::Instant;
11
12pub struct WheelAdvanceResult {
13    pub id: TaskId,
14    pub callback: Option<CallbackWrapper>,
15}
16
17/// Timing wheel single layer data structure
18///
19/// 时间轮单层数据结构
20struct WheelLayer {
21    /// Slot array, each slot stores a group of timer tasks
22    ///
23    /// 槽数组,每个槽存储一组定时器任务
24    slots: Vec<Vec<TimerTaskForWheel>>,
25
26    /// Current time pointer (tick index)
27    ///
28    /// 当前时间指针(tick 索引)
29    current_tick: u64,
30
31    /// Slot count
32    ///
33    /// 槽数量
34    slot_count: usize,
35
36    /// Duration of each tick
37    ///
38    /// 每个 tick 的持续时间
39    tick_duration: Duration,
40
41    /// Cache: tick duration in nanoseconds - avoid lossy conversions
42    ///
43    /// 缓存:tick 持续时间(纳秒)- 避免有损转换
44    tick_duration_nanos: u128,
45
46    /// Cache: slot mask (slot_count - 1) - for fast modulo operation
47    ///
48    /// 缓存:槽掩码(slot_count - 1)- 用于快速取模运算
49    slot_mask: usize,
50}
51
52impl WheelLayer {
53    /// Create a new wheel layer
54    ///
55    /// 创建一个新的时间轮层
56    fn new(slot_count: usize, tick_duration: Duration) -> Self {
57        let mut slots = Vec::with_capacity(slot_count);
58        // Pre-allocate capacity for each slot to reduce subsequent reallocation during push
59        // Most slots typically contain 0-4 tasks, pre-allocate capacity of 4
60        //
61        // 为每个槽预分配容量以减少后续 push 时的重新分配
62        // 大多数槽通常包含 0-4 个任务,预分配容量为 4
63        for _ in 0..slot_count {
64            slots.push(Vec::with_capacity(4));
65        }
66
67        let tick_duration_nanos = tick_duration.as_nanos();
68        let slot_mask = slot_count - 1;
69
70        Self {
71            slots,
72            current_tick: 0,
73            slot_count,
74            tick_duration,
75            tick_duration_nanos,
76            slot_mask,
77        }
78    }
79
80    /// Calculate the number of ticks corresponding to the delay
81    ///
82    /// 计算延迟对应的 tick 数量
83    fn delay_to_ticks(&self, delay: Duration) -> u64 {
84        let ticks = delay.as_nanos().div_ceil(self.tick_duration_nanos);
85        u64::try_from(ticks).unwrap_or(u64::MAX).max(1) // at least 1 tick (至少 1 个 tick)
86    }
87}
88
89/// Timing wheel data structure (hierarchical mode)
90///
91/// Now uses DeferredMap for O(1) task lookup and generational safety.
92///
93/// 时间轮数据结构(分层模式)
94///
95/// 现在使用 DeferredMap 实现 O(1) 任务查找和代数安全
96pub struct Wheel {
97    /// Identity shared by all handles and IDs allocated by this wheel
98    ///
99    /// 此时间轮分配的所有 handle 和 ID 共享的身份
100    owner: std::sync::Arc<WheelOwner>,
101
102    /// L0 layer (bottom layer)
103    ///
104    /// L0 层(底层)
105    l0: WheelLayer,
106
107    /// L1 layer (top layer)
108    ///
109    /// L1 层(顶层)
110    l1: WheelLayer,
111
112    /// L1 tick ratio relative to L0 tick
113    ///
114    /// L1 tick 相对于 L0 tick 的比率
115    pub(crate) l1_tick_ratio: u64,
116
117    /// Task index for fast lookup and cancellation using DeferredMap
118    ///
119    /// Keys are TaskIds (u64 from DeferredMap), values are TaskLocations
120    ///
121    /// 任务索引,使用 DeferredMap 实现快速查找和取消
122    ///
123    /// 键是 TaskId(来自 DeferredMap 的 u64),值是 TaskLocation
124    pub(crate) task_index: DeferredMap<TaskLocation>,
125
126    /// Batch processing configuration
127    ///
128    /// 批处理配置
129    batch_config: BatchConfig,
130
131    /// Cache: L0 layer capacity in ticks - avoid repeated calculation
132    ///
133    /// 缓存:L0 层容量(tick)- 避免重复计算
134    l0_capacity_ticks: u64,
135
136    /// Cache: L1 layer capacity in ticks - avoid repeated calculation
137    ///
138    /// 缓存:L1 层容量(tick 数)- 避免重复计算
139    l1_capacity_ticks: u64,
140
141    /// Tokio clock time associated with the wheel's origin.
142    ///
143    /// 与时间轮起点对应的 Tokio 时钟时间。
144    clock_origin: Instant,
145
146    /// Tokio clock time associated with the most recently processed tick.
147    ///
148    /// 与最近一次处理的 tick 对应的 Tokio 时钟时间。
149    clock_at: Instant,
150}
151
152impl Wheel {
153    /// Create new timing wheel
154    ///
155    /// # Parameters
156    /// - `config`: Timing wheel configuration
157    /// - `batch_config`: Batch processing configuration
158    ///
159    /// # Notes
160    /// Configuration is validated again at this public construction boundary.
161    /// Now uses DeferredMap for task indexing with generational safety.
162    ///
163    /// 创建新的时间轮
164    ///
165    /// # 参数
166    /// - `config`: 时间轮配置
167    /// - `batch_config`: 批处理配置
168    ///
169    /// # 注意
170    /// 此公开构造边界会再次验证配置。
171    /// 现在使用 DeferredMap 进行任务索引,具有代数安全特性。
172    pub fn new(config: WheelConfig, batch_config: BatchConfig) -> Result<Self, TimerError> {
173        let config = config.validate()?;
174        let owner = WheelOwner::new();
175        let l0 = WheelLayer::new(config.l0_slot_count(), config.l0_tick_duration());
176        let l1 = WheelLayer::new(config.l1_slot_count(), config.l1_tick_duration());
177        let now = Instant::now();
178
179        // Calculate L1 tick ratio relative to L0 tick
180        // 计算 L1 tick 相对于 L0 tick 的比率
181        let l1_tick_ratio = u64::try_from(l1.tick_duration_nanos / l0.tick_duration_nanos)
182            .map_err(|_| TimerError::InvalidConfiguration {
183                field: "l1_tick_duration".to_string(),
184                reason: "L1/L0 tick ratio must fit in u64".to_string(),
185            })?;
186
187        // Pre-calculate capacity to avoid repeated calculation in insert
188        // 预计算容量,避免在 insert 中重复计算
189        let l0_capacity_ticks = l0.slot_count as u64;
190        let l1_capacity_ticks = l1.slot_count as u64;
191
192        // Estimate initial capacity for DeferredMap based on L0 slot count
193        // 根据 L0 槽数量估算 DeferredMap 的初始容量
194        let estimated_capacity = (l0.slot_count / 4).max(64);
195
196        Ok(Self {
197            owner,
198            l0,
199            l1,
200            l1_tick_ratio,
201            task_index: DeferredMap::with_capacity(estimated_capacity),
202            batch_config,
203            l0_capacity_ticks,
204            l1_capacity_ticks,
205            clock_origin: now,
206            clock_at: now,
207        })
208    }
209
210    /// Get current tick (L0 layer tick)
211    ///
212    /// 获取当前 tick(L0 层 tick)
213    #[allow(dead_code)]
214    pub fn current_tick(&self) -> u64 {
215        self.l0.current_tick
216    }
217
218    /// Get tick duration (L0 layer tick duration)
219    ///
220    /// 获取 tick 持续时间(L0 层 tick 持续时间)
221    #[allow(dead_code)]
222    pub fn tick_duration(&self) -> Duration {
223        self.l0.tick_duration
224    }
225
226    /// Get slot count (L0 layer slot count)
227    ///
228    /// 获取槽数量(L0 层槽数量)
229    #[allow(dead_code)]
230    pub fn slot_count(&self) -> usize {
231        self.l0.slot_count
232    }
233
234    /// Calculate the number of ticks corresponding to the delay (based on L0 layer)
235    ///
236    /// 计算延迟对应的 tick 数量(基于 L0 层)
237    #[allow(dead_code)]
238    pub fn delay_to_ticks(&self, delay: Duration) -> u64 {
239        self.l0.delay_to_ticks(delay)
240    }
241
242    /// Determine which layer the delay should be inserted into
243    ///
244    /// # Returns
245    /// Returns: (layer, ticks, rounds)
246    /// - Layer: 0 = L0, 1 = L1
247    /// - Ticks: number of ticks calculated from current tick
248    /// - Rounds: number of rounds (only used for very long delays in L1 layer)
249    ///
250    /// 确定延迟应该插入到哪一层
251    ///
252    /// # 返回值
253    /// 返回:(层级, ticks, 轮数)
254    /// - 层级:0 = L0, 1 = L1
255    /// - Ticks:从当前 tick 计算的 tick 数量
256    /// - 轮数:轮数(仅用于 L1 层的超长延迟)
257    #[inline(always)]
258    fn determine_layer(&self, delay: Duration) -> (u8, u64, u32) {
259        let l0_ticks = self.l0.delay_to_ticks(delay);
260
261        // Fast path: most tasks are within L0 range (using cached capacity)
262        // 快速路径:大多数任务在 L0 范围内(使用缓存的容量)
263        if l0_ticks <= self.l0_capacity_ticks {
264            return (0, l0_ticks, 0);
265        }
266
267        // Slow path: L1 layer tasks (using cached values)
268        // 慢速路径:L1 层任务(使用缓存的值)
269        let l1_ticks = self.l1.delay_to_ticks(delay);
270        let rounds = ((l1_ticks - 1) / self.l1_capacity_ticks).min(u32::MAX as u64) as u32;
271        (1, l1_ticks, rounds)
272    }
273
274    /// Allocate a handle from DeferredMap
275    ///
276    /// 从 DeferredMap 分配一个 handle
277    ///
278    /// # Returns
279    /// A unique handle for later insertion
280    ///
281    /// # 返回值
282    /// 用于后续插入的唯一 handle
283    pub fn allocate_handle(&mut self) -> TaskHandle {
284        self.reclaim_dropped_handles();
285        TaskHandle::new(self.owner.clone(), self.task_index.allocate_handle())
286    }
287
288    /// Batch allocate handles from DeferredMap
289    ///
290    /// 从 DeferredMap 批量分配 handles
291    ///
292    /// # Parameters
293    /// - `count`: Number of handles to allocate
294    ///
295    /// # Returns
296    /// Vector of unique handles for later batch insertion
297    ///
298    /// # 参数
299    /// - `count`: 要分配的 handle 数量
300    ///
301    /// # 返回值
302    /// 用于后续批量插入的唯一 handles 向量
303    pub fn allocate_handles(&mut self, count: usize) -> Vec<TaskHandle> {
304        self.reclaim_dropped_handles();
305        let mut handles = Vec::with_capacity(count);
306        for _ in 0..count {
307            handles.push(TaskHandle::new(
308                self.owner.clone(),
309                self.task_index.allocate_handle(),
310            ));
311        }
312        handles
313    }
314
315    fn reclaim_dropped_handles(&mut self) {
316        for handle in self.owner.take_released_handles() {
317            self.task_index.release_handle(handle);
318        }
319    }
320
321    fn validate_periodic_interval(&self, interval: Duration) -> Result<(), TimerError> {
322        if interval.is_zero() {
323            return Err(TimerError::InvalidConfiguration {
324                field: "interval".to_string(),
325                reason: "periodic interval must be greater than zero".to_string(),
326            });
327        }
328
329        if interval < self.l0.tick_duration {
330            return Err(TimerError::InvalidConfiguration {
331                field: "interval".to_string(),
332                reason: format!(
333                    "periodic interval ({interval:?}) must be at least the L0 tick duration ({:?})",
334                    self.l0.tick_duration
335                ),
336            });
337        }
338
339        Ok(())
340    }
341
342    /// Insert timer task
343    ///
344    /// # Parameters
345    /// - `handle`: Handle for the task
346    /// - `task`: Timer task with completion notifier
347    ///
348    /// # Returns
349    /// `Ok(())` when inserted, or `Err(TimerError::WrongWheel)` when the handle
350    /// belongs to another timing wheel.
351    ///
352    /// # Implementation Details
353    /// - Allocates Handle from DeferredMap to generate TaskId with generational safety
354    /// - Automatically calculate the layer and slot where the task should be inserted
355    /// - Hierarchical mode: short delay tasks are inserted into L0, long delay tasks are inserted into L1
356    /// - Use bit operations to optimize slot index calculation
357    /// - Use DeferredMap for O(1) lookup and cancellation with generation checking
358    ///
359    /// 插入定时器任务
360    ///
361    /// # 参数
362    /// - `handle`: 任务的 handle
363    /// - `task`: 带完成通知器的定时器任务
364    ///
365    /// # 返回值
366    /// 插入成功返回 `Ok(())`;handle 属于其他时间轮时返回
367    /// `Err(TimerError::WrongWheel)`。
368    ///
369    /// # 实现细节
370    /// - 自动计算任务应该插入的层级和槽位
371    /// - 分层模式:短延迟任务插入 L0,长延迟任务插入 L1
372    /// - 使用位运算优化槽索引计算
373    /// - 使用 DeferredMap 实现 O(1) 查找和取消,带代数检查
374    #[inline]
375    pub fn insert(
376        &mut self,
377        handle: TaskHandle,
378        task: TimerTaskWithCompletionNotifier,
379    ) -> Result<(), TimerError> {
380        self.insert_one(handle, task, None)
381    }
382
383    /// Insert a task using the current monotonic time.
384    ///
385    /// 使用当前单调时钟时间插入任务。
386    #[inline]
387    pub(crate) fn insert_at(
388        &mut self,
389        handle: TaskHandle,
390        task: TimerTaskWithCompletionNotifier,
391    ) -> Result<(), TimerError> {
392        self.insert_one(handle, task, Some(Instant::now()))
393    }
394
395    fn insert_one(
396        &mut self,
397        handle: TaskHandle,
398        task: TimerTaskWithCompletionNotifier,
399        now: Option<Instant>,
400    ) -> Result<(), TimerError> {
401        if self.owner.is_closed() {
402            return Err(TimerError::Shutdown);
403        }
404
405        if !handle.belongs_to(self.owner.id()) {
406            return Err(TimerError::WrongWheel);
407        }
408
409        if let Some(interval) = task.get_interval() {
410            self.validate_periodic_interval(interval)?;
411        }
412
413        let task_id = handle.task_id();
414        let request_time = now.unwrap_or(self.clock_at);
415
416        let (level, ticks, rounds) = self.determine_layer(task.delay);
417        let deadline_at = request_time + task.delay;
418
419        // Use match to reduce branches, and use cached slot mask
420        // 使用 match 减少分支,并使用缓存的槽掩码
421        let (current_tick, slot_mask, slots) = match level {
422            0 => (self.l0.current_tick, self.l0.slot_mask, &mut self.l0.slots),
423            _ => (self.l1.current_tick, self.l1.slot_mask, &mut self.l1.slots),
424        };
425
426        let total_ticks = current_tick.saturating_add(ticks);
427        let slot_index = (total_ticks as usize) & slot_mask;
428
429        // Create task with the assigned TaskId
430        // 使用分配的 TaskId 创建任务
431        let task = TimerTaskForWheel::new_with_id(task_id, task, total_ticks, rounds, deadline_at);
432
433        // Get the index position of the task in Vec (the length before insertion is the index of the new task)
434        // 获取任务在 Vec 中的索引位置(插入前的长度就是新任务的索引)
435        let vec_index = slots[slot_index].len();
436        let location = TaskLocation::new(level, slot_index, vec_index);
437
438        // Insert task into slot
439        // 将任务插入槽中
440        slots[slot_index].push(task);
441
442        // Insert task location into DeferredMap using handle
443        // 使用 handle 将任务位置插入 DeferredMap
444        self.task_index.insert(handle.into_handle(), location);
445
446        Ok(())
447    }
448
449    /// Batch insert timer tasks
450    ///
451    /// # Parameters
452    /// - `handles`: List of pre-allocated handles for tasks
453    /// - `tasks`: List of timer tasks with completion notifiers
454    ///
455    /// # Returns
456    /// - `Ok(())` if all tasks are successfully inserted
457    /// - `Err(TimerError::BatchLengthMismatch)` if handles and tasks lengths don't match
458    /// - `Err(TimerError::WrongWheel)` if any handle belongs to another wheel
459    ///
460    /// # Performance Advantages
461    /// - Reduce repeated boundary checks and capacity adjustments
462    /// - For tasks with the same delay, calculation results can be reused
463    /// - Uses DeferredMap for efficient task indexing with generational safety
464    ///
465    /// 批量插入定时器任务
466    ///
467    /// # 参数
468    /// - `handles`: 任务的预分配 handles 列表
469    /// - `tasks`: 带完成通知器的定时器任务列表
470    ///
471    /// # 返回值
472    /// - `Ok(())` 如果所有任务成功插入
473    /// - `Err(TimerError::BatchLengthMismatch)` 如果 handles 和 tasks 长度不匹配
474    /// - `Err(TimerError::WrongWheel)` 如果任一 handle 属于其他时间轮
475    ///
476    /// # 性能优势
477    /// - 减少重复的边界检查和容量调整
478    /// - 对于相同延迟的任务,可以重用计算结果
479    /// - 使用 DeferredMap 实现高效的任务索引,具有代数安全特性
480    #[inline]
481    pub fn insert_batch(
482        &mut self,
483        handles: Vec<TaskHandle>,
484        tasks: Vec<TimerTaskWithCompletionNotifier>,
485    ) -> Result<(), TimerError> {
486        self.insert_batch_with_time(handles, tasks, None)
487    }
488
489    /// Batch insert tasks using the current monotonic time.
490    ///
491    /// 使用当前单调时钟时间批量插入任务。
492    #[inline]
493    pub(crate) fn insert_batch_at(
494        &mut self,
495        handles: Vec<TaskHandle>,
496        tasks: Vec<TimerTaskWithCompletionNotifier>,
497    ) -> Result<(), TimerError> {
498        self.insert_batch_with_time(handles, tasks, Some(Instant::now()))
499    }
500
501    fn insert_batch_with_time(
502        &mut self,
503        handles: Vec<TaskHandle>,
504        tasks: Vec<TimerTaskWithCompletionNotifier>,
505        now: Option<Instant>,
506    ) -> Result<(), TimerError> {
507        // Validate that handles and tasks have the same length
508        // 验证 handles 和 tasks 长度相同
509        if handles.len() != tasks.len() {
510            return Err(TimerError::BatchLengthMismatch {
511                handles_len: handles.len(),
512                tasks_len: tasks.len(),
513            });
514        }
515
516        if self.owner.is_closed() {
517            return Err(TimerError::Shutdown);
518        }
519
520        if handles
521            .iter()
522            .any(|handle| !handle.belongs_to(self.owner.id()))
523        {
524            return Err(TimerError::WrongWheel);
525        }
526
527        for task in &tasks {
528            if let Some(interval) = task.get_interval() {
529                self.validate_periodic_interval(interval)?;
530            }
531        }
532
533        for (handle, task) in handles.into_iter().zip(tasks) {
534            self.insert_one(handle, task, now)?;
535        }
536
537        Ok(())
538    }
539
540    /// Cancel timer task
541    ///
542    /// # Parameters
543    /// - `task_id`: Task ID
544    ///
545    /// # Returns
546    /// `Ok(true)` when cancelled, `Ok(false)` when the task is absent, or
547    /// `Err(TimerError::WrongWheel)` for an ID from another timing wheel.
548    ///
549    /// Now uses DeferredMap for safe task removal with generational checking
550    ///
551    /// 取消定时器任务
552    ///
553    /// # 参数
554    /// - `task_id`: 任务 ID
555    ///
556    /// # 返回值
557    /// 任务存在且取消成功时返回 `Ok(true)`,任务不存在时返回 `Ok(false)`,
558    /// ID 属于其他时间轮时返回 `Err(TimerError::WrongWheel)`。
559    ///
560    /// 现在使用 DeferredMap 实现安全的任务移除,带代数检查
561    #[inline]
562    pub fn cancel(&mut self, task_id: TaskId) -> Result<bool, TimerError> {
563        if !task_id.belongs_to(self.owner.id()) {
564            return Err(TimerError::WrongWheel);
565        }
566
567        // Remove task location from DeferredMap using TaskId as key
568        // 使用 TaskId 作为 key 从 DeferredMap 中移除任务位置
569        let location = match self.task_index.remove(task_id.key()) {
570            Some(loc) => loc,
571            None => return Ok(false), // Task not found or already removed (generation mismatch)
572        };
573
574        // Use match to get slot reference, reduce branches
575        // 使用 match 获取槽引用,减少分支
576        let slot = match location.level {
577            0 => &mut self.l0.slots[location.slot_index],
578            _ => &mut self.l1.slots[location.slot_index],
579        };
580
581        // Boundary check and ID verification
582        // 边界检查和 ID 验证
583        if location.vec_index >= slot.len() || slot[location.vec_index].get_id() != task_id {
584            // Index inconsistent - this shouldn't happen with DeferredMap, but handle it anyway
585            // 索引不一致 - DeferredMap 不应该出现这种情况,但还是处理一下
586            return Ok(false);
587        }
588
589        // Use swap_remove to remove task, record swapped task ID
590        // 使用 swap_remove 移除任务,记录被交换的任务 ID
591        let removed_task = slot.swap_remove(location.vec_index);
592
593        // Ensure the correct task was removed
594        // 确保移除了正确的任务
595        debug_assert_eq!(removed_task.get_id(), task_id);
596
597        match removed_task.into_task_type() {
598            TaskTypeWithCompletionNotifier::OneShot {
599                completion_notifier,
600            } => {
601                // Use Notify + AtomicU8 for zero-allocation notification
602                // 使用 Notify + AtomicU8 实现零分配通知
603                let _ = completion_notifier.send(crate::task::TaskCompletion::Cancelled);
604            }
605            TaskTypeWithCompletionNotifier::Periodic {
606                completion_notifier,
607                ..
608            } => {
609                // Apply the configured bounded or unbounded completion policy.
610                // 按配置应用有界或无界完成通知策略。
611                let _ = completion_notifier.send(TaskCompletion::Cancelled);
612            }
613        }
614
615        // If a swap occurred (vec_index is not the last element)
616        // 如果发生了交换(vec_index 不是最后一个元素)
617        if location.vec_index < slot.len() {
618            let swapped_task_id = slot[location.vec_index].get_id();
619            // Update swapped element's index in one go, using DeferredMap's get_mut
620            // 一次性更新被交换元素的索引,使用 DeferredMap 的 get_mut
621            if let Some(swapped_location) = self.task_index.get_mut(swapped_task_id.key()) {
622                swapped_location.vec_index = location.vec_index;
623            }
624        }
625
626        Ok(true)
627    }
628
629    /// Batch cancel timer tasks
630    ///
631    /// # Parameters
632    /// - `task_ids`: List of task IDs to cancel
633    ///
634    /// # Returns
635    /// Number of successfully cancelled tasks, or `Err(TimerError::WrongWheel)`
636    /// if any ID belongs to another timing wheel.
637    ///
638    /// # Performance Advantages
639    /// - Reduce repeated HashMap lookup overhead
640    /// - Multiple cancellation operations on the same slot can be batch processed
641    /// - Use unstable sort to improve performance
642    /// - Small batch optimization: skip sorting based on configuration threshold, process directly
643    ///
644    /// 批量取消定时器任务
645    ///
646    /// # 参数
647    /// - `task_ids`: 要取消的任务 ID 列表
648    ///
649    /// # 返回值
650    /// 成功取消的任务数量;如果任一 ID 属于其他时间轮则返回
651    /// `Err(TimerError::WrongWheel)`,且不修改任何任务。
652    ///
653    /// # 性能优势
654    /// - 减少重复的 HashMap 查找开销
655    /// - 同一槽位的多个取消操作可以批量处理
656    /// - 使用不稳定排序提高性能
657    /// - 小批量优化:根据配置阈值跳过排序,直接处理
658    #[inline]
659    pub fn cancel_batch(&mut self, task_ids: &[TaskId]) -> Result<usize, TimerError> {
660        if task_ids
661            .iter()
662            .any(|task_id| !task_id.belongs_to(self.owner.id()))
663        {
664            return Err(TimerError::WrongWheel);
665        }
666
667        let mut cancelled_count = 0;
668
669        // Small batch optimization: cancel one by one to avoid grouping and sorting overhead
670        // 小批量优化:逐个取消以避免分组和排序开销
671        if task_ids.len() <= self.batch_config.small_batch_threshold {
672            for task_id in task_ids.iter().copied() {
673                if self.cancel(task_id)? {
674                    cancelled_count += 1;
675                }
676            }
677            return Ok(cancelled_count);
678        }
679
680        // Group by layer and slot to optimize batch cancellation
681        // Use SmallVec to avoid heap allocation in most cases
682        // 按层级和槽位分组以优化批量取消
683        // 使用 SmallVec 避免在大多数情况下进行堆分配
684        let l0_slot_count = self.l0.slot_count;
685        let l1_slot_count = self.l1.slot_count;
686
687        let mut l0_tasks_by_slot: Vec<Vec<(TaskId, usize)>> = vec![Vec::new(); l0_slot_count];
688        let mut l1_tasks_by_slot: Vec<Vec<(TaskId, usize)>> = vec![Vec::new(); l1_slot_count];
689
690        // Collect information of tasks to be cancelled
691        // 收集要取消的任务信息
692        for task_id in task_ids.iter().copied() {
693            // Use DeferredMap's get with TaskId key
694            // 使用 DeferredMap 的 get,传入 TaskId key
695            if let Some(location) = self.task_index.get(task_id.key()) {
696                if location.level == 0 {
697                    l0_tasks_by_slot[location.slot_index].push((task_id, location.vec_index));
698                } else {
699                    l1_tasks_by_slot[location.slot_index].push((task_id, location.vec_index));
700                }
701            }
702        }
703
704        // Process L0 layer cancellation
705        // 处理 L0 层取消
706        for (slot_index, tasks) in l0_tasks_by_slot.iter_mut().enumerate() {
707            if tasks.is_empty() {
708                continue;
709            }
710
711            // Sort by vec_index in descending order, delete from back to front to avoid index invalidation
712            // 按 vec_index 降序排序,从后向前删除以避免索引失效
713            tasks.sort_unstable_by_key(|b| std::cmp::Reverse(b.1));
714
715            let slot = &mut self.l0.slots[slot_index];
716
717            for &(task_id, vec_index) in tasks.iter() {
718                if vec_index < slot.len() && slot[vec_index].get_id() == task_id {
719                    let removed_task = slot.swap_remove(vec_index);
720                    match removed_task.into_task_type() {
721                        TaskTypeWithCompletionNotifier::OneShot {
722                            completion_notifier,
723                        } => {
724                            // Use Notify + AtomicU8 for zero-allocation notification
725                            // 使用 Notify + AtomicU8 实现零分配通知
726                            let _ =
727                                completion_notifier.send(crate::task::TaskCompletion::Cancelled);
728                        }
729                        TaskTypeWithCompletionNotifier::Periodic {
730                            completion_notifier,
731                            ..
732                        } => {
733                            // Apply the configured bounded or unbounded completion policy.
734                            // 按配置应用有界或无界完成通知策略。
735                            let _ = completion_notifier.send(TaskCompletion::Cancelled);
736                        }
737                    }
738
739                    if vec_index < slot.len() {
740                        let swapped_task_id = slot[vec_index].get_id();
741                        // Use DeferredMap's get_mut with TaskId key
742                        // 使用 DeferredMap 的 get_mut,传入 TaskId key
743                        if let Some(swapped_location) =
744                            self.task_index.get_mut(swapped_task_id.key())
745                        {
746                            swapped_location.vec_index = vec_index;
747                        }
748                    }
749
750                    // Use DeferredMap's remove with TaskId key
751                    // 使用 DeferredMap 的 remove,传入 TaskId key
752                    self.task_index.remove(task_id.key());
753                    cancelled_count += 1;
754                }
755            }
756        }
757
758        // Process L1 layer cancellation
759        // 处理 L1 层取消
760        for (slot_index, tasks) in l1_tasks_by_slot.iter_mut().enumerate() {
761            if tasks.is_empty() {
762                continue;
763            }
764
765            tasks.sort_unstable_by_key(|b| std::cmp::Reverse(b.1));
766
767            let slot = &mut self.l1.slots[slot_index];
768
769            for &(task_id, vec_index) in tasks.iter() {
770                if vec_index < slot.len() && slot[vec_index].get_id() == task_id {
771                    let removed_task = slot.swap_remove(vec_index);
772
773                    match removed_task.into_task_type() {
774                        TaskTypeWithCompletionNotifier::OneShot {
775                            completion_notifier,
776                        } => {
777                            // Use Notify + AtomicU8 for zero-allocation notification
778                            // 使用 Notify + AtomicU8 实现零分配通知
779                            let _ =
780                                completion_notifier.send(crate::task::TaskCompletion::Cancelled);
781                        }
782                        TaskTypeWithCompletionNotifier::Periodic {
783                            completion_notifier,
784                            ..
785                        } => {
786                            // Apply the configured bounded or unbounded completion policy.
787                            // 按配置应用有界或无界完成通知策略。
788                            let _ = completion_notifier.send(TaskCompletion::Cancelled);
789                        }
790                    }
791
792                    if vec_index < slot.len() {
793                        let swapped_task_id = slot[vec_index].get_id();
794                        // Use DeferredMap's get_mut with TaskId key
795                        // 使用 DeferredMap 的 get_mut,传入 TaskId key
796                        if let Some(swapped_location) =
797                            self.task_index.get_mut(swapped_task_id.key())
798                        {
799                            swapped_location.vec_index = vec_index;
800                        }
801                    }
802
803                    // Use DeferredMap's remove with TaskId key
804                    // 使用 DeferredMap 的 remove,传入 TaskId key
805                    self.task_index.remove(task_id.key());
806                    cancelled_count += 1;
807                }
808            }
809        }
810
811        Ok(cancelled_count)
812    }
813
814    /// Reinsert periodic task with the same TaskId
815    ///
816    /// Used to automatically reschedule periodic tasks after they expire
817    ///
818    /// TaskId remains unchanged, only location is updated in DeferredMap
819    ///
820    /// 重新插入周期性任务(保持相同的 TaskId)
821    ///
822    /// 用于在周期性任务过期后自动重新调度
823    ///
824    /// TaskId 保持不变,只更新 DeferredMap 中的位置
825    fn reinsert_periodic_task(&mut self, task_id: TaskId, task: TimerTaskWithCompletionNotifier) {
826        let task_key = task_id.key();
827
828        // Determine which layer the interval should be inserted into
829        // This method is only called by periodic tasks, so the interval is guaranteed to be Some.
830        // 确定间隔应该插入到哪一层
831        // 该方法只能由周期性任务调用,所以间隔是 guaranteed 应当保证为 Some.
832        let interval = task.get_interval().unwrap();
833        let deadline_at = self.clock_at + interval;
834        let (level, ticks, rounds) = self.determine_layer(interval);
835
836        // Use match to reduce branches, and use cached slot mask
837        // 使用 match 减少分支,并使用缓存的槽掩码
838        let (current_tick, slot_mask, slots) = match level {
839            0 => (self.l0.current_tick, self.l0.slot_mask, &mut self.l0.slots),
840            _ => (self.l1.current_tick, self.l1.slot_mask, &mut self.l1.slots),
841        };
842
843        let total_ticks = current_tick.saturating_add(ticks);
844        let slot_index = (total_ticks as usize) & slot_mask;
845
846        // Get the index position of the task in Vec
847        // 获取任务在 Vec 中的索引位置
848        let vec_index = slots[slot_index].len();
849        let new_location = TaskLocation::new(level, slot_index, vec_index);
850
851        // Insert task into slot
852        // 将任务插入槽中
853        slots[slot_index].push(TimerTaskForWheel::new_with_id(
854            task_id,
855            task,
856            total_ticks,
857            rounds,
858            deadline_at,
859        ));
860
861        // Update task location in DeferredMap (doesn't remove, just updates)
862        // 更新 DeferredMap 中的任务位置(不删除,仅更新)
863        if let Some(location) = self.task_index.get_mut(task_key) {
864            *location = new_location;
865        }
866    }
867
868    fn reinsert_task(&mut self, mut task: TimerTaskForWheel) {
869        let remaining = task
870            .deadline_at
871            .checked_duration_since(self.clock_at)
872            .unwrap_or(Duration::ZERO);
873        let (level, ticks, rounds) = self.determine_layer(remaining);
874        let (current_tick, slot_mask, slots) = match level {
875            0 => (self.l0.current_tick, self.l0.slot_mask, &mut self.l0.slots),
876            _ => (self.l1.current_tick, self.l1.slot_mask, &mut self.l1.slots),
877        };
878        let total_ticks = current_tick.saturating_add(ticks);
879        let slot_index = (total_ticks as usize) & slot_mask;
880        let task_id = task.task_id;
881        task.deadline_tick = total_ticks;
882        task.rounds = rounds;
883        let vec_index = slots[slot_index].len();
884        slots[slot_index].push(task);
885
886        if let Some(location) = self.task_index.get_mut(task_id.key()) {
887            *location = TaskLocation::new(level, slot_index, vec_index);
888        }
889    }
890
891    /// Advance the timing wheel by one tick, return all expired tasks
892    ///
893    /// # Returns
894    /// List of expired tasks
895    ///
896    /// # Implementation Details
897    /// - L0 layer advances 1 tick each time (no rounds check)
898    /// - L1 layer advances once every (L1_tick / L0_tick) times
899    /// - L1 expired tasks are batch demoted to L0
900    ///
901    /// 推进时间轮一个 tick,返回所有过期的任务
902    ///
903    /// # 返回值
904    /// 过期任务列表
905    ///
906    /// # 实现细节
907    /// - L0 层每次推进 1 个 tick(无轮数检查)
908    /// - L1 层每 (L1_tick / L0_tick) 次推进一次
909    /// - L1 层过期任务批量降级到 L0
910    pub fn advance(&mut self) -> Vec<WheelAdvanceResult> {
911        if self.owner.is_closed() {
912            return Vec::new();
913        }
914
915        self.clock_at += self.l0.tick_duration;
916        self.advance_one_tick()
917    }
918
919    /// Advance the wheel at a real monotonic timestamp.
920    ///
921    /// 在真实单调时钟时间点推进时间轮。
922    #[inline]
923    pub(crate) fn advance_at(&mut self, now: Instant) -> Vec<WheelAdvanceResult> {
924        if self.owner.is_closed() {
925            return Vec::new();
926        }
927
928        let elapsed = now
929            .checked_duration_since(self.clock_origin)
930            .unwrap_or(Duration::ZERO);
931        let target_tick = u64::try_from(
932            elapsed
933                .as_nanos()
934                .checked_div(self.l0.tick_duration.as_nanos())
935                .unwrap_or_default(),
936        )
937        .unwrap_or(u64::MAX);
938        let ticks_to_advance = target_tick.saturating_sub(self.l0.current_tick).max(1);
939        self.clock_at = now;
940
941        let mut expired_tasks = Vec::new();
942        for _ in 0..ticks_to_advance {
943            expired_tasks.extend(self.advance_one_tick());
944        }
945        expired_tasks
946    }
947
948    #[inline]
949    pub(crate) fn owner(&self) -> std::sync::Arc<WheelOwner> {
950        self.owner.clone()
951    }
952
953    fn advance_one_tick(&mut self) -> Vec<WheelAdvanceResult> {
954        // Advance L0 layer
955        // 推进 L0 层
956        self.l0.current_tick = self.l0.current_tick.saturating_add(1);
957
958        let mut expired_tasks = Vec::new();
959
960        // Process L0 layer expired tasks
961        // Distinguish between one-shot and periodic tasks
962        // 处理 L0 层过期任务
963        // 区分一次性任务和周期性任务
964        let l0_slot_index = (self.l0.current_tick as usize) & self.l0.slot_mask;
965
966        // Collect periodic tasks to reinsert
967        // 收集需要重新插入的周期性任务
968        let mut periodic_tasks_to_reinsert = Vec::new();
969        let mut tasks_to_reinsert = Vec::new();
970
971        {
972            let l0_slot = &mut self.l0.slots[l0_slot_index];
973
974            // Process all tasks in the current slot by always removing from index 0
975            // This avoids index tracking issues with swap_remove
976            // 通过始终从索引 0 移除来处理当前槽中的所有任务
977            // 这避免了 swap_remove 的索引跟踪问题
978            while !l0_slot.is_empty() {
979                // Always remove from index 0
980                // 始终从索引 0 移除
981                let task_with_notifier = l0_slot.swap_remove(0);
982                let task_id = task_with_notifier.get_id();
983
984                // Determine if this is a periodic task (check before consuming)
985                // 判断是否为周期性任务(在消耗前检查)
986                let is_periodic = matches!(
987                    task_with_notifier.task.task_type,
988                    TaskTypeWithCompletionNotifier::Periodic { .. }
989                );
990
991                // For one-shot tasks, remove from DeferredMap index
992                // For periodic tasks, keep in index (will update location in reinsert)
993                // 对于一次性任务,从 DeferredMap 索引中移除
994                // 对于周期性任务,保留在索引中(重新插入时会更新位置)
995                if !is_periodic {
996                    self.task_index.remove(task_id.key());
997                }
998
999                // Update swapped element's index (the element that was moved to index 0)
1000                // 更新被交换元素的索引(被移动到索引 0 的元素)
1001                if !l0_slot.is_empty() {
1002                    let swapped_task_id = l0_slot[0].get_id();
1003                    // Use DeferredMap's get_mut with TaskId key
1004                    // 使用 DeferredMap 的 get_mut,传入 TaskId key
1005                    if let Some(swapped_location) = self.task_index.get_mut(swapped_task_id.key()) {
1006                        swapped_location.vec_index = 0;
1007                    }
1008                }
1009
1010                if task_with_notifier.deadline_at > self.clock_at {
1011                    tasks_to_reinsert.push(task_with_notifier);
1012                    continue;
1013                }
1014
1015                let TimerTaskForWheel { task_id, task, .. } = task_with_notifier;
1016
1017                match task.task_type {
1018                    TaskTypeWithCompletionNotifier::Periodic {
1019                        interval,
1020                        completion_notifier,
1021                    } => {
1022                        let _ = completion_notifier.send(TaskCompletion::Called);
1023
1024                        periodic_tasks_to_reinsert.push((
1025                            task_id,
1026                            TimerTaskWithCompletionNotifier {
1027                                task_type: TaskTypeWithCompletionNotifier::Periodic {
1028                                    interval,
1029                                    completion_notifier,
1030                                },
1031                                delay: task.delay,
1032                                callback: task.callback.clone(),
1033                            },
1034                        ));
1035                    }
1036                    TaskTypeWithCompletionNotifier::OneShot {
1037                        completion_notifier,
1038                    } => {
1039                        let _ = completion_notifier.send(crate::task::TaskCompletion::Called);
1040                    }
1041                }
1042
1043                expired_tasks.push(WheelAdvanceResult {
1044                    id: task_id,
1045                    callback: task.callback,
1046                });
1047            }
1048        }
1049
1050        for task in tasks_to_reinsert {
1051            self.reinsert_task(task);
1052        }
1053
1054        // Reinsert periodic tasks for next interval
1055        // 重新插入周期性任务到下一个周期
1056        for (task_id, task) in periodic_tasks_to_reinsert {
1057            self.reinsert_periodic_task(task_id, task);
1058        }
1059
1060        // Process L1 layer
1061        // Check if L1 layer needs to be advanced
1062        // 处理 L1 层
1063        // 检查是否需要推进 L1 层
1064        if self.l0.current_tick.is_multiple_of(self.l1_tick_ratio) {
1065            self.l1.current_tick = self.l1.current_tick.saturating_add(1);
1066            let l1_slot_index = (self.l1.current_tick as usize) & self.l1.slot_mask;
1067            let l1_slot = &mut self.l1.slots[l1_slot_index];
1068
1069            // Collect L1 layer expired tasks
1070            // 收集 L1 层过期任务
1071            let mut tasks_to_demote = Vec::new();
1072            let mut i = 0;
1073            while i < l1_slot.len() {
1074                let task = &mut l1_slot[i];
1075
1076                if task.rounds > 0 {
1077                    // Still has rounds, decrease rounds and keep
1078                    // 还有轮数,减少轮数并保留
1079                    task.rounds -= 1;
1080                    // Use DeferredMap's get_mut with TaskId key
1081                    // 使用 DeferredMap 的 get_mut,传入 TaskId key
1082                    if let Some(location) = self.task_index.get_mut(task.get_id().key()) {
1083                        location.vec_index = i;
1084                    }
1085                    i += 1;
1086                } else {
1087                    // rounds = 0, need to demote to L0
1088                    // Don't remove from task_index - will update location in demote_tasks
1089                    // rounds = 0,需要降级到 L0
1090                    // 不从 task_index 中移除 - 在 demote_tasks 中会更新位置
1091                    let task_to_demote = l1_slot.swap_remove(i);
1092
1093                    if i < l1_slot.len() {
1094                        let swapped_task_id = l1_slot[i].get_id();
1095                        // Use DeferredMap's get_mut with TaskId key
1096                        // 使用 DeferredMap 的 get_mut,传入 TaskId key
1097                        if let Some(swapped_location) =
1098                            self.task_index.get_mut(swapped_task_id.key())
1099                        {
1100                            swapped_location.vec_index = i;
1101                        }
1102                    }
1103
1104                    tasks_to_demote.push(task_to_demote);
1105                }
1106            }
1107
1108            // Demote tasks to L0
1109            // 将任务降级到 L0
1110            self.demote_tasks(tasks_to_demote);
1111        }
1112
1113        expired_tasks
1114    }
1115
1116    /// Demote tasks from L1 to L0
1117    ///
1118    /// Recalculate and insert L1 expired tasks into L0 layer
1119    ///
1120    /// Updates task location in DeferredMap without removing/reinserting
1121    ///
1122    /// 将任务从 L1 降级到 L0
1123    ///
1124    /// 重新计算并将 L1 过期任务插入到 L0 层
1125    ///
1126    /// 更新 DeferredMap 中的任务位置而不删除/重新插入
1127    fn demote_tasks(&mut self, tasks: Vec<TimerTaskForWheel>) {
1128        for task in tasks {
1129            self.reinsert_task(task);
1130        }
1131    }
1132
1133    /// Check if the timing wheel is empty
1134    ///
1135    /// 检查时间轮是否为空
1136    #[allow(dead_code)]
1137    pub fn is_empty(&self) -> bool {
1138        self.task_index.is_empty()
1139    }
1140
1141    /// Cancel every task and permanently close the wheel.
1142    ///
1143    /// All retained completion receivers receive `Cancelled` before their
1144    /// corresponding notifier is dropped. The operation is idempotent.
1145    ///
1146    /// 取消所有任务并永久关闭时间轮。
1147    ///
1148    /// 所有仍保留的完成接收器都会先收到 `Cancelled`,随后对应通知器才会
1149    /// 被释放。该操作可重复调用。
1150    pub(crate) fn shutdown(&mut self) {
1151        if self.owner.is_closed() {
1152            return;
1153        }
1154
1155        self.owner.close();
1156
1157        let mut task_ids = Vec::with_capacity(self.task_index.len());
1158        task_ids.extend(
1159            self.l0
1160                .slots
1161                .iter()
1162                .flat_map(|slot| slot.iter().map(TimerTaskForWheel::get_id)),
1163        );
1164        task_ids.extend(
1165            self.l1
1166                .slots
1167                .iter()
1168                .flat_map(|slot| slot.iter().map(TimerTaskForWheel::get_id)),
1169        );
1170
1171        let _ = self.cancel_batch(&task_ids);
1172    }
1173
1174    /// Postpone timer task (keep original TaskId)
1175    ///
1176    /// # Parameters
1177    /// - `task_id`: Task ID to postpone
1178    /// - `new_delay`: New delay time (recalculated from current tick, not continuing from original delay time)
1179    /// - `new_callback`: New callback function (if None, keep original callback)
1180    ///
1181    /// # Returns
1182    /// `Ok(true)` when postponed, `Ok(false)` when the task is absent, or
1183    /// `Err(TimerError::WrongWheel)` for an ID from another timing wheel.
1184    ///
1185    /// # Implementation Details
1186    /// - Remove task from original layer/slot, keep its completion_notifier (will not trigger cancellation notification)
1187    /// - Update delay time and callback function (if provided)
1188    /// - Recalculate target layer, slot, and rounds based on new_delay
1189    /// - Cross-layer migration may occur (L0 <-> L1)
1190    /// - Re-insert to new position using original TaskId
1191    /// - Keep consistent with external held TaskId reference
1192    ///
1193    /// 延期定时器任务(保留原始 TaskId)
1194    ///
1195    /// # 参数
1196    /// - `task_id`: 要延期的任务 ID
1197    /// - `new_delay`: 新延迟时间(从当前 tick 重新计算,而非从原延迟时间继续)
1198    /// - `new_callback`: 新回调函数(如果为 None,则保留原回调)
1199    ///
1200    /// # 返回值
1201    /// 任务存在且延期成功时返回 `Ok(true)`,任务不存在时返回 `Ok(false)`,
1202    /// ID 属于其他时间轮时返回 `Err(TimerError::WrongWheel)`。
1203    ///
1204    /// # 实现细节
1205    /// - 从原层级/槽位移除任务,保留其 completion_notifier(不会触发取消通知)
1206    /// - 更新延迟时间和回调函数(如果提供)
1207    /// - 根据 new_delay 重新计算目标层级、槽位和轮数
1208    /// - 可能发生跨层迁移(L0 <-> L1)
1209    /// - 使用原始 TaskId 重新插入到新位置
1210    /// - 与外部持有的 TaskId 引用保持一致
1211    #[inline]
1212    pub fn postpone(
1213        &mut self,
1214        task_id: TaskId,
1215        new_delay: Duration,
1216        new_callback: Option<crate::task::CallbackWrapper>,
1217    ) -> Result<bool, TimerError> {
1218        self.postpone_with_time(task_id, new_delay, new_callback, None)
1219    }
1220
1221    /// Postpone a task using the current monotonic time.
1222    ///
1223    /// 使用当前单调时钟时间延期任务。
1224    #[inline]
1225    pub(crate) fn postpone_at(
1226        &mut self,
1227        task_id: TaskId,
1228        new_delay: Duration,
1229        new_callback: Option<crate::task::CallbackWrapper>,
1230    ) -> Result<bool, TimerError> {
1231        self.postpone_with_time(task_id, new_delay, new_callback, Some(Instant::now()))
1232    }
1233
1234    fn postpone_with_time(
1235        &mut self,
1236        task_id: TaskId,
1237        new_delay: Duration,
1238        new_callback: Option<crate::task::CallbackWrapper>,
1239        now: Option<Instant>,
1240    ) -> Result<bool, TimerError> {
1241        if !task_id.belongs_to(self.owner.id()) {
1242            return Err(TimerError::WrongWheel);
1243        }
1244
1245        let task_key = task_id.key();
1246        let request_time = now.unwrap_or(self.clock_at);
1247
1248        // Step 1: Get task location from DeferredMap (don't remove)
1249        // 步骤 1: 从 DeferredMap 获取任务位置(不删除)
1250        let old_location = match self.task_index.get(task_key) {
1251            Some(loc) => *loc,
1252            None => return Ok(false),
1253        };
1254
1255        // Use match to get slot reference
1256        // 使用 match 获取槽引用
1257        let slot = match old_location.level {
1258            0 => &mut self.l0.slots[old_location.slot_index],
1259            _ => &mut self.l1.slots[old_location.slot_index],
1260        };
1261
1262        // Verify task is still at expected position
1263        // 验证任务仍在预期位置
1264        if old_location.vec_index >= slot.len() || slot[old_location.vec_index].get_id() != task_id
1265        {
1266            // Index inconsistent, return failure
1267            // 索引不一致,返回失败
1268            return Ok(false);
1269        }
1270
1271        // Use swap_remove to remove task from slot
1272        // 使用 swap_remove 从槽中移除任务
1273        let mut task = slot.swap_remove(old_location.vec_index);
1274
1275        // Update swapped element's index (if a swap occurred)
1276        // 更新被交换元素的索引(如果发生了交换)
1277        if old_location.vec_index < slot.len() {
1278            let swapped_task_id = slot[old_location.vec_index].get_id();
1279            // Use DeferredMap's get_mut with TaskId key
1280            // 使用 DeferredMap 的 get_mut,传入 TaskId key
1281            if let Some(swapped_location) = self.task_index.get_mut(swapped_task_id.key()) {
1282                swapped_location.vec_index = old_location.vec_index;
1283            }
1284        }
1285
1286        // Step 2: Update task's delay and callback
1287        // 步骤 2: 更新任务的延迟和回调
1288        task.update_delay(new_delay);
1289        if let Some(callback) = new_callback {
1290            task.update_callback(callback);
1291        }
1292
1293        // Step 3: Recalculate layer, slot, and rounds based on new delay
1294        // 步骤 3: 根据新延迟重新计算层级、槽位和轮数
1295        let (new_level, ticks, new_rounds) = self.determine_layer(new_delay);
1296        let deadline_at = request_time + new_delay;
1297
1298        // Use match to reduce branches, and use cached slot mask
1299        // 使用 match 减少分支,并使用缓存的槽掩码
1300        let (current_tick, slot_mask, slots) = match new_level {
1301            0 => (self.l0.current_tick, self.l0.slot_mask, &mut self.l0.slots),
1302            _ => (self.l1.current_tick, self.l1.slot_mask, &mut self.l1.slots),
1303        };
1304
1305        let total_ticks = current_tick.saturating_add(ticks);
1306        let new_slot_index = (total_ticks as usize) & slot_mask;
1307
1308        // Update task's timing wheel parameters
1309        // 更新任务的时间轮参数
1310        task.deadline_tick = total_ticks;
1311        task.rounds = new_rounds;
1312        task.deadline_at = deadline_at;
1313
1314        // Step 4: Re-insert task to new layer/slot
1315        // 步骤 4: 将任务重新插入到新层级/槽位
1316        let new_vec_index = slots[new_slot_index].len();
1317        let new_location = TaskLocation::new(new_level, new_slot_index, new_vec_index);
1318
1319        slots[new_slot_index].push(task);
1320
1321        // Update task location in DeferredMap (task already exists in index)
1322        // 更新 DeferredMap 中的任务位置(任务已在索引中)
1323        if let Some(location) = self.task_index.get_mut(task_key) {
1324            *location = new_location;
1325        }
1326
1327        Ok(true)
1328    }
1329
1330    /// Batch postpone timer tasks
1331    ///
1332    /// # Parameters
1333    /// - `updates`: List of tuples of (task ID, new delay)
1334    ///
1335    /// # Returns
1336    /// Number of successfully postponed tasks, or `Err(TimerError::WrongWheel)`
1337    /// if any ID belongs to another timing wheel.
1338    ///
1339    /// # Performance Advantages
1340    /// - Batch processing reduces function call overhead
1341    /// - All delays are recalculated from current_tick at call time
1342    ///
1343    /// # Notes
1344    /// - If a task ID does not exist, that task will be skipped without affecting other tasks' postponement
1345    ///
1346    /// 批量延期定时器任务
1347    ///
1348    /// # 参数
1349    /// - `updates`: (任务 ID, 新延迟) 元组列表
1350    ///
1351    /// # 返回值
1352    /// 成功延期的任务数量;如果任一 ID 属于其他时间轮则返回
1353    /// `Err(TimerError::WrongWheel)`,且不修改任何任务。
1354    ///
1355    /// # 性能优势
1356    /// - 批处理减少函数调用开销
1357    /// - 所有延迟在调用时从 current_tick 重新计算
1358    ///
1359    /// # 注意
1360    /// - 如果任务 ID 不存在,该任务将被跳过,不影响其他任务的延期
1361    #[inline]
1362    pub fn postpone_batch(
1363        &mut self,
1364        updates: Vec<(TaskId, Duration)>,
1365    ) -> Result<usize, TimerError> {
1366        self.postpone_batch_with_time(updates, None)
1367    }
1368
1369    /// Batch postpone tasks using the current monotonic time.
1370    ///
1371    /// 使用当前单调时钟时间批量延期任务。
1372    #[inline]
1373    pub(crate) fn postpone_batch_at(
1374        &mut self,
1375        updates: Vec<(TaskId, Duration)>,
1376    ) -> Result<usize, TimerError> {
1377        self.postpone_batch_with_time(updates, Some(Instant::now()))
1378    }
1379
1380    fn postpone_batch_with_time(
1381        &mut self,
1382        updates: Vec<(TaskId, Duration)>,
1383        now: Option<Instant>,
1384    ) -> Result<usize, TimerError> {
1385        if updates
1386            .iter()
1387            .any(|(task_id, _)| !task_id.belongs_to(self.owner.id()))
1388        {
1389            return Err(TimerError::WrongWheel);
1390        }
1391
1392        let mut postponed_count = 0;
1393
1394        for (task_id, new_delay) in updates {
1395            if self.postpone_with_time(task_id, new_delay, None, now)? {
1396                postponed_count += 1;
1397            }
1398        }
1399
1400        Ok(postponed_count)
1401    }
1402
1403    /// Batch postpone timer tasks (replace callbacks)
1404    ///
1405    /// # Parameters
1406    /// - `updates`: List of tuples of (task ID, new delay, new callback)
1407    ///
1408    /// # Returns
1409    /// Number of successfully postponed tasks, or `Err(TimerError::WrongWheel)`
1410    /// if any ID belongs to another timing wheel.
1411    ///
1412    /// 批量延期定时器任务(替换回调)
1413    ///
1414    /// # 参数
1415    /// - `updates`: (任务 ID, 新延迟, 新回调) 元组列表
1416    ///
1417    /// # 返回值
1418    /// 成功延期的任务数量;如果任一 ID 属于其他时间轮则返回
1419    /// `Err(TimerError::WrongWheel)`,且不修改任何任务。
1420    pub fn postpone_batch_with_callbacks(
1421        &mut self,
1422        updates: Vec<(TaskId, Duration, Option<crate::task::CallbackWrapper>)>,
1423    ) -> Result<usize, TimerError> {
1424        self.postpone_batch_with_callbacks_at_time(updates, None)
1425    }
1426
1427    /// Batch postpone tasks with callbacks using the current monotonic time.
1428    ///
1429    /// 使用当前单调时钟时间批量延期并替换回调。
1430    #[inline]
1431    pub(crate) fn postpone_batch_with_callbacks_at(
1432        &mut self,
1433        updates: Vec<(TaskId, Duration, Option<crate::task::CallbackWrapper>)>,
1434    ) -> Result<usize, TimerError> {
1435        self.postpone_batch_with_callbacks_at_time(updates, Some(Instant::now()))
1436    }
1437
1438    fn postpone_batch_with_callbacks_at_time(
1439        &mut self,
1440        updates: Vec<(TaskId, Duration, Option<crate::task::CallbackWrapper>)>,
1441        now: Option<Instant>,
1442    ) -> Result<usize, TimerError> {
1443        if updates
1444            .iter()
1445            .any(|(task_id, _, _)| !task_id.belongs_to(self.owner.id()))
1446        {
1447            return Err(TimerError::WrongWheel);
1448        }
1449
1450        let mut postponed_count = 0;
1451
1452        for (task_id, new_delay, new_callback) in updates {
1453            if self.postpone_with_time(task_id, new_delay, new_callback, now)? {
1454                postponed_count += 1;
1455            }
1456        }
1457
1458        Ok(postponed_count)
1459    }
1460}
1461
1462#[cfg(test)]
1463mod tests {
1464    use super::*;
1465    use crate::task::{CallbackWrapper, TimerTask, TimerTaskWithCompletionNotifier};
1466
1467    #[test]
1468    fn test_wheel_creation() {
1469        let wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1470        assert_eq!(wheel.slot_count(), 512);
1471        assert_eq!(wheel.current_tick(), 0);
1472        assert!(wheel.is_empty());
1473    }
1474
1475    #[test]
1476    fn test_hierarchical_wheel_creation() {
1477        let config = WheelConfig::default();
1478
1479        let wheel = Wheel::new(config, BatchConfig::default()).unwrap();
1480        assert_eq!(wheel.slot_count(), 512); // L0 slot count (L0 层槽数量)
1481        assert_eq!(wheel.current_tick(), 0);
1482        assert!(wheel.is_empty());
1483        // L1 layer always exists in hierarchical mode (L1 层在分层模式下始终存在)
1484        assert_eq!(wheel.l1.slot_count, 64);
1485        assert_eq!(wheel.l1_tick_ratio, 100); // 1000ms / 10ms = 100 ticks (1000毫秒 / 10毫秒 = 100个tick)
1486    }
1487
1488    #[test]
1489    fn test_hierarchical_config_validation() {
1490        // L1 tick must be an integer multiple of L0 tick (L1 tick 必须是 L0 tick 的整数倍)
1491        let result = WheelConfig::builder()
1492            .l0_tick_duration(Duration::from_millis(10))
1493            .l0_slot_count(512)
1494            .l1_tick_duration(Duration::from_millis(15)) // Not an integer multiple (不是整数倍)
1495            .l1_slot_count(64)
1496            .build();
1497
1498        assert!(result.is_err());
1499
1500        // Correct configuration (正确的配置)
1501        let result = WheelConfig::builder()
1502            .l0_tick_duration(Duration::from_millis(10))
1503            .l0_slot_count(512)
1504            .l1_tick_duration(Duration::from_secs(1)) // 1000ms / 10ms = 100 ticks (1000毫秒 / 10毫秒 = 100个tick)
1505            .l1_slot_count(64)
1506            .build();
1507
1508        assert!(result.is_ok());
1509    }
1510
1511    #[test]
1512    fn test_layer_determination() {
1513        let config = WheelConfig::default();
1514
1515        let wheel = Wheel::new(config, BatchConfig::default()).unwrap();
1516
1517        // Short delay should enter L0 layer (短延迟应该进入 L0 层)
1518        // L0: 512 slots * 10ms = 5120ms
1519        let (level, _, rounds) = wheel.determine_layer(Duration::from_millis(100));
1520        assert_eq!(level, 0);
1521        assert_eq!(rounds, 0);
1522
1523        // Long delay should enter L1 layer
1524        // 超过 L0 范围(>5120ms) (超过 L0 范围 (>5120毫秒))
1525        let (level, _, rounds) = wheel.determine_layer(Duration::from_secs(10));
1526        assert_eq!(level, 1);
1527        assert_eq!(rounds, 0);
1528
1529        // Long delay should enter L1 layer and have rounds
1530        // L1: 64 slots * 1000ms = 64000ms (L1: 64个槽 * 1000毫秒 = 64000毫秒)
1531        let (level, _, rounds) = wheel.determine_layer(Duration::from_secs(120));
1532        assert_eq!(level, 1);
1533        assert!(rounds > 0);
1534
1535        // Exact L0 capacity remains in L0; the next nanosecond moves to L1.
1536        let (level, ticks, _) = wheel.determine_layer(Duration::from_millis(5120));
1537        assert_eq!(level, 0);
1538        assert_eq!(ticks, 512);
1539        let (level, _, _) = wheel.determine_layer(Duration::from_millis(5121));
1540        assert_eq!(level, 1);
1541    }
1542
1543    #[test]
1544    fn test_hierarchical_insert_and_advance() {
1545        let config = WheelConfig::default();
1546
1547        let mut wheel = Wheel::new(config, BatchConfig::default()).unwrap();
1548
1549        // Insert short delay task into L0 (插入短延迟任务到 L0)
1550        let callback = CallbackWrapper::new(|| async {});
1551        let task = TimerTask::new_oneshot(Duration::from_millis(100), Some(callback));
1552        let (task_with_notifier, _completion_rx) =
1553            TimerTaskWithCompletionNotifier::from_timer_task(task);
1554        let handle = wheel.allocate_handle();
1555        let task_id = handle.task_id();
1556        wheel.insert(handle, task_with_notifier).unwrap();
1557
1558        // Verify task is in L0 layer (验证任务在 L0 层)
1559        let location = wheel.task_index.get(task_id.key()).unwrap();
1560        assert_eq!(location.level, 0);
1561
1562        // Advance 10 ticks (100ms) (前进 10 个 tick (100毫秒))
1563        for _ in 0..10 {
1564            let expired = wheel.advance();
1565            if !expired.is_empty() {
1566                assert_eq!(expired.len(), 1);
1567                assert_eq!(expired[0].id, task_id);
1568                return;
1569            }
1570        }
1571        panic!("Task should have expired");
1572    }
1573
1574    #[test]
1575    fn test_cross_layer_cancel() {
1576        let config = WheelConfig::default();
1577
1578        let mut wheel = Wheel::new(config, BatchConfig::default()).unwrap();
1579
1580        // Insert L0 task (插入 L0 任务)
1581        let callback1 = CallbackWrapper::new(|| async {});
1582        let task1 = TimerTask::new_oneshot(Duration::from_millis(100), Some(callback1));
1583        let (task_with_notifier1, _rx1) = TimerTaskWithCompletionNotifier::from_timer_task(task1);
1584        let handle1 = wheel.allocate_handle();
1585        let task_id1 = handle1.task_id();
1586        wheel.insert(handle1, task_with_notifier1).unwrap();
1587
1588        // Insert L1 task (插入 L1 任务)
1589        let callback2 = CallbackWrapper::new(|| async {});
1590        let task2 = TimerTask::new_oneshot(Duration::from_secs(10), Some(callback2));
1591        let (task_with_notifier2, _rx2) = TimerTaskWithCompletionNotifier::from_timer_task(task2);
1592        let handle2 = wheel.allocate_handle();
1593        let task_id2 = handle2.task_id();
1594        wheel.insert(handle2, task_with_notifier2).unwrap();
1595
1596        // Verify levels (验证层级)
1597        assert_eq!(wheel.task_index.get(task_id1.key()).unwrap().level, 0);
1598        assert_eq!(wheel.task_index.get(task_id2.key()).unwrap().level, 1);
1599
1600        // Cancel L0 task (取消 L0 任务)
1601        assert!(wheel.cancel(task_id1).unwrap());
1602        assert!(wheel.task_index.get(task_id1.key()).is_none());
1603
1604        // Cancel L1 task (取消 L1 任务)
1605        assert!(wheel.cancel(task_id2).unwrap());
1606        assert!(wheel.task_index.get(task_id2.key()).is_none());
1607
1608        assert!(wheel.is_empty()); // 时间轮应该为空
1609    }
1610
1611    #[test]
1612    fn test_delay_to_ticks() {
1613        let wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1614        assert_eq!(wheel.delay_to_ticks(Duration::from_millis(100)), 10);
1615        assert_eq!(wheel.delay_to_ticks(Duration::from_millis(50)), 5);
1616        assert_eq!(wheel.delay_to_ticks(Duration::from_millis(1)), 1); // Minimum 1 tick (最小 1 个 tick)
1617        assert_eq!(wheel.delay_to_ticks(Duration::from_millis(15)), 2);
1618        assert_eq!(wheel.delay_to_ticks(Duration::from_micros(500)), 1);
1619    }
1620
1621    #[test]
1622    fn test_wheel_invalid_slot_count() {
1623        let result = WheelConfig::builder().l0_slot_count(100).build();
1624        assert!(result.is_err());
1625        if let Err(crate::error::TimerError::InvalidSlotCount { slot_count, reason }) = result {
1626            assert_eq!(slot_count, 100);
1627            assert_eq!(reason, "L0 layer slot count must be power of 2"); // L0 层槽数量必须是 2 的幂
1628        } else {
1629            panic!("Expected InvalidSlotCount error"); // 期望 InvalidSlotCount 错误
1630        }
1631    }
1632
1633    #[test]
1634    fn test_minimum_delay() {
1635        let mut wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1636
1637        // Test minimum delay (delays less than 1 tick should be rounded up to 1 tick) (测试最小延迟 (延迟小于 1 个 tick 应该向上舍入到 1 个 tick))
1638        let callback = CallbackWrapper::new(|| async {});
1639        let task = TimerTask::new_oneshot(Duration::from_millis(1), Some(callback));
1640        let (task_with_notifier, _completion_rx) =
1641            TimerTaskWithCompletionNotifier::from_timer_task(task);
1642        let handle = wheel.allocate_handle();
1643        let task_id: TaskId = handle.task_id();
1644        wheel.insert(handle, task_with_notifier).unwrap();
1645
1646        // Advance 1 tick, task should trigger (前进 1 个 tick,任务应该触发)
1647        let expired = wheel.advance();
1648        assert_eq!(
1649            expired.len(),
1650            1,
1651            "Minimum delay task should be triggered after 1 tick"
1652        ); // 最小延迟任务应该在 1 个 tick 后触发
1653        assert_eq!(expired[0].id, task_id);
1654    }
1655
1656    #[test]
1657    fn test_advance_empty_slots() {
1658        let mut wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1659
1660        // Do not insert any tasks, advance multiple ticks (不插入任何任务,前进多个tick)
1661        for _ in 0..100 {
1662            let expired = wheel.advance();
1663            assert!(
1664                expired.is_empty(),
1665                "Empty slots should not return any tasks"
1666            );
1667        }
1668
1669        assert_eq!(
1670            wheel.current_tick(),
1671            100,
1672            "current_tick should correctly increment"
1673        ); // current_tick 应该正确递增
1674    }
1675
1676    #[test]
1677    fn test_slot_boundary() {
1678        let mut wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1679
1680        // Test slot boundary and wraparound (测试槽边界和环绕)
1681        // 第一个任务:延迟 10ms(1 tick),应该在 slot 1 触发
1682        let callback1 = CallbackWrapper::new(|| async {});
1683        let task1 = TimerTask::new_oneshot(Duration::from_millis(10), Some(callback1));
1684        let (task_with_notifier1, _rx1) = TimerTaskWithCompletionNotifier::from_timer_task(task1);
1685        let handle1 = wheel.allocate_handle();
1686        let task_id_1 = handle1.task_id();
1687        wheel.insert(handle1, task_with_notifier1).unwrap();
1688
1689        // Second task: delay 5110ms (511 ticks), should trigger on slot 511 (第二个任务:延迟 5110毫秒 (511个tick),应该在槽 511 触发)
1690        let callback2 = CallbackWrapper::new(|| async {});
1691        let task2 = TimerTask::new_oneshot(Duration::from_millis(5110), Some(callback2));
1692        let (task_with_notifier2, _rx2) = TimerTaskWithCompletionNotifier::from_timer_task(task2);
1693        let handle2 = wheel.allocate_handle();
1694        let task_id_2 = handle2.task_id();
1695        wheel.insert(handle2, task_with_notifier2).unwrap();
1696
1697        // Advance 1 tick, first task should trigger (前进 1 个 tick,第一个任务应该触发)
1698        let expired = wheel.advance();
1699        assert_eq!(expired.len(), 1, "First task should trigger on tick 1"); // 第一个任务应该在第 1 个 tick 触发
1700        assert_eq!(expired[0].id, task_id_1);
1701
1702        // Continue advancing to 511 ticks (from tick 1 to tick 511), second task should trigger (继续前进 511个tick (从tick 1到tick 511),第二个任务应该触发)
1703        let mut triggered = false;
1704        for i in 0..510 {
1705            let expired = wheel.advance();
1706            if !expired.is_empty() {
1707                assert_eq!(
1708                    expired.len(),
1709                    1,
1710                    "The {}th advance should trigger the second task",
1711                    i + 2
1712                ); // 第 {i + 2} 次前进应该触发第二个任务
1713                assert_eq!(expired[0].id, task_id_2);
1714                triggered = true;
1715                break;
1716            }
1717        }
1718        assert!(triggered, "Second task should trigger on tick 511"); // 第二个任务应该在第 511 个 tick 触发
1719
1720        assert!(wheel.is_empty(), "All tasks should have been triggered"); // 所有任务都应该被触发
1721    }
1722
1723    #[test]
1724    fn test_task_id_uniqueness() {
1725        let mut wheel = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1726
1727        // Insert multiple tasks, verify TaskId uniqueness (插入多个任务,验证 TaskId 唯一性)
1728        let mut task_ids = std::collections::HashSet::new();
1729        for _ in 0..100 {
1730            let callback = CallbackWrapper::new(|| async {});
1731            let task = TimerTask::new_oneshot(Duration::from_millis(100), Some(callback));
1732            let (task_with_notifier, _rx) = TimerTaskWithCompletionNotifier::from_timer_task(task);
1733            let handle = wheel.allocate_handle();
1734            let task_id = handle.task_id();
1735            wheel.insert(handle, task_with_notifier).unwrap();
1736
1737            assert!(task_ids.insert(task_id), "TaskId should be unique"); // TaskId 应该唯一
1738        }
1739
1740        assert_eq!(task_ids.len(), 100);
1741    }
1742
1743    #[test]
1744    fn test_cross_wheel_handle_is_rejected() {
1745        let mut source = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1746        let mut target = Wheel::new(WheelConfig::default(), BatchConfig::default()).unwrap();
1747
1748        let handle = source.allocate_handle();
1749        let task = TimerTask::new_oneshot(Duration::from_secs(10), None);
1750        let (task_with_notifier, _receiver) =
1751            TimerTaskWithCompletionNotifier::from_timer_task(task);
1752
1753        assert_eq!(
1754            target.insert(handle, task_with_notifier),
1755            Err(TimerError::WrongWheel)
1756        );
1757
1758        // The rejected handle is reclaimed by its original wheel before the
1759        // next allocation.
1760        let _next_handle = source.allocate_handle();
1761    }
1762}