zenith-runtime 0.1.0

Zenith 全链路数据面运行时:WorkerRuntime(eBPF + XSK + Worker 集成)、三级 Supervisor、ChangeSet 热切换、RuntimeGraph 拓扑规划
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
//! 运行期自动优化系统
//!
//! 提供三大自动优化能力:
//! 1. 运行期重规划 - 基于负载变化自动重新计算最优拓扑
//! 2. 自适应 QoS - 动态调整任务优先级与资源分配
//! 3. 缓存预测预热 - 基于访问模式预测热点数据并主动加载
//!
//! # 极致性能优化
//! - 使用 FxHashMap 替代 std HashMap(对小键哈希快 ~5x,规范 §6.1.1)
//! - 键使用 `Box<str>` 替代 `String`(节省 8 字节容量字段,零堆开销增长)
//! - `predict_warmup` 返回 `Vec<Box<str>>`,Clone 零成本(仅指针拷贝)

use std::collections::VecDeque;
use std::sync::atomic::{AtomicU8, AtomicU64, Ordering};
use std::sync::{Arc, RwLock};
use std::time::Instant;

// 极致性能:FxHash 对小字符串键比 SipHash 快 ~5x
use rustc_hash::FxHashMap;

const MAX_HISTORY: usize = 256;
const DEFAULT_QOS_WINDOW_MS: u64 = 1000;

/// 服务质量等级,用于动态调整任务优先级与资源分配。
///
/// `#[repr(u8)]` + 显式判别值:数值即优先级(0 最高,4 最低),
/// 与 [`QosLevel::priority`] 的一致性由编译期断言锁定,
/// `as u8` 强转不再依赖枚举声明顺序。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum QosLevel {
    /// 关键级别:负载极高且持续上升,需最高优先级保障。
    Critical = 0,
    /// 高级别:负载较高,优先调度关键任务。
    High = 1,
    /// 常规级别:负载正常,按默认策略调度。
    Normal = 2,
    /// 低级别:负载较低,可适当降低资源占用。
    Low = 3,
    /// 后台级别:负载极低,仅在空闲时执行。
    Background = 4,
}

// 编译期锁定:priority() 数值必须与显式判别值一致(枚举强转脆弱性回归防护)
const _: () = {
    assert!(QosLevel::Critical.priority() == QosLevel::Critical as u8);
    assert!(QosLevel::High.priority() == QosLevel::High as u8);
    assert!(QosLevel::Normal.priority() == QosLevel::Normal as u8);
    assert!(QosLevel::Low.priority() == QosLevel::Low as u8);
    assert!(QosLevel::Background.priority() == QosLevel::Background as u8);
};

impl QosLevel {
    /// 将 QoS 等级转换为数值优先级(0 最高,4 最低)。
    ///
    /// 数值取自 `#[repr(u8)]` 显式判别值,与声明顺序解耦。
    pub const fn priority(&self) -> u8 {
        *self as u8
    }

    /// 获取 QoS 等级的静态名称(指标标签 / 日志用)。
    pub fn as_str(&self) -> &'static str {
        match self {
            QosLevel::Critical => "critical",
            QosLevel::High => "high",
            QosLevel::Normal => "normal",
            QosLevel::Low => "low",
            QosLevel::Background => "background",
        }
    }

    /// 将数值优先级转换回 QoS 等级,超出范围时回退到 [`QosLevel::Background`]。
    pub fn from_priority(p: u8) -> Self {
        match p {
            0 => QosLevel::Critical,
            1 => QosLevel::High,
            2 => QosLevel::Normal,
            3 => QosLevel::Low,
            _ => QosLevel::Background,
        }
    }

    /// 将 QoS 等级编码为 u8(用于 AtomicU8 无锁存储)。
    #[inline]
    pub fn to_u8(self) -> u8 {
        self.priority()
    }

    /// 从 u8 解码 QoS 等级,未知值回退到 [`QosLevel::Background`]。
    #[inline]
    pub fn from_u8(v: u8) -> Self {
        Self::from_priority(v)
    }
}

/// 单次负载采样快照,记录某一时刻的系统负载指标。
#[derive(Debug, Clone, Copy)]
pub struct LoadSample {
    /// 采样时间戳。
    pub timestamp: Instant,
    /// CPU 使用率(0.0 ~ 1.0)。
    pub cpu_usage: f64,
    /// 当前任务队列深度。
    pub queue_depth: u64,
    /// P99 延迟(毫秒)。
    pub latency_p99: u64,
    /// 吞吐量(请求数/秒)。
    pub throughput: u64,
}

