use std::sync::atomic::{AtomicU32, AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use dashmap::DashMap;
pub const BP_LOW_THRESHOLD: f32 = 0.3;
pub const BP_MEDIUM_THRESHOLD: f32 = 0.5;
pub const BP_HIGH_THRESHOLD: f32 = 0.7;
pub const BP_CRITICAL_THRESHOLD: f32 = 0.9;
const BP_SCALE: u32 = 1000;
#[derive(Debug)]
pub struct BackpressureState {
value: AtomicU32,
last_update: AtomicU64,
active_clients: AtomicUsize,
queue_depth: AtomicUsize,
rejected_count: AtomicU64,
}
impl BackpressureState {
pub fn new() -> Self {
Self {
value: AtomicU32::new(0),
last_update: AtomicU64::new(0),
active_clients: AtomicUsize::new(0),
queue_depth: AtomicUsize::new(0),
rejected_count: AtomicU64::new(0),
}
}
pub fn get(&self) -> f32 {
self.value.load(Ordering::Acquire) as f32 / BP_SCALE as f32
}
pub fn set(&self, value: f32) {
let scaled = (value.clamp(0.0, 1.0) * BP_SCALE as f32) as u32;
self.value.store(scaled, Ordering::Release);
let now = Instant::now().duration_since(Instant::now()).as_secs();
self.last_update.store(now, Ordering::Relaxed);
}
pub fn record_rejection(&self) {
self.rejected_count.fetch_add(1, Ordering::Relaxed);
}
pub fn rejected_count(&self) -> u64 {
self.rejected_count.load(Ordering::Acquire)
}
pub fn active_clients(&self) -> usize {
self.active_clients.load(Ordering::Acquire)
}
pub fn queue_depth(&self) -> usize {
self.queue_depth.load(Ordering::Acquire)
}
pub fn level(&self) -> &'static str {
let bp = self.get();
if bp < BP_LOW_THRESHOLD {
"Low"
} else if bp < BP_MEDIUM_THRESHOLD {
"Medium"
} else if bp < BP_HIGH_THRESHOLD {
"High"
} else if bp < BP_CRITICAL_THRESHOLD {
"Very High"
} else {
"Critical"
}
}
}
impl Default for BackpressureState {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ModuleQuota {
pub max_calls_per_sec: u32,
pub max_in_flight: usize,
pub max_memory_bytes: usize,
}
impl Default for ModuleQuota {
fn default() -> Self {
Self {
max_calls_per_sec: 1000,
max_in_flight: 100,
max_memory_bytes: 64 * 1024 * 1024, }
}
}
#[derive(Debug)]
pub struct ModuleResources {
module_name: String,
calls_this_sec: AtomicU32,
in_flight: AtomicUsize,
memory_bytes: AtomicUsize,
quota: ModuleQuota,
}
impl ModuleResources {
pub fn new(module_name: String, quota: ModuleQuota) -> Self {
Self {
module_name,
calls_this_sec: AtomicU32::new(0),
in_flight: AtomicUsize::new(0),
memory_bytes: AtomicUsize::new(0),
quota,
}
}
pub fn can_admit(&self) -> bool {
if self.in_flight.load(Ordering::Acquire) >= self.quota.max_in_flight {
return false;
}
let calls = self.calls_this_sec.load(Ordering::Acquire);
if calls >= self.quota.max_calls_per_sec {
return false;
}
let memory = self.memory_bytes.load(Ordering::Acquire);
if memory >= self.quota.max_memory_bytes {
return false;
}
true
}
pub fn record_call_start(&self) -> bool {
if !self.can_admit() {
return false;
}
self.in_flight.fetch_add(1, Ordering::AcqRel);
self.calls_this_sec.fetch_add(1, Ordering::Relaxed);
true
}
pub fn record_call_end(&self) {
self.in_flight.fetch_sub(1, Ordering::AcqRel);
}
pub fn set_memory_usage(&self, bytes: usize) {
self.memory_bytes.store(bytes, Ordering::Release);
}
pub fn reset_second_counter(&self) {
self.calls_this_sec.store(0, Ordering::Relaxed);
}
pub fn in_flight(&self) -> usize {
self.in_flight.load(Ordering::Acquire)
}
pub fn memory_usage(&self) -> usize {
self.memory_bytes.load(Ordering::Acquire)
}
pub fn module_name(&self) -> &str {
&self.module_name
}
}
#[derive(Debug)]
pub struct ResourceManager {
pub backpressure: Arc<BackpressureState>,
modules: DashMap<String, Arc<ModuleResources>>,
default_quota: ModuleQuota,
}
impl ResourceManager {
pub fn new() -> Self {
Self {
backpressure: Arc::new(BackpressureState::new()),
modules: DashMap::new(),
default_quota: ModuleQuota::default(),
}
}
pub fn with_default_quota(quota: ModuleQuota) -> Self {
Self {
backpressure: Arc::new(BackpressureState::new()),
modules: DashMap::new(),
default_quota: quota,
}
}
pub fn get_or_create_module(&self, module_name: &str) -> Arc<ModuleResources> {
self.modules
.entry(module_name.to_string())
.or_insert_with(|| {
Arc::new(ModuleResources::new(
module_name.to_string(),
self.default_quota.clone(),
))
})
.clone()
}
pub fn register_module(&self, module_name: &str, quota: ModuleQuota) {
self.modules.insert(
module_name.to_string(),
Arc::new(ModuleResources::new(module_name.to_string(), quota)),
);
}
pub fn can_admit_request(&self, module_name: &str) -> bool {
let bp = self.backpressure.get();
if bp >= BP_CRITICAL_THRESHOLD {
self.backpressure.record_rejection();
return false;
}
let module = self.get_or_create_module(module_name);
if !module.can_admit() {
self.backpressure.record_rejection();
return false;
}
true
}
pub fn record_request_start(&self, module_name: &str) -> bool {
if !self.can_admit_request(module_name) {
return false;
}
let module = self.get_or_create_module(module_name);
module.record_call_start();
self.backpressure
.queue_depth
.fetch_add(1, Ordering::Relaxed);
true
}
pub fn record_request_end(&self, module_name: &str) {
let module = self.get_or_create_module(module_name);
module.record_call_end();
self.backpressure
.queue_depth
.fetch_sub(1, Ordering::Relaxed);
}
pub fn update_backpressure(&self) {
let queue_depth = self.backpressure.queue_depth.load(Ordering::Acquire);
let active_clients = self.backpressure.active_clients.load(Ordering::Acquire);
let queue_factor = (queue_depth as f32 / 1000.0).min(1.0);
let client_factor = (active_clients as f32 / 100.0).min(1.0);
let backpressure = queue_factor * 0.7 + client_factor * 0.3;
self.backpressure.set(backpressure);
}
pub fn client_connected(&self) {
self.backpressure
.active_clients
.fetch_add(1, Ordering::AcqRel);
}
pub fn client_disconnected(&self) {
self.backpressure
.active_clients
.fetch_sub(1, Ordering::AcqRel);
}
pub fn stats(&self) -> ResourceManagerStats {
let mut total_in_flight = 0;
let mut total_memory = 0;
for entry in self.modules.iter() {
total_in_flight += entry.value().in_flight();
total_memory += entry.value().memory_usage();
}
ResourceManagerStats {
backpressure: self.backpressure.get(),
active_clients: self.backpressure.active_clients(),
queue_depth: self.backpressure.queue_depth(),
total_in_flight,
total_memory,
module_count: self.modules.len(),
}
}
pub fn spawn_background_task(&self) -> std::thread::JoinHandle<()> {
let _backpressure = Arc::clone(&self.backpressure);
let modules = self
.modules
.iter()
.map(|e| e.key().clone())
.collect::<Vec<_>>();
let modules = Arc::new(modules);
std::thread::spawn(move || {
let mut last_second = Instant::now();
let mut last_update = Instant::now();
loop {
let now = Instant::now();
if now.duration_since(last_second) >= Duration::from_secs(1) {
for module_name in modules.iter() {
let _ = module_name;
}
last_second = now;
}
if now.duration_since(last_update) >= Duration::from_millis(100) {
last_update = now;
}
std::thread::sleep(Duration::from_millis(10));
}
})
}
}
impl Default for ResourceManager {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ResourceManagerStats {
pub backpressure: f32,
pub active_clients: usize,
pub queue_depth: usize,
pub total_in_flight: usize,
pub total_memory: usize,
pub module_count: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_backpressure_state() {
let bp = BackpressureState::new();
assert_eq!(bp.get(), 0.0);
bp.set(0.5);
assert_eq!(bp.get(), 0.5);
bp.set(1.0);
assert_eq!(bp.get(), 1.0);
bp.set(1.5); assert_eq!(bp.get(), 1.0);
}
#[test]
fn test_module_quota_enforcement() {
let quota = ModuleQuota {
max_calls_per_sec: 10,
max_in_flight: 5,
max_memory_bytes: 1024,
};
let module = ModuleResources::new("test".to_string(), quota);
for i in 0..5 {
assert!(module.record_call_start(), "Call {} should be admitted", i);
}
assert!(!module.record_call_start());
module.record_call_end();
assert!(module.record_call_start());
}
#[test]
fn test_resource_manager_backpressure() {
let rm = ResourceManager::new();
assert_eq!(rm.backpressure.get(), 0.0);
rm.record_request_start("module1");
rm.record_request_start("module2");
rm.record_request_start("module1");
rm.update_backpressure();
assert!(rm.backpressure.get() > 0.0);
rm.record_request_end("module1");
rm.record_request_end("module2");
rm.record_request_end("module1");
rm.update_backpressure();
assert!(rm.backpressure.get() < 0.1);
}
#[test]
fn test_client_tracking() {
let rm = ResourceManager::new();
assert_eq!(rm.backpressure.active_clients(), 0);
rm.client_connected();
rm.client_connected();
assert_eq!(rm.backpressure.active_clients(), 2);
rm.client_disconnected();
assert_eq!(rm.backpressure.active_clients(), 1);
}
}