use super::region::MemoryRegion;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PressureLevel {
Normal,
Moderate,
High,
Critical,
}
impl PressureLevel {
#[must_use]
pub const fn description(&self) -> &'static str {
match self {
Self::Normal => "Normal operation",
Self::Moderate => "Proactive eviction",
Self::High => "Aggressive eviction/spilling",
Self::Critical => "Blocking allocations",
}
}
#[must_use]
pub const fn requires_eviction(&self) -> bool {
matches!(self, Self::Moderate | Self::High | Self::Critical)
}
#[must_use]
pub const fn should_spill(&self) -> bool {
matches!(self, Self::High | Self::Critical)
}
#[must_use]
pub const fn blocks_allocations(&self) -> bool {
matches!(self, Self::Critical)
}
}
impl std::fmt::Display for PressureLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Normal => write!(f, "Normal"),
Self::Moderate => write!(f, "Moderate"),
Self::High => write!(f, "High"),
Self::Critical => write!(f, "Critical"),
}
}
}
#[derive(Debug, Clone)]
pub struct BufferStats {
pub budget: usize,
pub total_allocated: usize,
pub region_allocated: [usize; 4],
pub pressure_level: PressureLevel,
pub consumer_count: usize,
}
impl BufferStats {
#[must_use]
pub fn utilization(&self) -> f64 {
if self.budget == 0 {
return 0.0;
}
self.total_allocated as f64 / self.budget as f64
}
#[must_use]
pub fn utilization_percent(&self) -> f64 {
self.utilization() * 100.0
}
#[must_use]
pub fn region_usage(&self, region: MemoryRegion) -> usize {
self.region_allocated[region.index()]
}
#[must_use]
pub fn available(&self) -> usize {
self.budget.saturating_sub(self.total_allocated)
}
}
impl Default for BufferStats {
fn default() -> Self {
Self {
budget: 0,
total_allocated: 0,
region_allocated: [0; 4],
pressure_level: PressureLevel::Normal,
consumer_count: 0,
}
}
}
impl std::fmt::Display for BufferStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Buffer Manager Stats:")?;
writeln!(
f,
" Budget: {} ({:.2}% used)",
format_bytes(self.budget),
self.utilization_percent()
)?;
writeln!(
f,
" Allocated: {} / {}",
format_bytes(self.total_allocated),
format_bytes(self.budget)
)?;
writeln!(f, " Pressure: {}", self.pressure_level)?;
writeln!(f, " Consumers: {}", self.consumer_count)?;
writeln!(f, " Per-region:")?;
for region in MemoryRegion::all() {
writeln!(
f,
" {}: {}",
region.name(),
format_bytes(self.region_usage(region))
)?;
}
Ok(())
}
}
fn format_bytes(bytes: usize) -> String {
const KB: usize = 1024;
const MB: usize = KB * 1024;
const GB: usize = MB * 1024;
if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{bytes} B")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pressure_level_ordering() {
assert!(PressureLevel::Normal < PressureLevel::Moderate);
assert!(PressureLevel::Moderate < PressureLevel::High);
assert!(PressureLevel::High < PressureLevel::Critical);
}
#[test]
fn test_pressure_level_properties() {
assert!(!PressureLevel::Normal.requires_eviction());
assert!(PressureLevel::Moderate.requires_eviction());
assert!(PressureLevel::High.requires_eviction());
assert!(PressureLevel::Critical.requires_eviction());
assert!(!PressureLevel::Normal.should_spill());
assert!(!PressureLevel::Moderate.should_spill());
assert!(PressureLevel::High.should_spill());
assert!(PressureLevel::Critical.should_spill());
assert!(!PressureLevel::Normal.blocks_allocations());
assert!(!PressureLevel::High.blocks_allocations());
assert!(PressureLevel::Critical.blocks_allocations());
}
#[test]
fn test_buffer_stats_utilization() {
let stats = BufferStats {
budget: 1000,
total_allocated: 750,
region_allocated: [250, 250, 200, 50],
pressure_level: PressureLevel::Moderate,
consumer_count: 3,
};
assert!((stats.utilization() - 0.75).abs() < 0.001);
assert!((stats.utilization_percent() - 75.0).abs() < 0.1);
assert_eq!(stats.available(), 250);
}
#[test]
fn test_buffer_stats_region_usage() {
let stats = BufferStats {
budget: 1000,
total_allocated: 600,
region_allocated: [100, 200, 250, 50],
pressure_level: PressureLevel::Normal,
consumer_count: 2,
};
assert_eq!(stats.region_usage(MemoryRegion::GraphStorage), 100);
assert_eq!(stats.region_usage(MemoryRegion::IndexBuffers), 200);
assert_eq!(stats.region_usage(MemoryRegion::ExecutionBuffers), 250);
assert_eq!(stats.region_usage(MemoryRegion::SpillStaging), 50);
}
#[test]
fn test_format_bytes() {
assert_eq!(format_bytes(512), "512 B");
assert_eq!(format_bytes(1024), "1.00 KB");
assert_eq!(format_bytes(1536), "1.50 KB");
assert_eq!(format_bytes(1024 * 1024), "1.00 MB");
assert_eq!(format_bytes(1024 * 1024 * 1024), "1.00 GB");
}
#[test]
fn test_pressure_level_description() {
assert_eq!(PressureLevel::Normal.description(), "Normal operation");
assert_eq!(PressureLevel::Moderate.description(), "Proactive eviction");
assert_eq!(
PressureLevel::High.description(),
"Aggressive eviction/spilling"
);
assert_eq!(
PressureLevel::Critical.description(),
"Blocking allocations"
);
}
#[test]
fn test_pressure_level_display() {
assert_eq!(PressureLevel::Normal.to_string(), "Normal");
assert_eq!(PressureLevel::Moderate.to_string(), "Moderate");
assert_eq!(PressureLevel::High.to_string(), "High");
assert_eq!(PressureLevel::Critical.to_string(), "Critical");
}
#[test]
fn test_buffer_stats_zero_budget() {
let stats = BufferStats {
budget: 0,
total_allocated: 0,
..Default::default()
};
assert_eq!(stats.utilization(), 0.0);
assert_eq!(stats.utilization_percent(), 0.0);
}
#[test]
fn test_buffer_stats_default() {
let stats = BufferStats::default();
assert_eq!(stats.budget, 0);
assert_eq!(stats.total_allocated, 0);
assert_eq!(stats.pressure_level, PressureLevel::Normal);
assert_eq!(stats.consumer_count, 0);
}
#[test]
fn test_buffer_stats_available_saturates() {
let stats = BufferStats {
budget: 100,
total_allocated: 150,
..Default::default()
};
assert_eq!(stats.available(), 0);
}
#[test]
fn test_buffer_stats_display_contains_budget() {
let stats = BufferStats {
budget: 1024,
total_allocated: 512,
region_allocated: [128, 128, 128, 128],
pressure_level: PressureLevel::Normal,
consumer_count: 1,
};
let s = stats.to_string();
assert!(s.contains("Budget"));
assert!(s.contains("Pressure"));
assert!(s.contains("Normal"));
}
}