/// 负载历史窗口,按定长环形缓冲保存最近的负载采样。
#[derive(Debug, Clone)]
pub struct LoadHistory {
    samples: VecDeque<LoadSample>,
    max_size: usize,
}

impl LoadHistory {
    /// 创建指定最大容量的负载历史窗口。
    pub fn new(max_size: usize) -> Self {
        Self {
            samples: VecDeque::with_capacity(max_size),
            max_size,
        }
    }

    /// 记录一条负载采样,超出容量时淘汰最早的样本。
    pub fn record(&mut self, sample: LoadSample) {
        if self.samples.len() >= self.max_size {
            self.samples.pop_front();
        }
        self.samples.push_back(sample);
    }

    /// 计算窗口内所有采样的平均 CPU 使用率,空窗口返回 0.0。
    pub fn avg_cpu(&self) -> f64 {
        if self.samples.is_empty() {
            return 0.0;
        }
        let sum: f64 = self.samples.iter().map(|s| s.cpu_usage).sum();
        sum / self.samples.len() as f64
    }

    /// 计算窗口内所有采样的平均 P99 延迟(毫秒),空窗口返回 0。
    pub fn avg_latency_p99(&self) -> u64 {
        if self.samples.is_empty() {
            return 0;
        }
        let sum: u64 = self.samples.iter().map(|s| s.latency_p99).sum();
        sum / self.samples.len() as u64
    }

    /// 返回窗口内最大的队列深度,空窗口返回 0。
    pub fn max_queue_depth(&self) -> u64 {
        self.samples.iter().map(|s| s.queue_depth).max().unwrap_or(0)
    }

    /// 计算窗口内所有采样的平均吞吐量,空窗口返回 0。
    pub fn avg_throughput(&self) -> u64 {
        if self.samples.is_empty() {
            return 0;
        }
        let sum: u64 = self.samples.iter().map(|s| s.throughput).sum();
        sum / self.samples.len() as u64
    }

    /// 根据前后半段 CPU 使用率均值差判断负载趋势。
    pub fn trend(&self) -> LoadTrend {
        if self.samples.len() < 4 {
            return LoadTrend::Stable;
        }
        let mid = self.samples.len() / 2;
        // 极致性能:直接迭代求和,避免 Vec<&LoadSample> 堆分配
        let (mut first_sum, mut first_cnt) = (0.0f64, 0usize);
        for s in self.samples.iter().take(mid) {
            first_sum += s.cpu_usage;
            first_cnt += 1;
        }
        let (mut second_sum, mut second_cnt) = (0.0f64, 0usize);
        for s in self.samples.iter().skip(mid) {
            second_sum += s.cpu_usage;
            second_cnt += 1;
        }
        let first_avg = if first_cnt > 0 { first_sum / first_cnt as f64 } else { 0.0 };
        let second_avg = if second_cnt > 0 { second_sum / second_cnt as f64 } else { 0.0 };

        let delta = second_avg - first_avg;
        if delta > 0.15 {
            LoadTrend::Increasing
        } else if delta < -0.15 {
            LoadTrend::Decreasing
        } else {
            LoadTrend::Stable
        }
    }

    /// 返回当前窗口中的采样数量。
    pub fn len(&self) -> usize {
        self.samples.len()
    }

    /// 判断窗口是否为空。
    pub fn is_empty(&self) -> bool {
        self.samples.is_empty()
    }
}

/// 负载变化趋势,由 [`LoadHistory::trend`] 推导。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoadTrend {
    /// 负载上升中。
    Increasing,
    /// 负载下降中。
    Decreasing,
    /// 负载保持稳定。
    Stable,
}

/// 自适应 QoS 控制器,依据负载历史动态调整服务质量等级。
///
/// # 极致性能优化
/// - `level` 使用 `AtomicU8` 存储,读/写零锁(§5.2 无锁数据结构)
/// - 阈值字段构造后不可变,通过 `Arc` 共享无需同步
/// - `evaluate()` 仅需 `&self`,可并发调用
pub struct AdaptiveQos {
    /// 当前 QoS 等级(AtomicU8,无锁读写)
    level: AtomicU8,
    /// 评估窗口时长(毫秒),构造后不可变
    window_ms: u64,
    /// CPU 使用率高阈值,构造后不可变
    cpu_high_threshold: f64,
    /// CPU 使用率低阈值,构造后不可变
    cpu_low_threshold: f64,
    /// 延迟高阈值(毫秒),构造后不可变
    latency_high_ms: u64,
    /// 延迟低阈值(毫秒),构造后不可变
    latency_low_ms: u64,
}

