use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};
use nodedb_mem::ScopedMemory;
use nodedb_types::collection_config::VectorPrimaryConfig;
use nodedb_vector::rerank::CodecSidecar;
use crate::engine::vector::HnswIndex;
use crate::engine::vector::id_map::VectorIdMap;
use crate::storage::engine::StorageEngine;
pub struct VectorState<S: StorageEngine> {
pub(crate) hnsw_indices: Mutex<HashMap<String, HnswIndex>>,
pub(crate) vector_id_map: Mutex<VectorIdMap>,
pub(crate) search_ef: usize,
pub(crate) storage: Arc<S>,
pub(crate) codec_sidecars: Arc<Mutex<HashMap<String, CodecSidecar>>>,
pub(crate) per_index_config: Arc<Mutex<HashMap<String, VectorPrimaryConfig>>>,
pub(crate) unloadable: Mutex<HashSet<String>>,
pub(crate) evicted: Mutex<HashSet<String>>,
pub(crate) memory: ScopedMemory,
}
pub struct RestoredVectorState<S: StorageEngine> {
pub storage: Arc<S>,
pub search_ef: usize,
pub indices: HashMap<String, HnswIndex>,
pub id_map: VectorIdMap,
pub memory: ScopedMemory,
}
impl<S: StorageEngine> VectorState<S> {
pub fn new(storage: Arc<S>, search_ef: usize, memory: ScopedMemory) -> Self {
Self {
hnsw_indices: Mutex::new(HashMap::new()),
vector_id_map: Mutex::new(VectorIdMap::new()),
search_ef,
storage,
codec_sidecars: Arc::new(Mutex::new(HashMap::new())),
per_index_config: Arc::new(Mutex::new(HashMap::new())),
unloadable: Mutex::new(HashSet::new()),
evicted: Mutex::new(HashSet::new()),
memory,
}
}
pub fn from_restored(restored: RestoredVectorState<S>) -> Self {
Self {
hnsw_indices: Mutex::new(restored.indices),
vector_id_map: Mutex::new(restored.id_map),
search_ef: restored.search_ef,
storage: restored.storage,
codec_sidecars: Arc::new(Mutex::new(HashMap::new())),
per_index_config: Arc::new(Mutex::new(HashMap::new())),
unloadable: Mutex::new(HashSet::new()),
evicted: Mutex::new(HashSet::new()),
memory: restored.memory,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::query::engine::{test_governor, test_scoped_memory};
use crate::storage::pagedb_storage::PagedbStorageMem;
#[tokio::test]
async fn per_index_config_starts_empty() {
let storage = Arc::new(
PagedbStorageMem::open_in_memory()
.await
.expect("in-memory pagedb"),
);
let memory = test_scoped_memory(&test_governor(), nodedb_mem::EngineId::Vector);
let state = VectorState::new(storage, 100, memory);
let configs = state.per_index_config.lock().expect("lock");
assert!(
configs.is_empty(),
"per_index_config must be empty on construction"
);
}
}