use super::*;
use crate::storage::RocksDb as DB;
use dashmap::DashMap;
use once_cell::sync::Lazy;
use std::sync::{Arc, Weak};
#[derive(Debug, Default)]
pub(crate) struct IndexMetaSnapshot {
pub indexes: Vec<Index>,
pub fulltext: Vec<FulltextIndex>,
pub geo: Vec<GeoIndex>,
pub ttl: Vec<TtlIndex>,
}
struct CacheEntry {
db: Weak<DB>,
snapshot: Arc<IndexMetaSnapshot>,
}
type CacheKey = (usize, String);
static INDEX_META_CACHE: Lazy<DashMap<CacheKey, CacheEntry>> = Lazy::new(DashMap::new);
fn cache_key(db: &DB, cf_name: &str) -> CacheKey {
(db as *const DB as usize, cf_name.to_string())
}
pub(crate) fn invalidate_index_meta(db: &DB, cf_name: &str) {
INDEX_META_CACHE.remove(&cache_key(db, cf_name));
}
impl Collection {
pub(crate) fn index_meta(&self) -> Option<Arc<IndexMetaSnapshot>> {
let key = cache_key(&self.db, &self.name);
if let Some(entry) = INDEX_META_CACHE.get(&key) {
if entry
.db
.upgrade()
.is_some_and(|db| Arc::ptr_eq(&db, &self.db))
{
return Some(Arc::clone(&entry.snapshot));
}
}
let cf = self.db.cf_handle(&self.name)?;
let mut snapshot = IndexMetaSnapshot::default();
macro_rules! load {
($prefix:expr, $target:expr) => {
let prefix = $prefix.as_bytes();
for (key, value) in self.db.prefix_iterator_cf(&cf, prefix).flatten() {
if !key.starts_with(prefix) {
break;
}
if let Ok(def) = serde_json::from_slice(&value) {
$target.push(def);
}
}
};
}
load!(IDX_META_PREFIX, snapshot.indexes);
load!(FT_META_PREFIX, snapshot.fulltext);
load!(GEO_META_PREFIX, snapshot.geo);
load!(TTL_META_PREFIX, snapshot.ttl);
let snapshot = Arc::new(snapshot);
INDEX_META_CACHE.insert(
key,
CacheEntry {
db: Arc::downgrade(&self.db),
snapshot: Arc::clone(&snapshot),
},
);
Some(snapshot)
}
pub(crate) fn invalidate_index_meta(&self) {
invalidate_index_meta(&self.db, &self.name);
}
}