use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug, Clone)]
pub struct DocumentCacheConfig {
pub max_entries: usize,
}
impl Default for DocumentCacheConfig {
fn default() -> Self {
Self {
max_entries: 10_000,
}
}
}
pub struct DocumentCache {
cache: RwLock<HashMap<String, Arc<serde_json::Value>>>,
access_order: RwLock<Vec<String>>,
max_entries: usize,
}
impl Clone for DocumentCache {
fn clone(&self) -> Self {
Self {
cache: RwLock::new(HashMap::new()),
access_order: RwLock::new(Vec::new()),
max_entries: self.max_entries,
}
}
}
impl DocumentCache {
pub fn new(max_entries: usize) -> Self {
Self {
cache: RwLock::new(HashMap::new()),
access_order: RwLock::new(Vec::new()),
max_entries,
}
}
pub fn with_config(config: &DocumentCacheConfig) -> Self {
Self::new(config.max_entries)
}
pub async fn get(&self, key: &str) -> Option<Arc<serde_json::Value>> {
let mut access_order = self.access_order.write().await;
if let Some(pos) = access_order.iter().position(|k| k == key) {
access_order.remove(pos);
access_order.push(key.to_string());
}
let cache = self.cache.read().await;
cache.get(key).cloned()
}
pub async fn put(&self, key: String, value: serde_json::Value) {
let mut cache = self.cache.write().await;
let mut access_order = self.access_order.write().await;
if cache.contains_key(&key) {
if let Some(pos) = access_order.iter().position(|k| k == &key) {
access_order.remove(pos);
}
}
cache.insert(key.clone(), Arc::new(value));
access_order.push(key);
while cache.len() > self.max_entries {
if let Some(oldest) = access_order.first() {
cache.remove(oldest);
access_order.remove(0);
} else {
break;
}
}
}
pub async fn invalidate(&self, key: &str) {
let mut cache = self.cache.write().await;
let mut access_order = self.access_order.write().await;
cache.remove(key);
if let Some(pos) = access_order.iter().position(|k| k == key) {
access_order.remove(pos);
}
}
pub async fn invalidate_collection(&self, collection_prefix: &str) {
let mut cache = self.cache.write().await;
let mut access_order = self.access_order.write().await;
let keys: Vec<String> = cache
.keys()
.filter(|k| k.starts_with(collection_prefix))
.cloned()
.collect();
for key in keys {
cache.remove(&key);
if let Some(pos) = access_order.iter().position(|k| k == &key) {
access_order.remove(pos);
}
}
}
pub async fn clear(&self) {
let mut cache = self.cache.write().await;
let mut access_order = self.access_order.write().await;
cache.clear();
access_order.clear();
}
pub async fn stats(&self) -> DocumentCacheStats {
let cache = self.cache.read().await;
DocumentCacheStats {
entries: cache.len(),
max_entries: self.max_entries,
}
}
}
#[derive(Debug, Clone)]
pub struct DocumentCacheStats {
pub entries: usize,
pub max_entries: usize,
}
static DOCUMENT_CACHE: std::sync::OnceLock<DocumentCache> = std::sync::OnceLock::new();
pub fn init_document_cache(config: &DocumentCacheConfig) {
let _ = DOCUMENT_CACHE.set(DocumentCache::with_config(config));
}
pub fn get_document_cache() -> &'static DocumentCache {
DOCUMENT_CACHE.get_or_init(|| DocumentCache::new(10_000))
}