use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Arc;
use anyhow::Result;
use tokio::sync::RwLock;
use crate::catalog::{DatabaseId, HnswParams, IndexId, NamespaceId, TableId};
use crate::ctx::FrozenContext;
use crate::idx::IndexKeyBase;
use crate::idx::trees::hnsw::index::HnswIndex;
pub(crate) type SharedHnswIndex = Arc<HnswIndex>;
pub(crate) type SharedHnswKey = (NamespaceId, DatabaseId, TableId, IndexId);
pub(crate) struct HnswIndexes(Arc<RwLock<HashMap<SharedHnswKey, SharedHnswIndex>>>);
impl Default for HnswIndexes {
fn default() -> Self {
Self(Arc::new(RwLock::new(HashMap::new())))
}
}
impl HnswIndexes {
pub(super) async fn get(
&self,
ctx: &FrozenContext,
tb: TableId,
ikb: &IndexKeyBase,
p: &HnswParams,
) -> Result<SharedHnswIndex> {
let key = (ikb.ns(), ikb.db(), tb, ikb.index());
let h = self.0.read().await.get(&key).cloned();
if let Some(h) = h {
return Ok(h);
}
let mut w = self.0.write().await;
let ix = match w.entry(key) {
Entry::Occupied(e) => Arc::clone(e.get()),
Entry::Vacant(e) => {
let h = Arc::new(
HnswIndex::new(
ctx.get_index_stores().vector_cache().clone(),
&ctx.tx(),
ikb.clone(),
tb,
p,
)
.await?,
);
e.insert(Arc::clone(&h));
h
}
};
Ok(ix)
}
pub(super) async fn remove(&self, tb: TableId, ikb: &IndexKeyBase) -> Result<()> {
let key = (ikb.ns(), ikb.db(), tb, ikb.index());
self.0.write().await.remove(&key);
Ok(())
}
}