use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use nodedb_types::{DatabaseId, TenantId};
use super::config::GovernorConfig;
use super::global_counter::GlobalCounter;
use crate::budget::Budget;
use crate::engine::EngineId;
use crate::error::Result;
use crate::pressure::PressureThresholds;
use crate::scoped_budget::ScopedBudget;
#[derive(Debug)]
pub struct MemoryGovernor {
pub(super) budgets: [Budget; EngineId::COUNT],
pub(crate) global_counter: Arc<GlobalCounter>,
pub(super) global_ceiling: usize,
pub(super) thresholds: PressureThresholds,
pub(super) database_budgets: RwLock<HashMap<DatabaseId, ScopedBudget>>,
pub(super) tenant_budgets: RwLock<HashMap<(DatabaseId, TenantId), ScopedBudget>>,
}
impl MemoryGovernor {
pub fn new(config: GovernorConfig) -> Result<Self> {
config.validate()?;
let limits = config.engine_limits.as_array();
let budgets: [Budget; EngineId::COUNT] = std::array::from_fn(|i| Budget::new(limits[i]));
let global_counter = Arc::new(GlobalCounter::new(config.global_ceiling));
Ok(Self {
budgets,
global_counter,
global_ceiling: config.global_ceiling,
thresholds: PressureThresholds::default(),
database_budgets: RwLock::new(HashMap::new()),
tenant_budgets: RwLock::new(HashMap::new()),
})
}
pub fn budget(&self, engine: EngineId) -> &Budget {
&self.budgets[engine.index()]
}
pub fn global_ceiling(&self) -> usize {
self.global_ceiling
}
}