use std::sync::Mutex;
use std::time::{Duration, Instant};
static LAST_REFRESH: Mutex<Option<Instant>> = Mutex::new(None);
pub fn load_average_one() -> f64 {
let _ = ensure_fresh();
sysinfo::System::load_average().one
}
pub fn ncpus() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4)
}
pub fn is_system_saturated() -> bool {
let load = load_average_one();
let n = ncpus() as f64;
let multiplier: f64 = std::env::var("SQLITE_GRAPHRAG_MAX_LOAD_PER_NCPU")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2.0);
load > n * multiplier
}
fn ensure_fresh() -> Option<Instant> {
let mut guard = LAST_REFRESH.lock().expect("loadavg mutex poisoned");
let now = Instant::now();
let should_refresh = guard
.as_ref()
.is_none_or(|last| now.duration_since(*last) > Duration::from_secs(1));
let prev = guard.as_ref().copied();
if should_refresh {
*guard = Some(now);
}
prev
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ncpus_is_at_least_one() {
assert!(ncpus() >= 1);
}
#[test]
fn load_average_is_non_negative() {
assert!(load_average_one() >= 0.0);
}
#[test]
fn saturation_default_threshold_is_two() {
let env_default = std::env::var("SQLITE_GRAPHRAG_MAX_LOAD_PER_NCPU")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2.0);
assert!(env_default >= 1.0);
}
#[test]
fn saturation_check_does_not_panic() {
let _ = is_system_saturated();
}
#[test]
fn ensure_fresh_returns_previous_then_sets_new() {
let prev = ensure_fresh();
if prev.is_none() {
let second = ensure_fresh();
assert!(second.is_some());
}
}
}