pi_local_timer/
local_timer.rs

1
2use std::{collections::VecDeque, fmt::{Debug, Formatter, Result as FResult}};
3
4use pi_dyn_uint::{UintFactory, ClassFactory, SlabFactory};
5use pi_time::run_millis;
6use crate::frame_wheel::{FrameWheel};
7use crate::item::{TimeoutItem};
8
9/// 任务轮实现的延时任务管理
10/// * `T` 延时任务的数据类型
11/// * `N1` 一级粒度轮的槽位数 <任务轮分4级粒度>
12/// * `N2` 二级粒度轮的槽位数 <任务轮分4级粒度>
13/// * `N3` 三级粒度轮的槽位数 <任务轮分4级粒度>
14/// * `N4` 四级粒度轮的槽位数 <任务轮分4级粒度>
15/// * N1 到 N4 依次减少, 总数不应超过 usize 范围
16/// ## Example ##
17/// ```rust
18/// let mut timer = LocalTimer::<i32, 100, 60, 60, 24>::new(10, run_millis());
19/// // 插入一个任务 - 数据为 55, 延时为 1000ms
20/// let timeout_handler = timer.insert(Item::new(55 as i32, 1000 as u64));
21/// // 尝试获取一个超时任务
22/// let one_task_option = timer.pop();
23/// // 当获取到的任务为空,可以检查可休眠时间
24/// let sleep_time = timer.check_sleep(now);
25/// // 可移除一个任务
26/// let item_option = timer.try_remove(timeout_handler);
27/// ```
28pub struct LocalTimer<T, const N1: usize, const N2: usize, const N3: usize, const N4: usize> {
29    /// 最小粒度世界线的帧间隔
30    pub frame_time: u64,
31    /// 启动时间
32    pub start_time: u64,
33    /// 滚动的累积时间
34    pub roll_time: u64,
35    /// Index 工厂
36    pub index_factory: SlabFactory<usize,()>,
37    /// 帧进度的任务轮
38    pub frame_wheel: FrameWheel<T, N1, N2, N3, N4>
39}
40
41impl<T, const N1: usize, const N2: usize, const N3: usize, const N4: usize> LocalTimer<T, N1, N2, N3, N4>{
42
43    /// Create a wheel to support four rounds.
44    /// * `frame_time` 最小时间间隔 - 单位`毫秒`
45    /// * `now` 当前绝对时间
46    /// * `tip` frame_time 与 N1..N4 之积 的乘积不应超过 uszie 范围
47    /// ### Error Example ###
48    /// ```rust
49    /// // 当 usize 最大 2**32, 则下面的创建不保证运行正确,且可能崩溃
50    /// let mut timer = WheelTimer::<i32, 100, 60, 60, 24>::new(1000, run_millis()); // 100*60*60*24*1000 = 8640000000 > 2**32
51    /// ```
52    pub fn new(frame_time: u64, now: u64) -> Self{
53        LocalTimer {
54            frame_time,
55            start_time: now,
56            roll_time: 0,
57            index_factory: SlabFactory::new(),
58            frame_wheel: FrameWheel::new()
59        }
60    }
61
62    #[inline]
63    /// 检查可休眠时间
64    /// * now 当前线程时间 <与创建时设置的 now 属于同一时间进度>
65    pub fn check_sleep(&self, now: u64) -> u64 {
66        let curr = self.start_time + self.roll_time;
67        if curr > now {
68            return curr - now;
69        }
70        else {
71            return 0;
72        }
73    }
74
75    /// 总任务数量
76    pub fn len(&self) -> usize {
77        self.frame_wheel.len()
78    }
79
80    #[inline]
81    /// 当前运行时长
82    pub fn get_time(&mut self) -> u64{
83        self.roll_time
84    }
85
86    /// 插入元素
87    /// * `data` 目标数据
88    /// * `timeout` 延时时间 - 单位`毫秒`
89    pub fn insert(&mut self, mut data: T, timeout: u64) -> usize{
90        let index = self.index_factory.create(0, 0, ());
91
92        // 相对毫秒延时 转换为 绝对帧位置
93        let frame_point = timeout / (self.frame_time as u64) + self.frame_wheel.frame;
94
95        let elem = TimeoutItem::new(data, frame_point);
96
97        self.frame_wheel.insert(elem, index, &mut self.index_factory);
98
99        index
100    }
101
102    /// clear all elem
103    pub fn clear(&mut self){
104        self.frame_wheel.clear();
105        self.index_factory.clear();
106    }
107
108    #[inline]
109    /// 弹出一个超时任务 - 当没有任务弹出,经过检查需要做一次滚动则进行一次滚动 - 当没有任务弹出,外部可以检查睡眠时间
110    /// * `now` 当前时间
111    pub fn pop(&mut self, now: u64) -> Option<(TimeoutItem<T>, usize)> {
112        if let Some(task) = self.frame_wheel.pop() {
113            self.index_factory.destroy(task.1);
114            return Some(task);
115        }
116        else {
117            // 已经没有超时任务,检查时间是否滚动
118            if self.check(now) {
119                self.roll_once();
120            }
121        }
122        None
123    }
124
125    /// 移除一个任务
126    /// * `index` 任务插入时返回的 index
127    pub fn try_remove(&mut self, index: usize) -> Option<TimeoutItem<T>>{
128        match self.index_factory.try_load(index) {
129            Some(i) => {
130                if let Some((elem, _)) = self.frame_wheel.delete(self.index_factory.get_class(index).clone(), i, &mut self.index_factory) {
131                    self.index_factory.destroy(index);
132                    return Some(elem);
133                }
134
135                None
136            },
137            None => None,
138        }
139    }
140
141    /// Panics if index is out of bounds. 移除一个任务
142    /// * `index` 任务插入时返回的 index
143    pub fn remove(&mut self, index: usize) -> Option<TimeoutItem<T>> {
144        if let Some((elem, _)) = self.frame_wheel.delete(self.index_factory.get_class(index).clone(), self.index_factory.load(index), &mut self.index_factory) {
145            self.index_factory.destroy(index);
146            return Some(elem);
147        }
148        None
149    }
150
151    #[inline]
152    /// 检查是否应该做一次滚动 - 内部使用 
153    /// * `now` 当前线程时间 <与创建时设置的 now 属于同一时间进度>
154    pub fn check(&self, now: u64) -> bool {
155        return self.check_sleep(now) == 0;
156    }
157
158    #[inline]
159    /// 滚动一次 - 使用者不调用
160    pub fn roll_once(&mut self) {
161        
162        self.roll_time += self.frame_time as u64;
163        self.frame_wheel.roll_once(&mut self.index_factory);
164    }
165
166    pub fn get_item_timeout(&self, item: &TimeoutItem<T>) -> u64 {
167        item.get_frame_point() * self.frame_time
168    }
169}
170
171impl<T: Debug, const N1: usize, const N2: usize, const N3: usize, const N4: usize> Debug for LocalTimer<T, N1, N2, N3, N4> where T: Debug {
172    fn fmt(&self, fmt: &mut Formatter) -> FResult {
173        write!(fmt,
174r##"Wheel( 
175    index_factory: {:?},
176    wheel: {:?},
177)"##,
178               self.index_factory,
179               self.frame_wheel
180        )
181    }
182}