use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use super::buffer_pool::{AdvancedBufferPool, MemoryPressure};
use super::error::ComputeError;
#[derive(Debug, Clone)]
pub struct MonitorConfig {
pub sampling_interval: Duration,
pub history_window_size: usize,
pub cleanup_threshold: MemoryPressure,
pub enable_circuit_breaker: bool,
}
impl Default for MonitorConfig {
fn default() -> Self {
Self {
sampling_interval: Duration::from_millis(100),
history_window_size: 100,
cleanup_threshold: MemoryPressure::High,
enable_circuit_breaker: true,
}
}
}
#[derive(Debug)]
pub struct MemoryPressureMonitor {
config: MonitorConfig,
pressure_history: Arc<Mutex<VecDeque<PressureReading>>>,
current_pressure: Arc<Mutex<MemoryPressure>>,
monitoring_active: bool,
statistics: Arc<Mutex<MonitoringStatistics>>,
}
#[derive(Debug, Clone)]
pub struct PressureReading {
pub timestamp: Instant,
pub pressure: MemoryPressure,
pub memory_usage_ratio: f32,
pub total_allocations: u64,
pub active_buffers: u64,
}
#[derive(Debug, Clone)]
pub struct MonitoringStatistics {
pub readings_taken: u64,
pub average_pressure: f32,
pub peak_pressure: MemoryPressure,
pub cleanup_events: u64,
pub circuit_breaker_activations: u64,
}
impl Default for MonitoringStatistics {
fn default() -> Self {
Self {
readings_taken: 0,
average_pressure: 0.0,
peak_pressure: MemoryPressure::None,
cleanup_events: 0,
circuit_breaker_activations: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct MonitoringReport {
pub current_pressure: MemoryPressure,
pub monitoring_stats: MonitoringStatistics,
pub recent_readings: Vec<PressureReading>,
}
impl MemoryPressureMonitor {
pub fn new(config: MonitorConfig) -> Self {
Self {
config,
pressure_history: Arc::new(Mutex::new(VecDeque::new())),
current_pressure: Arc::new(Mutex::new(MemoryPressure::None)),
monitoring_active: false,
statistics: Arc::new(Mutex::new(MonitoringStatistics::default())),
}
}
pub fn start_monitoring(
&mut self,
_buffer_pool: Arc<AdvancedBufferPool>,
) -> Result<(), ComputeError> {
self.monitoring_active = true;
Ok(())
}
pub fn stop_monitoring(&mut self) -> Result<(), ComputeError> {
self.monitoring_active = false;
Ok(())
}
pub fn record_pressure(&self, pressure: MemoryPressure, memory_usage_ratio: f32) {
let reading = PressureReading {
timestamp: Instant::now(),
pressure,
memory_usage_ratio,
total_allocations: 0, active_buffers: 0, };
*self.current_pressure.lock().unwrap() = pressure;
let mut history = self.pressure_history.lock().unwrap();
history.push_back(reading);
while history.len() > self.config.history_window_size {
history.pop_front();
}
let mut stats = self.statistics.lock().unwrap();
stats.readings_taken += 1;
if pressure > stats.peak_pressure {
stats.peak_pressure = pressure;
}
if pressure >= self.config.cleanup_threshold {
stats.cleanup_events += 1;
}
}
pub fn get_current_pressure(&self) -> MemoryPressure {
*self.current_pressure.lock().unwrap()
}
pub fn generate_report(&self) -> MonitoringReport {
let current_pressure = *self.current_pressure.lock().unwrap();
let monitoring_stats = self.statistics.lock().unwrap().clone();
let recent_readings = self
.pressure_history
.lock()
.unwrap()
.iter()
.cloned()
.collect();
MonitoringReport {
current_pressure,
monitoring_stats,
recent_readings,
}
}
pub fn should_activate_circuit_breaker(&self) -> bool {
if !self.config.enable_circuit_breaker {
return false;
}
let current_pressure = *self.current_pressure.lock().unwrap();
current_pressure >= MemoryPressure::Critical
}
pub fn get_statistics(&self) -> MonitoringStatistics {
self.statistics.lock().unwrap().clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pressure_monitor_creation() {
let config = MonitorConfig::default();
let monitor = MemoryPressureMonitor::new(config);
assert!(!monitor.monitoring_active);
assert_eq!(monitor.get_current_pressure(), MemoryPressure::None);
}
#[test]
fn test_pressure_recording() {
let config = MonitorConfig::default();
let monitor = MemoryPressureMonitor::new(config);
monitor.record_pressure(MemoryPressure::Medium, 0.7);
assert_eq!(monitor.get_current_pressure(), MemoryPressure::Medium);
let stats = monitor.get_statistics();
assert_eq!(stats.readings_taken, 1);
assert_eq!(stats.peak_pressure, MemoryPressure::Medium);
}
#[test]
fn test_circuit_breaker() {
let config = MonitorConfig::default();
let monitor = MemoryPressureMonitor::new(config);
monitor.record_pressure(MemoryPressure::Low, 0.4);
assert!(!monitor.should_activate_circuit_breaker());
monitor.record_pressure(MemoryPressure::Critical, 0.95);
assert!(monitor.should_activate_circuit_breaker());
}
}