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, DiskAnnParams, IndexId, NamespaceId, TableId};
use crate::idx::IndexKeyBase;
use crate::idx::trees::diskann::cache::DiskAnnCache;
use crate::idx::trees::diskann::index::DiskAnnIndex;
pub(crate) type SharedDiskAnnIndex = Arc<DiskAnnIndex>;
pub(crate) type SharedDiskAnnKey = (NamespaceId, DatabaseId, TableId, IndexId);
pub(crate) struct DiskAnnIndexes(Arc<RwLock<HashMap<SharedDiskAnnKey, SharedDiskAnnIndex>>>);
impl Default for DiskAnnIndexes {
fn default() -> Self {
Self(Arc::new(RwLock::new(HashMap::new())))
}
}
impl DiskAnnIndexes {
pub(super) async fn get(
&self,
tb: TableId,
ikb: &IndexKeyBase,
p: &DiskAnnParams,
cache: DiskAnnCache,
) -> Result<SharedDiskAnnIndex> {
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(DiskAnnIndex::new(ikb.clone(), tb, p, cache).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(())
}
}