use std::sync::{Arc, Weak};
use tracing::debug;
use super::plan_cache::PlanCache;
pub struct PlanCacheInvalidator {
cache: Weak<PlanCache>,
}
impl PlanCacheInvalidator {
pub fn new(cache: &Arc<PlanCache>) -> Self {
Self {
cache: Arc::downgrade(cache),
}
}
pub fn invalidate(&self, name: &str, new_version: u64) {
if let Some(cache) = self.cache.upgrade() {
debug!(
collection = name,
new_version, "gateway plan cache: invalidating entries for descriptor"
);
cache.invalidate_descriptor(name, new_version);
}
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use crate::control::gateway::plan_cache::{PlanCache, PlanCacheKey, hash_sql};
use crate::control::gateway::version_set::GatewayVersionSet;
use nodedb_physical::physical_plan::{KvOp, PhysicalPlan};
fn kv_plan() -> Arc<PhysicalPlan> {
Arc::new(PhysicalPlan::Kv(KvOp::Get {
collection: "users".into(),
key: vec![],
rls_filters: vec![],
surrogate_ceiling: None,
}))
}
fn key_for(sql: &str, col: &str, version: u64) -> PlanCacheKey {
PlanCacheKey {
sql_text_hash: hash_sql(sql),
placeholder_types_hash: 0,
version_set: GatewayVersionSet::from_pairs(vec![(col.into(), version)]),
}
}
#[test]
fn invalidate_drops_stale_entries_only() {
let cache = Arc::new(PlanCache::new(16));
let invalidator = PlanCacheInvalidator::new(&cache);
let k_users_v1 = key_for("q1", "users", 1);
let k_orders_v5 = key_for("q2", "orders", 5);
cache.insert(k_users_v1.clone(), kv_plan());
cache.insert(k_orders_v5.clone(), kv_plan());
assert_eq!(cache.len(), 2);
invalidator.invalidate("users", 2);
assert_eq!(cache.len(), 1);
assert!(cache.get(&k_users_v1).is_none());
assert!(cache.get(&k_orders_v5).is_some());
}
#[test]
fn invalidate_noop_when_cache_dropped() {
let cache = Arc::new(PlanCache::new(4));
let invalidator = PlanCacheInvalidator::new(&cache);
drop(cache);
invalidator.invalidate("any_collection", 99);
}
}