use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct WriteThrottleConfig {
pub max_pending_sections: usize,
pub max_pending_bytes: u64,
pub throttle_threshold: f64,
}
impl Default for WriteThrottleConfig {
fn default() -> Self {
Self {
max_pending_sections: 10,
max_pending_bytes: 64 * 1024 * 1024, throttle_threshold: 0.7,
}
}
}
#[derive(Debug)]
pub struct CompactionDebtTracker {
pending_sections: AtomicUsize,
pending_bytes: AtomicU64,
config: WriteThrottleConfig,
}
impl CompactionDebtTracker {
pub fn new(config: WriteThrottleConfig) -> Self {
Self {
pending_sections: AtomicUsize::new(0),
pending_bytes: AtomicU64::new(0),
config,
}
}
pub fn add_pending(&self, bytes: u64) {
self.pending_sections.fetch_add(1, Ordering::Relaxed);
self.pending_bytes.fetch_add(bytes, Ordering::Relaxed);
}
pub fn complete_pending(&self, bytes: u64) {
self.pending_sections.fetch_sub(1, Ordering::Relaxed);
self.pending_bytes.fetch_sub(bytes, Ordering::Relaxed);
}
pub fn should_throttle(&self) -> bool {
self.debt_ratio() >= self.config.throttle_threshold
}
pub fn debt_ratio(&self) -> f64 {
let sections = self.pending_sections.load(Ordering::Relaxed) as f64;
let bytes = self.pending_bytes.load(Ordering::Relaxed) as f64;
let section_ratio = sections / self.config.max_pending_sections as f64;
let bytes_ratio = bytes / self.config.max_pending_bytes as f64;
section_ratio.max(bytes_ratio)
}
pub fn throttle_duration(&self) -> Duration {
let ratio = self.debt_ratio();
if ratio <= self.config.throttle_threshold {
return Duration::from_millis(0);
}
let over = ratio - self.config.throttle_threshold;
let millis = (over * 1000.0).clamp(10.0, 2000.0);
Duration::from_millis(millis as u64)
}
}