kestrel_timer/
config.rs

1//! Timer Configuration Module
2//!
3//! Provides hierarchical configuration structure and Builder pattern for configuring timing wheel, service, and batch processing behavior.
4//!
5//! 定时器配置模块,提供分层的配置结构和 Builder 模式,用于配置时间轮、服务和批处理行为。
6use crate::error::TimerError;
7use std::time::Duration;
8
9/// Timing Wheel Configuration
10///
11/// Used to configure parameters for hierarchical timing wheel. The system only supports hierarchical mode.
12///
13/// # 时间轮配置
14/// 
15/// 用于配置分层时间轮的参数。系统只支持分层模式。
16/// 
17/// # Examples (示例)
18/// ```no_run
19/// use kestrel_timer::config::WheelConfig;
20/// use std::time::Duration;
21///
22/// // Use default configuration (使用默认配置,分层模式)
23/// let config = WheelConfig::default();
24///
25/// // Use Builder to customize configuration (使用 Builder 自定义配置)
26/// let config = WheelConfig::builder()
27///     .l0_tick_duration(Duration::from_millis(20))
28///     .l0_slot_count(1024)
29///     .l1_tick_duration(Duration::from_secs(2))
30///     .l1_slot_count(128)
31///     .build()
32///     .unwrap();
33/// ```
34#[derive(Debug, Clone)]
35pub struct WheelConfig {
36    /// Duration of each tick in L0 layer, bottom layer
37    /// 
38    /// L0 层每个 tick 的持续时间
39    pub l0_tick_duration: Duration,
40    
41    /// Number of slots in L0 layer, must be power of 2
42    /// 
43    /// L0 层槽位数,必须是 2 的幂
44    pub l0_slot_count: usize,
45    
46    /// Duration of each tick in L1 layer, upper layer
47    /// 
48    /// L1 层每个 tick 的持续时间
49    pub l1_tick_duration: Duration,
50
51    /// Number of slots in L1 layer, must be power of 2
52    /// 
53    /// L1 层槽位数,必须是 2 的幂
54    pub l1_slot_count: usize,
55}
56
57impl Default for WheelConfig {
58    fn default() -> Self {
59        Self {
60            l0_tick_duration: Duration::from_millis(10),
61            l0_slot_count: 512,
62            l1_tick_duration: Duration::from_secs(1),
63            l1_slot_count: 64,
64        }
65    }
66}
67
68impl WheelConfig {
69    /// Create configuration builder (创建配置构建器)
70    pub fn builder() -> WheelConfigBuilder {
71        WheelConfigBuilder::default()
72    }
73}
74
75/// Timing Wheel Configuration Builder
76#[derive(Debug, Clone)]
77pub struct WheelConfigBuilder {
78    l0_tick_duration: Duration,
79    l0_slot_count: usize,
80    l1_tick_duration: Duration,
81    l1_slot_count: usize,
82}
83
84impl Default for WheelConfigBuilder {
85    fn default() -> Self {
86        Self {
87            l0_tick_duration: Duration::from_millis(10),
88            l0_slot_count: 512,
89            l1_tick_duration: Duration::from_secs(1),
90            l1_slot_count: 64,
91        }
92    }
93}
94
95impl WheelConfigBuilder {
96    /// Set L0 layer tick duration
97    pub fn l0_tick_duration(mut self, duration: Duration) -> Self {
98        self.l0_tick_duration = duration;
99        self
100    }
101
102    /// Set L0 layer slot count
103    pub fn l0_slot_count(mut self, count: usize) -> Self {
104        self.l0_slot_count = count;
105        self
106    }
107
108    /// Set L1 layer tick duration
109    pub fn l1_tick_duration(mut self, duration: Duration) -> Self {
110        self.l1_tick_duration = duration;
111        self
112    }
113
114    /// Set L1 layer slot count
115    pub fn l1_slot_count(mut self, count: usize) -> Self {
116        self.l1_slot_count = count;
117        self
118    }
119
120    /// Build and validate configuration
121    ///
122    /// # Returns
123    /// - `Ok(WheelConfig)`: Configuration is valid
124    /// - `Err(TimerError)`: Configuration validation failed
125    ///
126    /// # Validation Rules
127    /// - L0 tick duration must be greater than 0
128    /// - L1 tick duration must be greater than 0
129    /// - L0 slot count must be greater than 0 and power of 2
130    /// - L1 slot count must be greater than 0 and power of 2
131    /// - L1 tick must be an integer multiple of L0 tick
132    pub fn build(self) -> Result<WheelConfig, TimerError> {
133        // Validate L0 layer configuration
134        if self.l0_tick_duration.is_zero() {
135            return Err(TimerError::InvalidConfiguration {
136                field: "l0_tick_duration".to_string(),
137                reason: "L0 layer tick duration must be greater than 0".to_string(),
138            });
139        }
140
141        if self.l0_slot_count == 0 {
142            return Err(TimerError::InvalidSlotCount {
143                slot_count: self.l0_slot_count,
144                reason: "L0 layer slot count must be greater than 0",
145            });
146        }
147
148        if !self.l0_slot_count.is_power_of_two() {
149            return Err(TimerError::InvalidSlotCount {
150                slot_count: self.l0_slot_count,
151                reason: "L0 layer slot count must be power of 2",
152            });
153        }
154
155        // Validate L1 layer configuration
156        if self.l1_tick_duration.is_zero() {
157            return Err(TimerError::InvalidConfiguration {
158                field: "l1_tick_duration".to_string(),
159                reason: "L1 layer tick duration must be greater than 0".to_string(),
160            });
161        }
162
163        if self.l1_slot_count == 0 {
164            return Err(TimerError::InvalidSlotCount {
165                slot_count: self.l1_slot_count,
166                reason: "L1 layer slot count must be greater than 0",
167            });
168        }
169
170        if !self.l1_slot_count.is_power_of_two() {
171            return Err(TimerError::InvalidSlotCount {
172                slot_count: self.l1_slot_count,
173                reason: "L1 layer slot count must be power of 2",
174            });
175        }
176
177        // Validate L1 tick is an integer multiple of L0 tick
178        let l0_ms = self.l0_tick_duration.as_millis() as u64;
179        let l1_ms = self.l1_tick_duration.as_millis() as u64;
180        if l1_ms % l0_ms != 0 {
181            return Err(TimerError::InvalidConfiguration {
182                field: "l1_tick_duration".to_string(),
183                reason: format!(
184                    "L1 tick duration ({} ms) must be an integer multiple of L0 tick duration ({} ms)",
185                    l1_ms, l0_ms
186                ),
187            });
188        }
189
190        Ok(WheelConfig {
191            l0_tick_duration: self.l0_tick_duration,
192            l0_slot_count: self.l0_slot_count,
193            l1_tick_duration: self.l1_tick_duration,
194            l1_slot_count: self.l1_slot_count,
195        })
196    }
197}
198
199/// Service Configuration
200///
201/// Used to configure channel capacities for TimerService.
202///
203/// # 服务配置
204/// 
205/// 用于配置 TimerService 的通道容量。
206/// 
207/// # Examples (示例)
208/// ```no_run
209/// use kestrel_timer::config::ServiceConfig;
210///
211/// // Use default configuration (使用默认配置)
212/// let config = ServiceConfig::default();
213///
214/// // Use Builder to customize configuration (使用 Builder 自定义配置)
215/// let config = ServiceConfig::builder()
216///     .command_channel_capacity(1024)
217///     .timeout_channel_capacity(2000)
218///     .build()
219///     .unwrap();
220/// ```
221#[derive(Debug, Clone)]
222pub struct ServiceConfig {
223    /// Command channel capacity 
224    /// 
225    /// 命令通道容量
226    pub command_channel_capacity: usize,
227
228    /// Timeout channel capacity
229    /// 
230    /// 超时通道容量
231    pub timeout_channel_capacity: usize,
232}
233
234impl Default for ServiceConfig {
235    fn default() -> Self {
236        Self {
237            command_channel_capacity: 512,
238            timeout_channel_capacity: 1000,
239        }
240    }
241}
242
243impl ServiceConfig {
244    /// Create configuration builder (创建配置构建器)
245    pub fn builder() -> ServiceConfigBuilder {
246        ServiceConfigBuilder::default()
247    }
248}
249
250/// Service Configuration Builder 
251/// 
252/// 用于构建 ServiceConfig 的构建器。
253#[derive(Debug, Clone)]
254pub struct ServiceConfigBuilder {
255    /// Command channel capacity
256    /// 
257    /// 命令通道容量
258    pub command_channel_capacity: usize,
259    
260    /// Timeout channel capacity
261    /// 
262    /// 超时通道容量
263    pub timeout_channel_capacity: usize,
264}
265
266impl Default for ServiceConfigBuilder {
267    fn default() -> Self {
268        let config = ServiceConfig::default();
269        Self {
270            command_channel_capacity: config.command_channel_capacity,
271            timeout_channel_capacity: config.timeout_channel_capacity,
272        }
273    }
274}
275
276impl ServiceConfigBuilder {
277    /// Set command channel capacity (设置命令通道容量)
278    pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
279        self.command_channel_capacity = capacity;
280        self
281    }
282
283    /// Set timeout channel capacity (设置超时通道容量)
284    pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
285        self.timeout_channel_capacity = capacity;
286        self
287    }
288
289    /// Build and validate configuration
290    ///
291    /// # Returns
292    /// - `Ok(ServiceConfig)`: Configuration is valid
293    /// - `Err(TimerError)`: Configuration validation failed
294    ///
295    /// # Validation Rules
296    /// - All channel capacities must be greater than 0
297    /// 
298    /// 构建并验证配置
299    /// 
300    /// # 返回值
301    /// - `Ok(ServiceConfig)`: 配置有效
302    /// - `Err(TimerError)`: 配置验证失败
303    /// 
304    /// # 验证规则
305    /// - 所有通道容量必须大于 0
306    /// 
307    pub fn build(self) -> Result<ServiceConfig, TimerError> {
308        if self.command_channel_capacity == 0 {
309            return Err(TimerError::InvalidConfiguration {
310                field: "command_channel_capacity".to_string(),
311                reason: "Command channel capacity must be greater than 0 (命令通道容量必须大于 0)".to_string(),
312            });
313        }
314
315        if self.timeout_channel_capacity == 0 {
316            return Err(TimerError::InvalidConfiguration {
317                field: "timeout_channel_capacity".to_string(),
318                reason: "Timeout channel capacity must be greater than 0 (超时通道容量必须大于 0)".to_string(),
319            });
320        }
321
322        Ok(ServiceConfig {
323            command_channel_capacity: self.command_channel_capacity,
324            timeout_channel_capacity: self.timeout_channel_capacity,
325        })
326    }
327}
328
329/// Batch Processing Configuration
330///
331/// Used to configure optimization parameters for batch operations.
332/// 
333/// 用于配置批处理操作的优化参数。
334/// 
335/// # 批处理配置
336/// 
337/// 用于配置批处理操作的优化参数。
338///
339/// # Examples (示例)
340/// ```no_run
341/// use kestrel_timer::config::BatchConfig;
342///
343/// // Use default configuration (使用默认配置)
344/// let config = BatchConfig::default();
345///
346/// // Custom configuration (使用自定义配置)
347/// let config = BatchConfig {
348///     small_batch_threshold: 20,
349/// };
350/// ```
351#[derive(Debug, Clone)]
352pub struct BatchConfig {
353    /// Small batch threshold, used for batch cancellation optimization
354    /// When the number of tasks to be cancelled is less than or equal to this value, cancel individually without grouping and sorting
355    /// 
356    /// 小批量阈值,用于批量取消操作的优化
357    /// 
358    /// 当需要取消的任务数量小于或等于此值时,取消操作将单独进行,无需分组和排序
359    pub small_batch_threshold: usize,
360}
361
362impl Default for BatchConfig {
363    fn default() -> Self {
364        Self {
365            small_batch_threshold: 10,
366        }
367    }
368}
369
370/// Top-level Timer Configuration
371///
372/// Combines all sub-configurations to provide complete timer system configuration.
373///
374/// # 定时器配置
375/// 
376/// 用于组合所有子配置,提供完整的定时器系统配置。
377/// 
378/// # Examples (示例)
379/// ```no_run
380/// use kestrel_timer::config::TimerConfig;
381///
382/// // Use default configuration (使用默认配置)
383/// let config = TimerConfig::default();
384///
385/// // Use Builder to customize configuration, service parameters only
386/// // (使用 Builder 自定义配置,仅配置服务参数)
387/// let config = TimerConfig::builder()
388///     .command_channel_capacity(1024)
389///     .timeout_channel_capacity(2000)
390///     .build()
391///     .unwrap();
392/// ```
393#[derive(Debug, Clone)]
394pub struct TimerConfig {
395    /// Timing wheel configuration
396    pub wheel: WheelConfig,
397    /// Service configuration
398    pub service: ServiceConfig,
399    /// Batch processing configuration
400    pub batch: BatchConfig,
401}
402
403impl Default for TimerConfig {
404    fn default() -> Self {
405        Self {
406            wheel: WheelConfig::default(),
407            service: ServiceConfig::default(),
408            batch: BatchConfig::default(),
409        }
410    }
411}
412
413impl TimerConfig {
414    /// Create configuration builder (创建配置构建器)
415    pub fn builder() -> TimerConfigBuilder {
416        TimerConfigBuilder::default()
417    }
418}
419
420/// Top-level Timer Configuration Builder (顶级定时器配置构建器)
421/// 
422/// 用于构建 TimerConfig 的构建器。
423#[derive(Debug)]
424pub struct TimerConfigBuilder {
425    wheel_builder: WheelConfigBuilder,
426    service_builder: ServiceConfigBuilder,
427    batch_config: BatchConfig,
428}
429
430impl Default for TimerConfigBuilder {
431    fn default() -> Self {
432        Self {
433            wheel_builder: WheelConfigBuilder::default(),
434            service_builder: ServiceConfigBuilder::default(),
435            batch_config: BatchConfig::default(),
436        }
437    }
438}
439
440impl TimerConfigBuilder {
441    /// Set command channel capacity (设置命令通道容量)
442    pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
443        self.service_builder = self.service_builder.command_channel_capacity(capacity);
444        self
445    }
446
447    /// Set timeout channel capacity (设置超时通道容量)
448    pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
449        self.service_builder = self.service_builder.timeout_channel_capacity(capacity);
450        self
451    }
452
453    /// Set small batch threshold (设置小批量阈值)
454    pub fn small_batch_threshold(mut self, threshold: usize) -> Self {
455        self.batch_config.small_batch_threshold = threshold;
456        self
457    }
458
459    /// Build and validate configuration
460    ///
461    /// # Returns
462    /// - `Ok(TimerConfig)`: Configuration is valid
463    /// - `Err(TimerError)`: Configuration validation failed
464    /// 
465    /// # 构建并验证配置
466    /// 
467    /// # 返回值
468    /// - `Ok(TimerConfig)`: 配置有效
469    /// - `Err(TimerError)`: 配置验证失败
470    /// 
471    pub fn build(self) -> Result<TimerConfig, TimerError> {
472        Ok(TimerConfig {
473            wheel: self.wheel_builder.build()?,
474            service: self.service_builder.build()?,
475            batch: self.batch_config,
476        })
477    }
478}
479
480#[cfg(test)]
481mod tests {
482    use super::*;
483
484    #[test]
485    fn test_wheel_config_default() {
486        let config = WheelConfig::default();
487        assert_eq!(config.l0_tick_duration, Duration::from_millis(10));
488        assert_eq!(config.l0_slot_count, 512);
489        assert_eq!(config.l1_tick_duration, Duration::from_secs(1));
490        assert_eq!(config.l1_slot_count, 64);
491    }
492
493    #[test]
494    fn test_wheel_config_builder() {
495        let config = WheelConfig::builder()
496            .l0_tick_duration(Duration::from_millis(20))
497            .l0_slot_count(1024)
498            .l1_tick_duration(Duration::from_secs(2))
499            .l1_slot_count(128)
500            .build()
501            .unwrap();
502
503        assert_eq!(config.l0_tick_duration, Duration::from_millis(20));
504        assert_eq!(config.l0_slot_count, 1024);
505        assert_eq!(config.l1_tick_duration, Duration::from_secs(2));
506        assert_eq!(config.l1_slot_count, 128);
507    }
508
509    #[test]
510    fn test_wheel_config_validation_zero_tick() {
511        let result = WheelConfig::builder()
512            .l0_tick_duration(Duration::ZERO)
513            .build();
514
515        assert!(result.is_err());
516    }
517
518    #[test]
519    fn test_wheel_config_validation_invalid_slot_count() {
520        let result = WheelConfig::builder()
521            .l0_slot_count(100)
522            .build();
523
524        assert!(result.is_err());
525    }
526
527    #[test]
528    fn test_service_config_default() {
529        let config = ServiceConfig::default();
530        assert_eq!(config.command_channel_capacity, 512);
531        assert_eq!(config.timeout_channel_capacity, 1000);
532    }
533
534    #[test]
535    fn test_service_config_builder() {
536        let config = ServiceConfig::builder()
537            .command_channel_capacity(1024)
538            .timeout_channel_capacity(2000)
539            .build()
540            .unwrap();
541
542        assert_eq!(config.command_channel_capacity, 1024);
543        assert_eq!(config.timeout_channel_capacity, 2000);
544    }
545
546    #[test]
547    fn test_batch_config_default() {
548        let config = BatchConfig::default();
549        assert_eq!(config.small_batch_threshold, 10);
550    }
551
552    #[test]
553    fn test_timer_config_default() {
554        let config = TimerConfig::default();
555        assert_eq!(config.wheel.l0_slot_count, 512);
556        assert_eq!(config.service.command_channel_capacity, 512);
557        assert_eq!(config.batch.small_batch_threshold, 10);
558    }
559
560    #[test]
561    fn test_timer_config_builder() {
562        let config = TimerConfig::builder()
563            .command_channel_capacity(1024)
564            .timeout_channel_capacity(2000)
565            .small_batch_threshold(20)
566            .build()
567            .unwrap();
568
569        assert_eq!(config.service.command_channel_capacity, 1024);
570        assert_eq!(config.service.timeout_channel_capacity, 2000);
571        assert_eq!(config.batch.small_batch_threshold, 20);
572    }
573}
574