1use crate::error::TimerError;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
25pub struct HierarchicalWheelConfig {
26 pub l0_tick_duration: Duration,
28 pub l0_slot_count: usize,
30
31 pub l1_tick_duration: Duration,
33 pub l1_slot_count: usize,
35}
36
37impl Default for HierarchicalWheelConfig {
38 fn default() -> Self {
39 Self {
40 l0_tick_duration: Duration::from_millis(10),
41 l0_slot_count: 512,
42 l1_tick_duration: Duration::from_secs(1),
43 l1_slot_count: 64,
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
70pub struct WheelConfig {
71 pub hierarchical: HierarchicalWheelConfig,
73}
74
75impl Default for WheelConfig {
76 fn default() -> Self {
77 Self {
78 hierarchical: HierarchicalWheelConfig::default(),
79 }
80 }
81}
82
83impl WheelConfig {
84 pub fn builder() -> WheelConfigBuilder {
86 WheelConfigBuilder::default()
87 }
88}
89
90#[derive(Debug, Clone)]
92pub struct WheelConfigBuilder {
93 hierarchical: HierarchicalWheelConfig,
94}
95
96impl Default for WheelConfigBuilder {
97 fn default() -> Self {
98 Self {
99 hierarchical: HierarchicalWheelConfig::default(),
100 }
101 }
102}
103
104impl WheelConfigBuilder {
105 pub fn l0_tick_duration(mut self, duration: Duration) -> Self {
107 self.hierarchical.l0_tick_duration = duration;
108 self
109 }
110
111 pub fn l0_slot_count(mut self, count: usize) -> Self {
113 self.hierarchical.l0_slot_count = count;
114 self
115 }
116
117 pub fn l1_tick_duration(mut self, duration: Duration) -> Self {
119 self.hierarchical.l1_tick_duration = duration;
120 self
121 }
122
123 pub fn l1_slot_count(mut self, count: usize) -> Self {
125 self.hierarchical.l1_slot_count = count;
126 self
127 }
128
129 pub fn build(self) -> Result<WheelConfig, TimerError> {
142 let h = &self.hierarchical;
143
144 if h.l0_tick_duration.is_zero() {
146 return Err(TimerError::InvalidConfiguration {
147 field: "l0_tick_duration".to_string(),
148 reason: "L0 层 tick 时长必须大于 0".to_string(),
149 });
150 }
151
152 if h.l0_slot_count == 0 {
153 return Err(TimerError::InvalidSlotCount {
154 slot_count: h.l0_slot_count,
155 reason: "L0 层槽位数量必须大于 0",
156 });
157 }
158
159 if !h.l0_slot_count.is_power_of_two() {
160 return Err(TimerError::InvalidSlotCount {
161 slot_count: h.l0_slot_count,
162 reason: "L0 层槽位数量必须是 2 的幂次方",
163 });
164 }
165
166 if h.l1_tick_duration.is_zero() {
168 return Err(TimerError::InvalidConfiguration {
169 field: "l1_tick_duration".to_string(),
170 reason: "L1 层 tick 时长必须大于 0".to_string(),
171 });
172 }
173
174 if h.l1_slot_count == 0 {
175 return Err(TimerError::InvalidSlotCount {
176 slot_count: h.l1_slot_count,
177 reason: "L1 层槽位数量必须大于 0",
178 });
179 }
180
181 if !h.l1_slot_count.is_power_of_two() {
182 return Err(TimerError::InvalidSlotCount {
183 slot_count: h.l1_slot_count,
184 reason: "L1 层槽位数量必须是 2 的幂次方",
185 });
186 }
187
188 let l0_ms = h.l0_tick_duration.as_millis() as u64;
190 let l1_ms = h.l1_tick_duration.as_millis() as u64;
191 if l1_ms % l0_ms != 0 {
192 return Err(TimerError::InvalidConfiguration {
193 field: "l1_tick_duration".to_string(),
194 reason: format!(
195 "L1 tick 时长 ({} ms) 必须是 L0 tick 时长 ({} ms) 的整数倍",
196 l1_ms, l0_ms
197 ),
198 });
199 }
200
201 Ok(WheelConfig {
202 hierarchical: self.hierarchical,
203 })
204 }
205}
206
207#[derive(Debug, Clone)]
226pub struct ServiceConfig {
227 pub command_channel_capacity: usize,
229 pub timeout_channel_capacity: usize,
231}
232
233impl Default for ServiceConfig {
234 fn default() -> Self {
235 Self {
236 command_channel_capacity: 512,
237 timeout_channel_capacity: 1000,
238 }
239 }
240}
241
242impl ServiceConfig {
243 pub fn builder() -> ServiceConfigBuilder {
245 ServiceConfigBuilder::default()
246 }
247}
248
249#[derive(Debug, Clone)]
251pub struct ServiceConfigBuilder {
252 command_channel_capacity: usize,
253 timeout_channel_capacity: usize,
254}
255
256impl Default for ServiceConfigBuilder {
257 fn default() -> Self {
258 let config = ServiceConfig::default();
259 Self {
260 command_channel_capacity: config.command_channel_capacity,
261 timeout_channel_capacity: config.timeout_channel_capacity,
262 }
263 }
264}
265
266impl ServiceConfigBuilder {
267 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
269 self.command_channel_capacity = capacity;
270 self
271 }
272
273 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
275 self.timeout_channel_capacity = capacity;
276 self
277 }
278
279 pub fn build(self) -> Result<ServiceConfig, TimerError> {
288 if self.command_channel_capacity == 0 {
289 return Err(TimerError::InvalidConfiguration {
290 field: "command_channel_capacity".to_string(),
291 reason: "命令通道容量必须大于 0".to_string(),
292 });
293 }
294
295 if self.timeout_channel_capacity == 0 {
296 return Err(TimerError::InvalidConfiguration {
297 field: "timeout_channel_capacity".to_string(),
298 reason: "超时通道容量必须大于 0".to_string(),
299 });
300 }
301
302 Ok(ServiceConfig {
303 command_channel_capacity: self.command_channel_capacity,
304 timeout_channel_capacity: self.timeout_channel_capacity,
305 })
306 }
307}
308
309#[derive(Debug, Clone)]
326pub struct BatchConfig {
327 pub small_batch_threshold: usize,
331}
332
333impl Default for BatchConfig {
334 fn default() -> Self {
335 Self {
336 small_batch_threshold: 10,
337 }
338 }
339}
340
341#[derive(Debug, Clone)]
360pub struct TimerConfig {
361 pub wheel: WheelConfig,
363 pub service: ServiceConfig,
365 pub batch: BatchConfig,
367}
368
369impl Default for TimerConfig {
370 fn default() -> Self {
371 Self {
372 wheel: WheelConfig::default(),
373 service: ServiceConfig::default(),
374 batch: BatchConfig::default(),
375 }
376 }
377}
378
379impl TimerConfig {
380 pub fn builder() -> TimerConfigBuilder {
382 TimerConfigBuilder::default()
383 }
384}
385
386#[derive(Debug)]
388pub struct TimerConfigBuilder {
389 wheel_builder: WheelConfigBuilder,
390 service_builder: ServiceConfigBuilder,
391 batch_config: BatchConfig,
392}
393
394impl Default for TimerConfigBuilder {
395 fn default() -> Self {
396 Self {
397 wheel_builder: WheelConfigBuilder::default(),
398 service_builder: ServiceConfigBuilder::default(),
399 batch_config: BatchConfig::default(),
400 }
401 }
402}
403
404impl TimerConfigBuilder {
405 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
407 self.service_builder = self.service_builder.command_channel_capacity(capacity);
408 self
409 }
410
411 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
413 self.service_builder = self.service_builder.timeout_channel_capacity(capacity);
414 self
415 }
416
417 pub fn small_batch_threshold(mut self, threshold: usize) -> Self {
419 self.batch_config.small_batch_threshold = threshold;
420 self
421 }
422
423 pub fn build(self) -> Result<TimerConfig, TimerError> {
429 Ok(TimerConfig {
430 wheel: self.wheel_builder.build()?,
431 service: self.service_builder.build()?,
432 batch: self.batch_config,
433 })
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn test_wheel_config_default() {
443 let config = WheelConfig::default();
444 assert_eq!(config.hierarchical.l0_tick_duration, Duration::from_millis(10));
445 assert_eq!(config.hierarchical.l0_slot_count, 512);
446 assert_eq!(config.hierarchical.l1_tick_duration, Duration::from_secs(1));
447 assert_eq!(config.hierarchical.l1_slot_count, 64);
448 }
449
450 #[test]
451 fn test_wheel_config_builder() {
452 let config = WheelConfig::builder()
453 .l0_tick_duration(Duration::from_millis(20))
454 .l0_slot_count(1024)
455 .l1_tick_duration(Duration::from_secs(2))
456 .l1_slot_count(128)
457 .build()
458 .unwrap();
459
460 assert_eq!(config.hierarchical.l0_tick_duration, Duration::from_millis(20));
461 assert_eq!(config.hierarchical.l0_slot_count, 1024);
462 assert_eq!(config.hierarchical.l1_tick_duration, Duration::from_secs(2));
463 assert_eq!(config.hierarchical.l1_slot_count, 128);
464 }
465
466 #[test]
467 fn test_wheel_config_validation_zero_tick() {
468 let result = WheelConfig::builder()
469 .l0_tick_duration(Duration::ZERO)
470 .build();
471
472 assert!(result.is_err());
473 }
474
475 #[test]
476 fn test_wheel_config_validation_invalid_slot_count() {
477 let result = WheelConfig::builder()
478 .l0_slot_count(100)
479 .build();
480
481 assert!(result.is_err());
482 }
483
484 #[test]
485 fn test_service_config_default() {
486 let config = ServiceConfig::default();
487 assert_eq!(config.command_channel_capacity, 512);
488 assert_eq!(config.timeout_channel_capacity, 1000);
489 }
490
491 #[test]
492 fn test_service_config_builder() {
493 let config = ServiceConfig::builder()
494 .command_channel_capacity(1024)
495 .timeout_channel_capacity(2000)
496 .build()
497 .unwrap();
498
499 assert_eq!(config.command_channel_capacity, 1024);
500 assert_eq!(config.timeout_channel_capacity, 2000);
501 }
502
503 #[test]
504 fn test_batch_config_default() {
505 let config = BatchConfig::default();
506 assert_eq!(config.small_batch_threshold, 10);
507 }
508
509 #[test]
510 fn test_timer_config_default() {
511 let config = TimerConfig::default();
512 assert_eq!(config.wheel.hierarchical.l0_slot_count, 512);
513 assert_eq!(config.service.command_channel_capacity, 512);
514 assert_eq!(config.batch.small_batch_threshold, 10);
515 }
516
517 #[test]
518 fn test_timer_config_builder() {
519 let config = TimerConfig::builder()
520 .command_channel_capacity(1024)
521 .timeout_channel_capacity(2000)
522 .small_batch_threshold(20)
523 .build()
524 .unwrap();
525
526 assert_eq!(config.service.command_channel_capacity, 1024);
527 assert_eq!(config.service.timeout_channel_capacity, 2000);
528 assert_eq!(config.batch.small_batch_threshold, 20);
529 }
530}
531