kestrel_protocol_timer/
config.rs

1//! 定时器配置模块
2//!
3//! 提供分层的配置结构和 Builder 模式,用于配置时间轮、服务和批处理行为。
4
5use crate::error::TimerError;
6use std::time::Duration;
7
8/// 时间轮配置
9///
10/// 用于配置时间轮的基本参数,包括 tick 时长和槽位数量。
11///
12/// # 示例
13/// ```no_run
14/// use kestrel_protocol_timer::WheelConfig;
15/// use std::time::Duration;
16///
17/// // 使用默认配置
18/// let config = WheelConfig::default();
19///
20/// // 使用 Builder 自定义配置
21/// let config = WheelConfig::builder()
22///     .tick_duration(Duration::from_millis(20))
23///     .slot_count(1024)
24///     .build()
25///     .unwrap();
26/// ```
27#[derive(Debug, Clone)]
28pub struct WheelConfig {
29    /// 每个 tick 的时间长度
30    pub tick_duration: Duration,
31    /// 槽位数量(必须是 2 的幂次方)
32    pub slot_count: usize,
33}
34
35impl Default for WheelConfig {
36    fn default() -> Self {
37        Self {
38            tick_duration: Duration::from_millis(10),
39            slot_count: 512,
40        }
41    }
42}
43
44impl WheelConfig {
45    /// 创建配置构建器
46    pub fn builder() -> WheelConfigBuilder {
47        WheelConfigBuilder::default()
48    }
49}
50
51/// 时间轮配置构建器
52#[derive(Debug, Clone)]
53pub struct WheelConfigBuilder {
54    tick_duration: Duration,
55    slot_count: usize,
56}
57
58impl Default for WheelConfigBuilder {
59    fn default() -> Self {
60        let config = WheelConfig::default();
61        Self {
62            tick_duration: config.tick_duration,
63            slot_count: config.slot_count,
64        }
65    }
66}
67
68impl WheelConfigBuilder {
69    /// 设置 tick 时长
70    pub fn tick_duration(mut self, duration: Duration) -> Self {
71        self.tick_duration = duration;
72        self
73    }
74
75    /// 设置槽位数量
76    pub fn slot_count(mut self, count: usize) -> Self {
77        self.slot_count = count;
78        self
79    }
80
81    /// 构建配置并进行验证
82    ///
83    /// # 返回
84    /// - `Ok(WheelConfig)`: 配置有效
85    /// - `Err(TimerError)`: 配置验证失败
86    ///
87    /// # 验证规则
88    /// - tick_duration 必须大于 0
89    /// - slot_count 必须大于 0 且是 2 的幂次方
90    pub fn build(self) -> Result<WheelConfig, TimerError> {
91        // 验证 tick_duration
92        if self.tick_duration.is_zero() {
93            return Err(TimerError::InvalidConfiguration {
94                field: "tick_duration".to_string(),
95                reason: "tick 时长必须大于 0".to_string(),
96            });
97        }
98
99        // 验证 slot_count
100        if self.slot_count == 0 {
101            return Err(TimerError::InvalidSlotCount {
102                slot_count: self.slot_count,
103                reason: "槽位数量必须大于 0",
104            });
105        }
106
107        if !self.slot_count.is_power_of_two() {
108            return Err(TimerError::InvalidSlotCount {
109                slot_count: self.slot_count,
110                reason: "槽位数量必须是 2 的幂次方",
111            });
112        }
113
114        Ok(WheelConfig {
115            tick_duration: self.tick_duration,
116            slot_count: self.slot_count,
117        })
118    }
119}
120
121/// 服务配置
122///
123/// 用于配置 TimerService 的通道容量。
124///
125/// # 示例
126/// ```no_run
127/// use kestrel_protocol_timer::ServiceConfig;
128///
129/// // 使用默认配置
130/// let config = ServiceConfig::default();
131///
132/// // 使用 Builder 自定义配置
133/// let config = ServiceConfig::builder()
134///     .command_channel_capacity(1024)
135///     .timeout_channel_capacity(2000)
136///     .build()
137///     .unwrap();
138/// ```
139#[derive(Debug, Clone)]
140pub struct ServiceConfig {
141    /// 命令通道容量
142    pub command_channel_capacity: usize,
143    /// 超时通道容量
144    pub timeout_channel_capacity: usize,
145}
146
147impl Default for ServiceConfig {
148    fn default() -> Self {
149        Self {
150            command_channel_capacity: 512,
151            timeout_channel_capacity: 1000,
152        }
153    }
154}
155
156impl ServiceConfig {
157    /// 创建配置构建器
158    pub fn builder() -> ServiceConfigBuilder {
159        ServiceConfigBuilder::default()
160    }
161}
162
163/// 服务配置构建器
164#[derive(Debug, Clone)]
165pub struct ServiceConfigBuilder {
166    command_channel_capacity: usize,
167    timeout_channel_capacity: usize,
168}
169
170impl Default for ServiceConfigBuilder {
171    fn default() -> Self {
172        let config = ServiceConfig::default();
173        Self {
174            command_channel_capacity: config.command_channel_capacity,
175            timeout_channel_capacity: config.timeout_channel_capacity,
176        }
177    }
178}
179
180impl ServiceConfigBuilder {
181    /// 设置命令通道容量
182    pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
183        self.command_channel_capacity = capacity;
184        self
185    }
186
187    /// 设置超时通道容量
188    pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
189        self.timeout_channel_capacity = capacity;
190        self
191    }
192
193    /// 构建配置并进行验证
194    ///
195    /// # 返回
196    /// - `Ok(ServiceConfig)`: 配置有效
197    /// - `Err(TimerError)`: 配置验证失败
198    ///
199    /// # 验证规则
200    /// - 所有通道容量必须大于 0
201    pub fn build(self) -> Result<ServiceConfig, TimerError> {
202        if self.command_channel_capacity == 0 {
203            return Err(TimerError::InvalidConfiguration {
204                field: "command_channel_capacity".to_string(),
205                reason: "命令通道容量必须大于 0".to_string(),
206            });
207        }
208
209        if self.timeout_channel_capacity == 0 {
210            return Err(TimerError::InvalidConfiguration {
211                field: "timeout_channel_capacity".to_string(),
212                reason: "超时通道容量必须大于 0".to_string(),
213            });
214        }
215
216        Ok(ServiceConfig {
217            command_channel_capacity: self.command_channel_capacity,
218            timeout_channel_capacity: self.timeout_channel_capacity,
219        })
220    }
221}
222
223/// 批处理配置
224///
225/// 用于配置批量操作的优化参数。
226///
227/// # 示例
228/// ```no_run
229/// use kestrel_protocol_timer::BatchConfig;
230///
231/// // 使用默认配置
232/// let config = BatchConfig::default();
233///
234/// // 自定义配置
235/// let config = BatchConfig {
236///     small_batch_threshold: 20,
237/// };
238/// ```
239#[derive(Debug, Clone)]
240pub struct BatchConfig {
241    /// 小批量阈值,用于批量取消优化
242    /// 
243    /// 当批量取消的任务数量小于等于此值时,直接逐个取消而不进行分组排序
244    pub small_batch_threshold: usize,
245}
246
247impl Default for BatchConfig {
248    fn default() -> Self {
249        Self {
250            small_batch_threshold: 10,
251        }
252    }
253}
254
255/// 顶层定时器配置
256///
257/// 组合所有子配置,提供完整的定时器系统配置。
258///
259/// # 示例
260/// ```no_run
261/// use kestrel_protocol_timer::TimerConfig;
262///
263/// // 使用默认配置
264/// let config = TimerConfig::default();
265///
266/// // 使用 Builder 自定义配置
267/// let config = TimerConfig::builder()
268///     .tick_duration(std::time::Duration::from_millis(20))
269///     .slot_count(1024)
270///     .command_channel_capacity(1024)
271///     .build()
272///     .unwrap();
273/// ```
274#[derive(Debug, Clone)]
275pub struct TimerConfig {
276    /// 时间轮配置
277    pub wheel: WheelConfig,
278    /// 服务配置
279    pub service: ServiceConfig,
280    /// 批处理配置
281    pub batch: BatchConfig,
282}
283
284impl Default for TimerConfig {
285    fn default() -> Self {
286        Self {
287            wheel: WheelConfig::default(),
288            service: ServiceConfig::default(),
289            batch: BatchConfig::default(),
290        }
291    }
292}
293
294impl TimerConfig {
295    /// 创建配置构建器
296    pub fn builder() -> TimerConfigBuilder {
297        TimerConfigBuilder::default()
298    }
299}
300
301/// 顶层定时器配置构建器
302#[derive(Debug)]
303pub struct TimerConfigBuilder {
304    wheel_builder: WheelConfigBuilder,
305    service_builder: ServiceConfigBuilder,
306    batch_config: BatchConfig,
307}
308
309impl Default for TimerConfigBuilder {
310    fn default() -> Self {
311        Self {
312            wheel_builder: WheelConfigBuilder::default(),
313            service_builder: ServiceConfigBuilder::default(),
314            batch_config: BatchConfig::default(),
315        }
316    }
317}
318
319impl TimerConfigBuilder {
320    /// 设置 tick 时长
321    pub fn tick_duration(mut self, duration: Duration) -> Self {
322        self.wheel_builder = self.wheel_builder.tick_duration(duration);
323        self
324    }
325
326    /// 设置槽位数量
327    pub fn slot_count(mut self, count: usize) -> Self {
328        self.wheel_builder = self.wheel_builder.slot_count(count);
329        self
330    }
331
332    /// 设置命令通道容量
333    pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
334        self.service_builder = self.service_builder.command_channel_capacity(capacity);
335        self
336    }
337
338    /// 设置超时通道容量
339    pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
340        self.service_builder = self.service_builder.timeout_channel_capacity(capacity);
341        self
342    }
343
344    /// 设置小批量阈值
345    pub fn small_batch_threshold(mut self, threshold: usize) -> Self {
346        self.batch_config.small_batch_threshold = threshold;
347        self
348    }
349
350    /// 构建配置并进行验证
351    ///
352    /// # 返回
353    /// - `Ok(TimerConfig)`: 配置有效
354    /// - `Err(TimerError)`: 配置验证失败
355    pub fn build(self) -> Result<TimerConfig, TimerError> {
356        Ok(TimerConfig {
357            wheel: self.wheel_builder.build()?,
358            service: self.service_builder.build()?,
359            batch: self.batch_config,
360        })
361    }
362}
363
364#[cfg(test)]
365mod tests {
366    use super::*;
367
368    #[test]
369    fn test_wheel_config_default() {
370        let config = WheelConfig::default();
371        assert_eq!(config.tick_duration, Duration::from_millis(10));
372        assert_eq!(config.slot_count, 512);
373    }
374
375    #[test]
376    fn test_wheel_config_builder() {
377        let config = WheelConfig::builder()
378            .tick_duration(Duration::from_millis(20))
379            .slot_count(1024)
380            .build()
381            .unwrap();
382
383        assert_eq!(config.tick_duration, Duration::from_millis(20));
384        assert_eq!(config.slot_count, 1024);
385    }
386
387    #[test]
388    fn test_wheel_config_validation_zero_tick() {
389        let result = WheelConfig::builder()
390            .tick_duration(Duration::ZERO)
391            .build();
392
393        assert!(result.is_err());
394    }
395
396    #[test]
397    fn test_wheel_config_validation_invalid_slot_count() {
398        let result = WheelConfig::builder()
399            .slot_count(100)
400            .build();
401
402        assert!(result.is_err());
403    }
404
405    #[test]
406    fn test_service_config_default() {
407        let config = ServiceConfig::default();
408        assert_eq!(config.command_channel_capacity, 512);
409        assert_eq!(config.timeout_channel_capacity, 1000);
410    }
411
412    #[test]
413    fn test_service_config_builder() {
414        let config = ServiceConfig::builder()
415            .command_channel_capacity(1024)
416            .timeout_channel_capacity(2000)
417            .build()
418            .unwrap();
419
420        assert_eq!(config.command_channel_capacity, 1024);
421        assert_eq!(config.timeout_channel_capacity, 2000);
422    }
423
424    #[test]
425    fn test_batch_config_default() {
426        let config = BatchConfig::default();
427        assert_eq!(config.small_batch_threshold, 10);
428    }
429
430    #[test]
431    fn test_timer_config_default() {
432        let config = TimerConfig::default();
433        assert_eq!(config.wheel.slot_count, 512);
434        assert_eq!(config.service.command_channel_capacity, 512);
435        assert_eq!(config.batch.small_batch_threshold, 10);
436    }
437
438    #[test]
439    fn test_timer_config_builder() {
440        let config = TimerConfig::builder()
441            .tick_duration(Duration::from_millis(20))
442            .slot_count(1024)
443            .command_channel_capacity(1024)
444            .timeout_channel_capacity(2000)
445            .small_batch_threshold(20)
446            .build()
447            .unwrap();
448
449        assert_eq!(config.wheel.tick_duration, Duration::from_millis(20));
450        assert_eq!(config.wheel.slot_count, 1024);
451        assert_eq!(config.service.command_channel_capacity, 1024);
452        assert_eq!(config.service.timeout_channel_capacity, 2000);
453        assert_eq!(config.batch.small_batch_threshold, 20);
454    }
455}
456