use std::sync::Arc;
use diskann::ANNResult;
use diskann_providers::storage::StorageReadProvider;
use diskann_providers::{storage::PQStorage, utils::load_metadata_from_file};
use crate::search::pq::PQData;
use tracing::info;
pub struct DiskIndexReader {
pq_data: Arc<PQData>,
num_points: usize,
}
impl DiskIndexReader {
pub fn new<Storage: StorageReadProvider>(
pq_pivot_path: String,
pq_compressed_data_path: String,
storage_provider: &Storage,
) -> ANNResult<Self> {
let pq_storage = PQStorage::new(&pq_pivot_path, &pq_compressed_data_path, None);
let pq_pivot_table = pq_storage.load_pq_pivots_bin::<Storage>(
&pq_pivot_path,
0, storage_provider,
)?;
let metadata = load_metadata_from_file(storage_provider, &pq_compressed_data_path)?;
let pq_compressed_data = PQStorage::load_pq_compressed_vectors_bin::<Storage>(
&pq_compressed_data_path,
metadata.npoints(),
pq_pivot_table.get_num_chunks(),
storage_provider,
)?;
info!(
"Loaded PQ centroids and in-memory compressed vectors. #points:{} #pq_chunks: {}",
metadata.npoints(),
pq_pivot_table.get_num_chunks()
);
Ok(DiskIndexReader {
pq_data: Arc::<PQData>::new(PQData::new(pq_pivot_table, pq_compressed_data)?),
num_points: metadata.npoints(),
})
}
pub fn get_pq_data(&self) -> Arc<PQData> {
Arc::clone(&self.pq_data)
}
pub fn get_num_points(&self) -> usize {
self.num_points
}
}
#[cfg(test)]
mod disk_index_storage_test {
use diskann::ANNErrorKind;
use diskann_providers::storage::VirtualStorageProvider;
use diskann_utils::test_data_root;
use vfs::OverlayFS;
use super::*;
#[test]
fn load_pivot_test() {
let pivot_file_prefix: &str = "/sift/siftsmall_learn";
let storage_provider = VirtualStorageProvider::new_overlay(test_data_root());
let storage = DiskIndexReader::new::<VirtualStorageProvider<OverlayFS>>(
pivot_file_prefix.to_string() + "_pq_pivots.bin",
pivot_file_prefix.to_string() + "_pq_compressed.bin",
&storage_provider,
)
.unwrap();
let _: Arc<PQData> = storage.get_pq_data();
}
#[test]
fn load_pivot_file_not_exist_test() {
let pivot_file_prefix: &str = "/sift/siftsmall_learn_file_not_exist";
let storage_provider = VirtualStorageProvider::new_overlay(test_data_root());
let err = match DiskIndexReader::new::<VirtualStorageProvider<OverlayFS>>(
pivot_file_prefix.to_string() + "_pq_pivots.bin",
pivot_file_prefix.to_string() + "_pq_compressed.bin",
&storage_provider,
) {
Ok(_) => panic!("this function should not have succeeded"),
Err(err) => err,
};
assert_eq!(err.kind(), ANNErrorKind::PQError);
assert!(err.to_string().contains("PQ k-means pivot file not found"));
}
#[test]
fn test_get_num_points() {
let pivot_file_prefix: &str = "/sift/siftsmall_learn";
let storage_provider = VirtualStorageProvider::new_overlay(test_data_root());
let storage = DiskIndexReader::new::<VirtualStorageProvider<OverlayFS>>(
pivot_file_prefix.to_string() + "_pq_pivots.bin",
pivot_file_prefix.to_string() + "_pq_compressed.bin",
&storage_provider,
)
.unwrap();
let num_points = storage.get_num_points();
assert_eq!(num_points, 25000);
}
}