impl std::fmt::Debug for AdaptiveQos {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("AdaptiveQos")
            .field("level", &self.current_level())
            .field("window_ms", &self.window_ms)
            .field("cpu_high_threshold", &self.cpu_high_threshold)
            .field("cpu_low_threshold", &self.cpu_low_threshold)
            .field("latency_high_ms", &self.latency_high_ms)
            .field("latency_low_ms", &self.latency_low_ms)
            .finish()
    }
}

impl Clone for AdaptiveQos {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            level: AtomicU8::new(self.level.load(Ordering::Acquire)),
            window_ms: self.window_ms,
            cpu_high_threshold: self.cpu_high_threshold,
            cpu_low_threshold: self.cpu_low_threshold,
            latency_high_ms: self.latency_high_ms,
            latency_low_ms: self.latency_low_ms,
        }
    }
}

impl AdaptiveQos {
    /// 使用默认阈值创建自适应 QoS 控制器。
    pub fn new() -> Self {
        Self {
            level: AtomicU8::new(QosLevel::Normal.to_u8()),
            window_ms: DEFAULT_QOS_WINDOW_MS,
            cpu_high_threshold: 0.85,
            cpu_low_threshold: 0.30,
            latency_high_ms: 100,
            latency_low_ms: 10,
        }
    }

    /// 设置评估窗口时长(毫秒),返回修改后的构建器。
    pub fn with_window(mut self, ms: u64) -> Self {
        self.window_ms = ms;
        self
    }

    /// 设置 CPU 使用率的高低阈值,返回修改后的构建器。
    pub fn with_cpu_thresholds(mut self, low: f64, high: f64) -> Self {
        self.cpu_low_threshold = low;
        self.cpu_high_threshold = high;
        self
    }

    /// 设置延迟的高低阈值(毫秒),返回修改后的构建器。
    pub fn with_latency_thresholds(mut self, low_ms: u64, high_ms: u64) -> Self {
        self.latency_low_ms = low_ms;
        self.latency_high_ms = high_ms;
        self
    }

    /// 返回当前的服务质量等级(无锁原子读)。
    #[inline]
    pub fn current_level(&self) -> QosLevel {
        QosLevel::from_u8(self.level.load(Ordering::Acquire))
    }

    /// 手动设置当前 QoS 等级(无锁原子写)。
    #[inline]
    pub fn set_level(&self, level: QosLevel) {
        self.level.store(level.to_u8(), Ordering::Release);
    }

    /// 根据负载历史评估并更新当前 QoS 等级,返回评估后的新等级。
    ///
    /// 滞回阈值:升降采用不同阈值,避免在阈值附近振荡
    /// - UP (Normal→High): cpu > 0.85; DOWN (High→Normal): cpu < 0.75
    /// - DOWN (Normal→Low): cpu < 0.25; UP (Low→Normal): cpu > 0.35
    pub fn evaluate(&self, history: &LoadHistory) -> QosLevel {
        let avg_cpu = history.avg_cpu();
        let avg_latency = history.avg_latency_p99();
        let trend = history.trend();
        let current = self.current_level();

        // 滞回:当前处于高等级时用更低阈值判定回落,当前处于低等级时用更高阈值判定回升
        let high_threshold = match current {
            QosLevel::Critical | QosLevel::High => self.cpu_high_threshold - 0.10,
            _ => self.cpu_high_threshold,
        };
        let low_threshold = match current {
            QosLevel::Low | QosLevel::Background => self.cpu_low_threshold + 0.05,
            _ => self.cpu_low_threshold - 0.05,
        };

        let new_level = if avg_cpu > high_threshold || avg_latency > self.latency_high_ms {
            match trend {
                LoadTrend::Increasing => QosLevel::Critical,
                _ => QosLevel::High,
            }
        } else if avg_cpu > 0.60 || avg_latency > self.latency_low_ms * 2 {
            QosLevel::Normal
        } else if avg_cpu < low_threshold && avg_latency < self.latency_low_ms {
            QosLevel::Low
        } else {
            QosLevel::Normal
        };

        // 极致性能:AtomicU8 store,无锁写入
        self.level.store(new_level.to_u8(), Ordering::Release);
        new_level
    }

