alopex_core/storage/format/
backpressure.rs1use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
4use std::time::Duration;
5
6#[derive(Debug, Clone)]
8pub struct WriteThrottleConfig {
9 pub max_pending_sections: usize,
11 pub max_pending_bytes: u64,
13 pub throttle_threshold: f64,
15}
16
17impl Default for WriteThrottleConfig {
18 fn default() -> Self {
19 Self {
20 max_pending_sections: 10,
21 max_pending_bytes: 64 * 1024 * 1024, throttle_threshold: 0.7,
23 }
24 }
25}
26
27#[derive(Debug)]
29pub struct CompactionDebtTracker {
30 pending_sections: AtomicUsize,
31 pending_bytes: AtomicU64,
32 config: WriteThrottleConfig,
33}
34
35impl CompactionDebtTracker {
36 pub fn new(config: WriteThrottleConfig) -> Self {
38 Self {
39 pending_sections: AtomicUsize::new(0),
40 pending_bytes: AtomicU64::new(0),
41 config,
42 }
43 }
44
45 pub fn add_pending(&self, bytes: u64) {
47 self.pending_sections.fetch_add(1, Ordering::Relaxed);
48 self.pending_bytes.fetch_add(bytes, Ordering::Relaxed);
49 }
50
51 pub fn complete_pending(&self, bytes: u64) {
53 self.pending_sections.fetch_sub(1, Ordering::Relaxed);
54 self.pending_bytes.fetch_sub(bytes, Ordering::Relaxed);
55 }
56
57 pub fn should_throttle(&self) -> bool {
59 self.debt_ratio() >= self.config.throttle_threshold
60 }
61
62 pub fn debt_ratio(&self) -> f64 {
64 let sections = self.pending_sections.load(Ordering::Relaxed) as f64;
65 let bytes = self.pending_bytes.load(Ordering::Relaxed) as f64;
66 let section_ratio = sections / self.config.max_pending_sections as f64;
67 let bytes_ratio = bytes / self.config.max_pending_bytes as f64;
68 section_ratio.max(bytes_ratio)
69 }
70
71 pub fn throttle_duration(&self) -> Duration {
73 let ratio = self.debt_ratio();
74 if ratio <= self.config.throttle_threshold {
75 return Duration::from_millis(0);
76 }
77 let over = ratio - self.config.throttle_threshold;
79 let millis = (over * 1000.0).clamp(10.0, 2000.0);
80 Duration::from_millis(millis as u64)
81 }
82}