use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use nodedb_types::id::DatabaseId;
pub struct MaterializeFreezeRegistry {
inner: RwLock<HashMap<DatabaseId, u32>>,
}
impl MaterializeFreezeRegistry {
pub fn new() -> Arc<Self> {
Arc::new(Self {
inner: RwLock::new(HashMap::new()),
})
}
pub fn freeze(self: &Arc<Self>, db_id: DatabaseId) -> FreezeGuard {
{
let mut map = self.inner.write().unwrap_or_else(|p| p.into_inner());
let count = map.entry(db_id).or_insert(0);
*count += 1;
}
FreezeGuard {
registry: Arc::clone(self),
db_id,
}
}
pub fn is_frozen(&self, db_id: DatabaseId) -> bool {
let map = self.inner.read().unwrap_or_else(|p| p.into_inner());
map.get(&db_id).copied().unwrap_or(0) > 0
}
fn release(&self, db_id: DatabaseId) {
let mut map = self.inner.write().unwrap_or_else(|p| p.into_inner());
if let Some(count) = map.get_mut(&db_id) {
if *count <= 1 {
map.remove(&db_id);
} else {
*count -= 1;
}
}
}
}
impl Default for MaterializeFreezeRegistry {
fn default() -> Self {
Self {
inner: RwLock::new(HashMap::new()),
}
}
}
pub struct FreezeGuard {
registry: Arc<MaterializeFreezeRegistry>,
db_id: DatabaseId,
}
impl Drop for FreezeGuard {
fn drop(&mut self) {
self.registry.release(self.db_id);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn db(id: u64) -> DatabaseId {
DatabaseId::new(id)
}
#[test]
fn freeze_and_release_single() {
let reg = MaterializeFreezeRegistry::new();
assert!(!reg.is_frozen(db(1)));
let guard = reg.freeze(db(1));
assert!(reg.is_frozen(db(1)));
drop(guard);
assert!(!reg.is_frozen(db(1)));
}
#[test]
fn nested_freeze_releases_on_last_drop() {
let reg = MaterializeFreezeRegistry::new();
let g1 = reg.freeze(db(2));
let g2 = reg.freeze(db(2));
assert!(reg.is_frozen(db(2)));
drop(g1);
assert!(reg.is_frozen(db(2)), "still frozen after first drop");
drop(g2);
assert!(!reg.is_frozen(db(2)), "unfrozen after last drop");
}
#[test]
fn different_databases_independent() {
let reg = MaterializeFreezeRegistry::new();
let _g1 = reg.freeze(db(3));
assert!(reg.is_frozen(db(3)));
assert!(!reg.is_frozen(db(4)));
}
}