    /// 根据负载趋势与 CPU 使用率计算有效工作线程数。
    pub fn effective_worker_count(&self, current: usize, history: &LoadHistory) -> usize {
        let avg_cpu = history.avg_cpu();
        let trend = history.trend();

        match trend {
            LoadTrend::Increasing => {
                if avg_cpu > self.cpu_high_threshold {
                    current.saturating_mul(2)
                } else if avg_cpu > 0.70 {
                    current.saturating_add((current / 4).max(1))
                } else {
                    current
                }
            }
            LoadTrend::Decreasing => {
                if avg_cpu < self.cpu_low_threshold {
                    // SYS-006:单 worker(current=1)低负载时 `1/2=0` 返回 0 个 worker
                    //(非法下界)。`.max(1)` 保证至少保留 1 个 worker。
                    current.saturating_div(2).max(1)
                } else if avg_cpu < 0.40 {
                    current.saturating_sub((current / 4).max(1)).max(1)
                } else {
                    current
                }
            }
            LoadTrend::Stable => current,
        }
    }
}

impl Default for AdaptiveQos {
    fn default() -> Self {
        Self::new()
    }
}

/// 单个缓存键的访问模式,记录访问计数与热度预测。
#[derive(Debug, Clone)]
pub struct CacheAccessPattern {
    /// 使用 Box<str> 替代 String,节省 8 字节容量字段
    key: Box<str>,
    access_count: u64,
    last_access: Instant,
    predicted_hot: bool,
}

/// 缓存预热预测器,基于访问模式预测热点数据并主动加载。
#[derive(Debug)]
pub struct CacheWarmupPredictor {
    /// FxHashMap 对小键哈希比 SipHash 快 ~5x
    patterns: FxHashMap<Box<str>, CacheAccessPattern>,
    hot_threshold: u64,
    decay_factor: f64,
}

impl CacheWarmupPredictor {
    /// 使用默认配置创建缓存预热预测器。
    ///
    /// 默认 `hot_threshold = 10`:在默认衰减因子 `decay_factor = 0.95` 下,
    /// 步进更新 `count = round(count*0.95 + 1)` 的衰减不动点约为 20,
    /// 原默认阈值 100 高于不动点导致"默认永不触发预热"(SYS-005)。
    /// 阈值取 10(< 20)保证默认配置可实际触发预热。
    pub fn new() -> Self {
        Self {
            patterns: FxHashMap::default(),
            hot_threshold: 10,
            decay_factor: 0.95,
        }
    }

    /// 使用指定热度阈值创建缓存预热预测器。
    pub fn with_threshold(threshold: u64) -> Self {
        Self {
            patterns: FxHashMap::default(),
            hot_threshold: threshold,
            decay_factor: 0.95,
        }
    }

    /// 设置热度阈值,返回修改后的构建器。
    pub fn with_hot_threshold(mut self, threshold: u64) -> Self {
        self.hot_threshold = threshold;
        self
    }

    /// 设置访问计数衰减因子,返回修改后的构建器。
    pub fn with_decay_factor(mut self, factor: f64) -> Self {
        self.decay_factor = factor;
        self
    }

    /// 记录一次缓存键访问,按衰减因子更新访问计数与热度预测。
    pub fn record_access(&mut self, key: &str) {
        let now = Instant::now();
        if let Some(pattern) = self.patterns.get_mut(key) {
            pattern.access_count = (pattern.access_count as f64 * self.decay_factor + 1.0).round() as u64;
            pattern.last_access = now;
            pattern.predicted_hot = pattern.access_count >= self.hot_threshold;
        } else {
            // 极致性能:Box::from(&str) 比 String::from(&str) 省 8 字节容量字段
            let key_box: Box<str> = key.into();
            self.patterns.insert(key_box.clone(), CacheAccessPattern {
                key: key_box,
                access_count: 1,
                last_access: now,
                predicted_hot: false,
            });
        }
    }

    /// 返回按访问计数降序排列的热键引用列表。
    pub fn get_hot_keys(&self) -> Vec<&str> {
        // 极致性能:预提取 access_count 到元组,避免 sort 中 O(n log n) 次哈希查找
        let mut hot: Vec<(&str, u64)> = self.patterns
            .values()
            .filter(|p| p.predicted_hot)
            .map(|p| (&*p.key, p.access_count))
            .collect();
        hot.sort_unstable_by_key(|b| std::cmp::Reverse(b.1));
        hot.into_iter().map(|(s, _)| s).collect()
    }

