use crate::backend::native::v3::node::NodeRecordV3;
use lru::LruCache;
use parking_lot::Mutex;
use std::num::NonZeroUsize;
pub struct NodeCache {
inner: Mutex<LruCache<i64, NodeRecordV3>>,
}
impl NodeCache {
pub fn new(capacity: usize) -> Self {
let capacity = NonZeroUsize::new(capacity.max(1)).expect("capacity must be at least 1");
Self {
inner: Mutex::new(LruCache::new(capacity)),
}
}
pub fn insert(&self, node_id: i64, record: NodeRecordV3) {
let mut cache = self.inner.lock();
cache.put(node_id, record);
}
pub fn get(&self, node_id: i64) -> Option<NodeRecordV3> {
let mut cache = self.inner.lock();
cache.get(&node_id).cloned()
}
pub fn invalidate(&self, node_id: i64) {
let mut cache = self.inner.lock();
cache.pop(&node_id);
}
pub fn clear(&self) {
let mut cache = self.inner.lock();
cache.clear();
}
pub fn len(&self) -> usize {
let cache = self.inner.lock();
cache.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::native::types::NodeFlags;
fn make_test_record(node_id: i64) -> NodeRecordV3 {
NodeRecordV3::new_inline(
node_id,
NodeFlags::empty(),
0, 0, vec![1, 2, 3, 4], 0, 0, 0, 0, )
}
#[test]
fn test_cache_insert_and_get() {
let cache = NodeCache::new(10);
let record = make_test_record(1);
cache.insert(1, record.clone());
let retrieved = cache.get(1);
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().id(), 1);
}
#[test]
fn test_cache_miss_returns_none() {
let cache = NodeCache::new(10);
assert!(cache.get(999).is_none());
}
#[test]
fn test_cache_eviction() {
let cache = NodeCache::new(3);
cache.insert(1, make_test_record(1));
cache.insert(2, make_test_record(2));
cache.insert(3, make_test_record(3));
assert_eq!(cache.len(), 3);
cache.insert(4, make_test_record(4));
assert_eq!(cache.len(), 3);
assert!(cache.get(1).is_none()); assert!(cache.get(2).is_some()); }
#[test]
fn test_cache_invalidate() {
let cache = NodeCache::new(10);
cache.insert(1, make_test_record(1));
assert!(cache.get(1).is_some());
cache.invalidate(1);
assert!(cache.get(1).is_none());
}
#[test]
fn test_cache_clear() {
let cache = NodeCache::new(10);
cache.insert(1, make_test_record(1));
cache.insert(2, make_test_record(2));
assert_eq!(cache.len(), 2);
cache.clear();
assert!(cache.is_empty());
}
#[test]
fn test_cache_len_and_is_empty() {
let cache = NodeCache::new(10);
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
cache.insert(1, make_test_record(1));
assert!(!cache.is_empty());
assert_eq!(cache.len(), 1);
}
}