    /// 返回热键列表(`Box<str>` Clone 零成本:仅指针+长度拷贝,无堆分配)
    pub fn predict_warmup(&self) -> Vec<Box<str>> {
        self.get_hot_keys()
            .into_iter()
            .map(|s| s.into())
            .collect()
    }

    /// 裁剪访问模式表,仅保留访问计数最高的 `max_patterns` 条记录。
    pub fn prune(&mut self, max_patterns: usize) {
        if self.patterns.len() <= max_patterns {
            return;
        }
        // 极致性能:drain 取出所有权,避免 clone 所有 (key, pattern) 对
        let mut entries: Vec<_> = self.patterns.drain().collect();
        entries.sort_unstable_by_key(|b| std::cmp::Reverse(b.1.access_count));
        entries.truncate(max_patterns);
        self.patterns = entries.into_iter().collect();
    }

    /// 返回当前记录的访问模式数量。
    pub fn pattern_count(&self) -> usize {
        self.patterns.len()
    }
}

impl Default for CacheWarmupPredictor {
    fn default() -> Self {
        Self::new()
    }
}

/// 自动优化器,集成负载历史、自适应 QoS 与缓存预热预测。
///
/// # 极致性能优化
/// - QoS 控制器使用 `Arc<AdaptiveQos>`(不可变 Arc + AtomicU8 level),无 RwLock 竞争
/// - `current_qos_level()` / `set_qos_level()` 完全无锁
/// - `evaluate_qos()` / `get_optimal_worker_count()` 仅需 `history.read()` 单锁
#[derive(Debug)]
pub struct AutoOptimizer {
    history: Arc<RwLock<LoadHistory>>,
    /// QoS 控制器:阈值不可变(Arc 共享),level 通过 AtomicU8 无锁读写
    qos: Arc<AdaptiveQos>,
    predictor: Arc<RwLock<CacheWarmupPredictor>>,
    replan_countdown: AtomicU64,
    replan_interval_ms: u64,
}

impl AutoOptimizer {
    /// 创建自动优化器,指定重规划倒计时间隔(毫秒)。
    ///
    /// `replan_interval_ms` 为 0 会让 [`Self::should_replan`] 恒返回 `true`(倒计时永远
    /// 停在 0),导致每 tick 都重规划。此处下取 `max(1)`,使 0 退化为最小有效间隔。
    pub fn new(replan_interval_ms: u64) -> Self {
        let replan_interval_ms = replan_interval_ms.max(1);
        Self {
            history: Arc::new(RwLock::new(LoadHistory::new(MAX_HISTORY))),
            qos: Arc::new(AdaptiveQos::new()),
            predictor: Arc::new(RwLock::new(CacheWarmupPredictor::new())),
            replan_countdown: AtomicU64::new(replan_interval_ms),
            replan_interval_ms,
        }
    }

    /// 设置缓存热度阈值,返回修改后的构建器。
    pub fn with_hot_threshold(mut self, threshold: u64) -> Self {
        self.predictor = Arc::new(RwLock::new(CacheWarmupPredictor::with_threshold(threshold)));
        self
    }

    /// 记录一条负载采样到历史窗口。
    pub fn record_sample(&self, sample: LoadSample) {
        if let Ok(mut history) = self.history.write() {
            history.record(sample);
        }
    }

    /// 记录一次缓存键访问以更新预热预测。
    pub fn record_cache_access(&self, key: &str) {
        if let Ok(mut predictor) = self.predictor.write() {
            predictor.record_access(key);
        }
    }

    /// 基于当前负载历史评估并返回 QoS 等级。
    pub fn evaluate_qos(&self) -> QosLevel {
        // 极致性能:仅需 history 读锁,QoS level 通过 AtomicU8 无锁写入
        if let Ok(history) = self.history.read() {
            self.qos.evaluate(&history)
        } else {
            QosLevel::Normal
        }
    }

    /// 递减重规划倒计时,归零时重置并返回是否应触发重规划。
    ///
    /// CAS 循环实现:多线程并发调用时
    /// - 倒计时不会从 0 下溢回绕到 `u64::MAX`(原 `fetch_sub` 竞态缺陷)
    /// - 每个周期仅一个调用者观察到 `true`(重置与触发判定原子化)
    pub fn should_replan(&self) -> bool {
        loop {
            let cur = self.replan_countdown.load(Ordering::Relaxed);
            if cur <= 1 {
                // 归零:CAS 重置为完整间隔,仅一个线程成功并触发重规划
                if self
                    .replan_countdown
                    .compare_exchange(
                        cur,
                        self.replan_interval_ms,
                        Ordering::Relaxed,
                        Ordering::Relaxed,
                    )
                    .is_ok()
                {
                    return true;
                }
            } else if self
                .replan_countdown
                .compare_exchange(cur, cur - 1, Ordering::Relaxed, Ordering::Relaxed)
                .is_ok()
            {
                return false;
            }
            // CAS 失败说明被并发修改,重试
        }
    }

    /// 重置重规划倒计时为完整间隔。
    pub fn reset_replan_timer(&self) {
        self.replan_countdown.store(self.replan_interval_ms, Ordering::Relaxed);
    }

    /// 根据当前负载历史计算最优工作线程数。
    pub fn get_optimal_worker_count(&self, current: usize) -> usize {
        // 极致性能:仅需 history 读锁,QoS 阈值通过 Arc 不可变共享
        if let Ok(history) = self.history.read() {
            self.qos.effective_worker_count(current, &history)
        } else {
            current
        }
    }

    /// 返回热缓存键列表(`Box<str>` 零成本 Clone,无堆分配增长)
    pub fn get_hot_cache_keys(&self) -> Vec<Box<str>> {
        if let Ok(predictor) = self.predictor.read() {
            predictor.predict_warmup()
        } else {
            Vec::new()
        }
    }

    /// 手动设置当前 QoS 等级(无锁原子写)。
    #[inline]
    pub fn set_qos_level(&self, level: QosLevel) {
        self.qos.set_level(level);
    }

    /// 返回当前 QoS 等级(无锁原子读)。
    #[inline]
    pub fn current_qos_level(&self) -> QosLevel {
        self.qos.current_level()
    }

    /// 返回负载历史的快照副本,锁竞争失败时返回 `None`。
    pub fn history_snapshot(&self) -> Option<LoadHistory> {
        self.history.read().ok().map(|h| (*h).clone())
    }
}

impl Default for AutoOptimizer {
    fn default() -> Self {
        Self::new(5000)
    }
}

impl Clone for AutoOptimizer {
    fn clone(&self) -> Self {
        Self {
            history: Arc::clone(&self.history),
            qos: Arc::clone(&self.qos),
            predictor: Arc::clone(&self.predictor),
            // 继承当前倒计时(原子加载):clone 不得重置为完整间隔,
            // 否则每次 clone 都会推迟重规划,造成倒计时漂移
            replan_countdown: AtomicU64::new(self.replan_countdown.load(Ordering::Relaxed)),
            replan_interval_ms: self.replan_interval_ms,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_qos_level() {
        assert_eq!(QosLevel::Critical.priority(), 0);
        assert_eq!(QosLevel::Background.priority(), 4);
        assert_eq!(QosLevel::from_priority(2), QosLevel::Normal);
    }

    #[test]
    fn test_load_history() {
        let mut history = LoadHistory::new(10);
        for i in 0..5 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.5 + (i as f64 * 0.1),
                queue_depth: 100 + i * 50,
                latency_p99: 10 + i * 5,
                throughput: 1000 + i * 200,
            });
        }
        assert_eq!(history.len(), 5);
        assert!(history.avg_cpu() > 0.5);
        assert!(history.max_queue_depth() >= 300);
        assert!(history.avg_throughput() > 1000);
    }

    #[test]
    fn test_load_history_overflow() {
        let mut history = LoadHistory::new(3);
        for i in 0..10 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: i as f64 * 0.1,
                queue_depth: i as u64,
                latency_p99: i as u64,
                throughput: i as u64,
            });
        }
        assert_eq!(history.len(), 3);
    }

    #[test]
    fn test_load_trend_stable() {
        let mut history = LoadHistory::new(10);
        for _ in 0..8 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.5,
                queue_depth: 100,
                latency_p99: 50,
                throughput: 1000,
            });
        }
        assert_eq!(history.trend(), LoadTrend::Stable);
    }

    #[test]
    fn test_load_trend_increasing() {
        let mut history = LoadHistory::new(10);
        for i in 0..8 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.2 + (i as f64 * 0.1),
                queue_depth: 100,
                latency_p99: 50,
                throughput: 1000,
            });
        }
        assert_eq!(history.trend(), LoadTrend::Increasing);
    }

    #[test]
    fn test_adaptive_qos_evaluation() {
        let qos = AdaptiveQos::new();
        assert_eq!(qos.current_level(), QosLevel::Normal);

        let mut history = LoadHistory::new(10);
        for _ in 0..8 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.95,
                queue_depth: 500,
                latency_p99: 200,
                throughput: 5000,
            });
        }

        let level = qos.evaluate(&history);
        assert!(matches!(level, QosLevel::Critical | QosLevel::High));
    }

    #[test]
    fn test_adaptive_qos_worker_scaling() {
        let qos = AdaptiveQos::new();
        let mut history = LoadHistory::new(10);

        for i in 0..8 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.3 + (i as f64 * 0.1),
                queue_depth: 50,
                latency_p99: 5,
                throughput: 200,
            });
        }

        let worker_count = qos.effective_worker_count(4, &history);
        assert!(worker_count >= 4);
    }

    #[test]
    fn test_cache_warmup_predictor() {
        let mut predictor = CacheWarmupPredictor::new().with_hot_threshold(5);

        for _ in 0..10 {
            predictor.record_access("key_hot");
        }
        for _ in 0..2 {
            predictor.record_access("key_cold");
        }

        let hot_keys = predictor.get_hot_keys();
        assert!(hot_keys.contains(&"key_hot"));
    }

    #[test]
    fn test_cache_warmup_predictor_prune() {
        let mut predictor = CacheWarmupPredictor::new();
        for i in 0..200 {
            predictor.record_access(&format!("key_{}", i));
        }
        assert!(predictor.pattern_count() > 100);
        predictor.prune(50);
        assert_eq!(predictor.pattern_count(), 50);
    }

    #[test]
    fn test_cache_warmup_default_threshold_triggers() {
        // SYS-005 回归:默认阈值 10(< 衰减不动点 20),默认配置即可实际触发预热。
        // 原默认 100 高于不动点 → 永不触发。
        let mut predictor = CacheWarmupPredictor::new();
        for _ in 0..10 {
            predictor.record_access("default_hot");
        }
        assert!(
            predictor.get_hot_keys().contains(&"default_hot"),
            "默认阈值必须低于衰减不动点使预热可触发"
        );
    }

    #[test]
    fn test_effective_worker_count_single_worker_lower_bound() {
        // SYS-006 回归:单 worker 低负载(Decreasing + 低 CPU)时,
        // 有效 worker 数不得返回 0(此前 `1/2=0` 非法下界)。
        let mut history = LoadHistory::new(10);
        // 构造 Decreasing 趋势 + 低 CPU(前高后低)
        for i in 0..8u64 {
            history.record(LoadSample {
                timestamp: Instant::now(),
                cpu_usage: 0.9 - (i as f64 * 0.1),
                queue_depth: 1,
                latency_p99: 5,
                throughput: 10,
            });
        }
        assert_eq!(history.trend(), LoadTrend::Decreasing);
        let qos = AdaptiveQos::new();
        let n = qos.effective_worker_count(1, &history);
        assert!(n >= 1, "单 worker 低负载下界必须 >= 1,实际 {n}");
    }

    #[test]
    fn test_auto_optimizer() {
        let optimizer = AutoOptimizer::new(100).with_hot_threshold(3);

        optimizer.record_sample(LoadSample {
            timestamp: Instant::now(),
            cpu_usage: 0.75,
            queue_depth: 200,
            latency_p99: 50,
            throughput: 5000,
        });

        optimizer.record_cache_access("session_abc");
        optimizer.record_cache_access("session_abc");
        optimizer.record_cache_access("session_abc");

        let level = optimizer.evaluate_qos();
        assert!(matches!(level, QosLevel::Normal | QosLevel::High));

        let hot_keys = optimizer.get_hot_cache_keys();
        assert!(!hot_keys.is_empty());
    }

    #[test]
    fn test_auto_optimizer_replan() {
        let optimizer = AutoOptimizer::new(2);
        assert!(!optimizer.should_replan());
        assert!(optimizer.should_replan());
        assert!(!optimizer.should_replan());
        optimizer.reset_replan_timer();
        assert!(!optimizer.should_replan());
        assert!(optimizer.should_replan());
    }

    #[test]
    fn test_should_replan_concurrent_no_underflow() {
        // 并发风暴下倒计时不得下溢回绕到 u64::MAX(原 fetch_sub 竞态缺陷回归测试)
        use std::sync::Arc;
        let optimizer = Arc::new(AutoOptimizer::new(4));
        let mut handles = Vec::new();
        for _ in 0..8 {
            let opt = Arc::clone(&optimizer);
            handles.push(std::thread::spawn(move || {
                let mut trues = 0u32;
                for _ in 0..1000 {
                    if opt.should_replan() {
                        trues += 1;
                    }
                }
                trues
            }));
        }
        let mut total_trues = 0u32;
        for h in handles {
            total_trues += h.join().unwrap();
        }
        // 8000 次调用 / 间隔 4 ≈ 2000 次触发;允许 CAS 竞争带来的少量偏差,
        // 但必须远小于调用总数(若下溢回绕,倒计时卡死,触发数趋近 0)
        assert!(
            total_trues > 1000,
            "并发触发次数异常(疑似下溢卡死): {}",
            total_trues
        );
        // 风暴后单线程语义仍然正确
        optimizer.reset_replan_timer();
        assert!(!optimizer.should_replan());
    }

    #[test]
    fn test_auto_optimizer_clone() {
        let optimizer = AutoOptimizer::new(100);
        optimizer.set_qos_level(QosLevel::High);
        let cloned = optimizer.clone();
        assert_eq!(cloned.current_qos_level(), QosLevel::High);
    }

    #[test]
    fn test_auto_optimizer_clone_inherits_replan_countdown() {
        // clone 必须继承当前倒计时,不得重置为完整间隔(倒计时漂移回归测试)
        let optimizer = AutoOptimizer::new(4);
        // 消耗 3 次倒计时(4 → 1)
        assert!(!optimizer.should_replan());
        assert!(!optimizer.should_replan());
        assert!(!optimizer.should_replan());
        let cloned = optimizer.clone();
        // 继承当前值 1:下一次调用即触发重规划(若被重置为 4 则不会触发)
        assert!(cloned.should_replan(), "clone 未继承 replan_countdown 当前值");
    }

    #[test]
    fn test_qos_level_discriminants_locked() {
        // repr(u8) 显式判别值锁定:priority()/to_u8() 与 as u8 强转一致
        assert_eq!(QosLevel::Critical as u8, 0);
        assert_eq!(QosLevel::High as u8, 1);
        assert_eq!(QosLevel::Normal as u8, 2);
        assert_eq!(QosLevel::Low as u8, 3);
        assert_eq!(QosLevel::Background as u8, 4);
        for level in [
            QosLevel::Critical,
            QosLevel::High,
            QosLevel::Normal,
            QosLevel::Low,
            QosLevel::Background,
        ] {
            assert_eq!(level.priority(), level as u8);
            assert_eq!(level.to_u8(), level as u8);
            assert!(!level.as_str().is_empty());
        }
    }

    #[test]
    fn test_qos_level_u8_roundtrip() {
        for level in [
            QosLevel::Critical,
            QosLevel::High,
            QosLevel::Normal,
            QosLevel::Low,
            QosLevel::Background,
        ] {
            assert_eq!(QosLevel::from_u8(level.to_u8()), level);
        }
        // 未知值回退到 Background
        assert_eq!(QosLevel::from_u8(255), QosLevel::Background);
        assert_eq!(QosLevel::from_u8(5), QosLevel::Background);
    }

    #[test]
    fn test_adaptive_qos_set_level_atomic() {
        let qos = AdaptiveQos::new();
        assert_eq!(qos.current_level(), QosLevel::Normal);
        qos.set_level(QosLevel::Critical);
        assert_eq!(qos.current_level(), QosLevel::Critical);
        qos.set_level(QosLevel::Background);
        assert_eq!(qos.current_level(), QosLevel::Background);
    }

    #[test]
    fn test_adaptive_qos_clone_preserves_level() {
        let qos = AdaptiveQos::new();
        qos.set_level(QosLevel::High);
        let cloned = qos.clone();
        assert_eq!(cloned.current_level(), QosLevel::High);
        // Clone 后修改不影响原对象
        cloned.set_level(QosLevel::Low);
        assert_eq!(qos.current_level(), QosLevel::High);
        assert_eq!(cloned.current_level(), QosLevel::Low);
    }
}