diff --git a/diskann-benchmark/src/inputs/save_and_load.rs b/diskann-benchmark/src/inputs/save_and_load.rs index 3866ac894..c5c3794f5 100644 --- a/diskann-benchmark/src/inputs/save_and_load.rs +++ b/diskann-benchmark/src/inputs/save_and_load.rs @@ -4,7 +4,7 @@ */ use std::{io::Read, mem::size_of, num::NonZeroUsize}; -use diskann::{ANNError, ANNResult}; +use diskann::{ANNError, ANNErrorKind, ANNResult}; use diskann_providers::storage::StorageReadProvider; pub fn get_graph_num_frozen_points( @@ -22,9 +22,9 @@ pub fn get_graph_num_frozen_points( let file_frozen_pts = usize::from_le_bytes(usize_buffer); NonZeroUsize::new(file_frozen_pts).ok_or_else(|| { - ANNError::log_index_config_error( - "num_frozen_pts".to_string(), - "num_frozen_pts is zero in saved file".to_string(), + ANNError::from_display( + ANNErrorKind::IndexConfigError, + "num_frozen_pts is invalid, err = num_frozen_pts is zero in saved file", ) }) } diff --git a/diskann-bftree/src/lib.rs b/diskann-bftree/src/lib.rs index 334e0dd82..ccb781dff 100644 --- a/diskann-bftree/src/lib.rs +++ b/diskann-bftree/src/lib.rs @@ -90,7 +90,10 @@ impl TransientError for VectorUnavailable { where D: std::fmt::Display, { - ANNError::log_index_error(format!("{self}, escalated: {why}")) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("{self}, escalated: {why}"), + ) } } @@ -107,11 +110,14 @@ pub(crate) fn validate_record_size( let required = key_size + value_size; let configured_max = config.get_cb_max_record_size(); if required > configured_max { - return Err(ANNError::log_index_error(format!( - "{provider_name}: cb_max_record_size ({configured_max}) is too small; \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "{provider_name}: cb_max_record_size ({configured_max}) is too small; \ a record requires {required} bytes ({key_size}-byte key + {value_size}-byte value); \ increase cb_max_record_size to at least {required}" - ))); + ), + )); } Ok(()) } diff --git a/diskann-bftree/src/neighbors.rs b/diskann-bftree/src/neighbors.rs index 148312720..cca2d0edd 100644 --- a/diskann-bftree/src/neighbors.rs +++ b/diskann-bftree/src/neighbors.rs @@ -122,7 +122,8 @@ impl NeighborProvider { if read_size > 0 { // A retrieved neighbor list should be exactly dim length if read_size as usize != self.dim * std::mem::size_of::() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Retrieved neighbor list is not expected length = max degree + 1", )); } @@ -135,7 +136,7 @@ impl NeighborProvider { // The specified list length must be smaller than the retrieved data length if count > self.max_degree() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, "Size of retrieved neighbor list is shorter than the stored neighbor count", )); } @@ -144,12 +145,14 @@ impl NeighborProvider { } } bf_tree::LeafReadResult::Deleted => { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "The bf-tree entry for the vector is marked as deleted", )); } bf_tree::LeafReadResult::InvalidKey => { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "The bf-tree entry for the vector key is marked as invalid", )); } @@ -196,7 +199,8 @@ impl NeighborProvider { self.num_get_calls.increment(); if buf.len() < self.dim { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "The provided buffer is not long enough", )); } @@ -227,7 +231,8 @@ impl NeighborProvider { /// - Buffer length (in `I` cells) is smaller than `max_degree() + 1` pub fn set_neighbors(&self, vector_id: I, neighbors: &[I], buf: &mut [I]) -> ANNResult<()> { if neighbors.len() > self.dim - 1 { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "The provided neighbor list is longer than the max degree", )); }; diff --git a/diskann-bftree/src/provider.rs b/diskann-bftree/src/provider.rs index 1a9f773ca..2c5e9b978 100644 --- a/diskann-bftree/src/provider.rs +++ b/diskann-bftree/src/provider.rs @@ -343,11 +343,14 @@ where { // Early validation before allocating resources if start_points.nrows() != params.num_start_points.get() { - return Err(ANNError::log_async_index_error(format!( - "start_points matrix has {} rows, but params.num_start_points is {}", - start_points.nrows(), - params.num_start_points.get(), - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::AsyncIndexError, + format!( + "start_points matrix has {} rows, but params.num_start_points is {}", + start_points.nrows(), + params.num_start_points.get(), + ), + )); } let provider = Self::new_empty(params.clone(), quant_precursor)?; @@ -732,11 +735,14 @@ where fn set_start_points(&self, _hidden: Hidden, start_points: MatrixView<'_, T>) -> ANNResult<()> { let start_point_ids = self.full_vectors.starting_points()?; if start_points.nrows() != start_point_ids.len() { - return Err(ANNError::log_async_index_error(format!( - "expected start_points to contain `{}` rows, instead it has {}", - start_point_ids.len(), - start_points.nrows(), - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::AsyncIndexError, + format!( + "expected start_points to contain `{}` rows, instead it has {}", + start_point_ids.len(), + start_points.nrows(), + ), + )); } let mut scratch = self.neighbor_provider.scratch(&self.locks); @@ -763,11 +769,14 @@ where fn set_start_points(&self, _hidden: Hidden, start_points: MatrixView<'_, T>) -> ANNResult<()> { let start_point_ids = self.full_vectors.starting_points()?; if start_points.nrows() != start_point_ids.len() { - return Err(ANNError::log_async_index_error(format!( - "expected start_points to contain `{}` rows, instead it has {}", - start_point_ids.len(), - start_points.nrows(), - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::AsyncIndexError, + format!( + "expected start_points to contain `{}` rows, instead it has {}", + start_point_ids.len(), + start_points.nrows(), + ), + )); } let mut scratch = self.neighbor_provider.scratch(&self.locks); @@ -1691,7 +1700,8 @@ fn save_bftree( use_snapshot: bool, ) -> ANNResult<()> { if !use_snapshot { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "cannot snapshot a BfTree that was not configured with use_snapshot(true)", )); } @@ -1725,8 +1735,12 @@ where { let saved_params = SavedParams { max_points: self.max_points(), - frozen_points: NonZeroUsize::new(self.num_start_points()) - .ok_or_else(|| ANNError::log_index_error("num_start_points is zero"))?, + frozen_points: NonZeroUsize::new(self.num_start_points()).ok_or_else(|| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "num_start_points is zero", + ) + })?, dim: self.dim(), metric: self.metric().as_str().to_string(), max_degree: self.max_degree(), @@ -1756,7 +1770,10 @@ where { let params_filename = BfTreePaths::params_json(&saved_params.prefix); let params_json = serde_json::to_string(&saved_params).map_err(|e| { - ANNError::log_index_error(format!("Failed to serialize params: {}", e)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to serialize params: {}", e), + ) })?; let mut params_writer = storage.create_for_write(¶ms_filename)?; params_writer.write_all(params_json.as_bytes())?; @@ -1793,12 +1810,19 @@ where let mut params_json = String::new(); params_reader.read_to_string(&mut params_json)?; serde_json::from_str(¶ms_json).map_err(|e| { - ANNError::log_index_error(format!("Failed to deserialize params: {}", e)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to deserialize params: {}", e), + ) })? }; - let metric = Metric::from_str(&saved_params.metric) - .map_err(|e| ANNError::log_index_error(format!("Failed to parse metric: {}", e)))?; + let metric = Metric::from_str(&saved_params.metric).map_err(|e| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to parse metric: {}", e), + ) + })?; let vector_index = load_bftree( BfTreePaths::vectors_bftree(&saved_params.prefix), @@ -1845,8 +1869,12 @@ where { let saved_params = SavedParams { max_points: self.max_points(), - frozen_points: NonZeroUsize::new(self.num_start_points()) - .ok_or_else(|| ANNError::log_index_error("num_start_points is zero"))?, + frozen_points: NonZeroUsize::new(self.num_start_points()).ok_or_else(|| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "num_start_points is zero", + ) + })?, dim: self.dim(), metric: self.metric().as_str().to_string(), max_degree: self.max_degree(), @@ -1887,7 +1915,10 @@ where { let params_filename = BfTreePaths::params_json(&saved_params.prefix); let params_json = serde_json::to_string(&saved_params).map_err(|e| { - ANNError::log_index_error(format!("Failed to serialize params: {}", e)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to serialize params: {}", e), + ) })?; let mut params_writer = storage.create_for_write(¶ms_filename)?; params_writer.write_all(params_json.as_bytes())?; @@ -1914,7 +1945,9 @@ where .quant_vectors .quantizer .serialize(GlobalAllocator) - .map_err(|e| ANNError::log_index_error(format!("{e}")))?; + .map_err(|e| { + ANNError::from_display(diskann::ANNErrorKind::IndexError, format!("{e}")) + })?; let mut writer = storage.create_for_write(&filename)?; writer.write_all(&serialized)?; @@ -1938,16 +1971,26 @@ where let mut params_json = String::new(); params_reader.read_to_string(&mut params_json)?; serde_json::from_str(¶ms_json).map_err(|e| { - ANNError::log_index_error(format!("Failed to deserialize params: {}", e)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to deserialize params: {}", e), + ) })? }; let _quant_params = saved_params.quant_params.ok_or_else(|| { - ANNError::log_index_error("Missing quant_params in saved params for quantized provider") + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Missing quant_params in saved params for quantized provider", + ) })?; - let metric = Metric::from_str(&saved_params.metric) - .map_err(|e| ANNError::log_index_error(format!("Failed to parse metric: {}", e)))?; + let metric = Metric::from_str(&saved_params.metric).map_err(|e| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to parse metric: {}", e), + ) + })?; let vector_index = load_bftree( BfTreePaths::vectors_bftree(&saved_params.prefix), @@ -1973,8 +2016,10 @@ where let mut reader = storage.open_reader(&filename)?; let mut bytes = Vec::new(); reader.read_to_end(&mut bytes)?; - let quantizer: Poly = try_deserialize(&bytes, GlobalAllocator) - .map_err(|e| ANNError::log_index_error(format!("{e}")))?; + let quantizer: Poly = + try_deserialize(&bytes, GlobalAllocator).map_err(|e| { + ANNError::from_display(diskann::ANNErrorKind::IndexError, format!("{e}")) + })?; let quant_vector_index = load_bftree( BfTreePaths::quant_bftree(&saved_params.prefix), diff --git a/diskann-bftree/src/quant.rs b/diskann-bftree/src/quant.rs index 8a37ffd19..8f5e8b19c 100644 --- a/diskann-bftree/src/quant.rs +++ b/diskann-bftree/src/quant.rs @@ -102,7 +102,7 @@ impl QuantVectorProvider { GlobalAllocator, ScopedAllocator::global(), ) - .map_err(|e| ANNError::log_sq_error(e))?; + .map_err(|e| ANNError::new(diskann::ANNErrorKind::SQError, e))?; Ok(QuantQueryComputer(inner)) } @@ -110,7 +110,7 @@ impl QuantVectorProvider { pub fn distance_computer(&self) -> ANNResult { self.quantizer .distance_computer(GlobalAllocator) - .map_err(|e| ANNError::log_sq_error(e)) + .map_err(|e| ANNError::new(diskann::ANNErrorKind::SQError, e)) } pub(crate) fn get_vector_into(&self, i: usize, buffer: &mut [u8]) -> Result<(), AccessError> { @@ -133,7 +133,7 @@ impl QuantVectorProvider { match self.quant_vector_index.read(bytemuck::bytes_of(&i), buffer) { bf_tree::LeafReadResult::Found(read_size) => { if read_size as usize != expected { - return Err(AccessError::Error(ANNError::log_index_error(format!( + return Err(AccessError::Error(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "The bf-tree entry for vector id {} is marked as found but has size {} instead of the expected size {}", i, read_size, expected, )))); @@ -146,10 +146,10 @@ impl QuantVectorProvider { })); } bf_tree::LeafReadResult::InvalidKey => { - return Err(AccessError::Error(ANNError::log_index_error(format!( - "The bf-tree entry for vector id {} is marked as invalid", - i, - )))); + return Err(AccessError::Error(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("The bf-tree entry for vector id {} is marked as invalid", i,), + ))); } bf_tree::LeafReadResult::NotFound => { return Err(AccessError::Transient(VectorUnavailable { @@ -183,7 +183,8 @@ impl QuantVectorProvider { let vf32: &[f32] = &T::as_f32(v).into_ann_result()?; if vf32.len() != self.full_dim() { - return Err(ANNError::log_dimension_mismatch_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::DimensionMismatchError, "Vector f32 dimension is not equal to the expected dimension.".to_string(), )); } @@ -199,7 +200,7 @@ impl QuantVectorProvider { OpaqueMut::new(quant_vector), ScopedAllocator::global(), ) - .map_err(|e| ANNError::log_sq_error(e))?; + .map_err(|e| ANNError::new(diskann::ANNErrorKind::SQError, e))?; bftree_insert(&self.quant_vector_index, key, quant_vector)?; @@ -214,7 +215,8 @@ impl QuantVectorProvider { #[cfg(test)] pub(crate) fn set_quant_vector(&self, i: usize, v: &[u8]) -> ANNResult<()> { if v.len() != self.quantizer.bytes() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } diff --git a/diskann-bftree/src/vectors.rs b/diskann-bftree/src/vectors.rs index 661ffac08..bc01a0fd8 100644 --- a/diskann-bftree/src/vectors.rs +++ b/diskann-bftree/src/vectors.rs @@ -99,7 +99,10 @@ impl VectorProvider { (self.max_vectors..self.total()) .map(|i| { u32::try_from(i).map_err(|_| { - ANNError::log_index_error(format_args!("start point id {i} exceeds u32::MAX")) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("start point id {i} exceeds u32::MAX"), + ) }) }) .collect() @@ -124,12 +127,14 @@ impl VectorProvider { #[inline(always)] pub(crate) fn set_vector_sync(&self, i: usize, v: &[T]) -> ANNResult<()> { if v.len() != self.dim { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } if i >= self.total() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } @@ -163,7 +168,7 @@ impl VectorProvider { bf_tree::LeafReadResult::Found(read_size) => { let vector_size = std::mem::size_of::() * self.dim; if read_size as usize != vector_size { - return Err(RankedError::Error(ANNError::log_index_error(format!( + return Err(RankedError::Error(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "The bf-tree entry for vector id {} is marked as found but has size {} instead of the expected size {}", i, read_size, vector_size, )))); @@ -176,10 +181,10 @@ impl VectorProvider { })); } bf_tree::LeafReadResult::InvalidKey => { - return Err(RankedError::Error(ANNError::log_index_error(format!( - "The bf-tree entry for vector id {} is marked as invalid", - i - )))); + return Err(RankedError::Error(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("The bf-tree entry for vector id {} is marked as invalid", i), + ))); } bf_tree::LeafReadResult::NotFound => { return Err(RankedError::Transient(VectorUnavailable { diff --git a/diskann-disk/src/build/builder/build.rs b/diskann-disk/src/build/builder/build.rs index 432c577fc..998c7a4dd 100644 --- a/diskann-disk/src/build/builder/build.rs +++ b/diskann-disk/src/build/builder/build.rs @@ -226,7 +226,12 @@ where // use either user-specified number of threads or default to available parallelism let num_tasks = NonZeroUsize::new(config.num_threads) .or_else(|| std::thread::available_parallelism().ok()) - .ok_or_else(|| ANNError::log_index_error("Failed to determine number of threads"))?; + .ok_or_else(|| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Failed to determine number of threads", + ) + })?; // Associated data will only be used in the write_disk_layout function which only requires the none-partitioned associated data stream. let dataset_iter = Arc::new(Mutex::new({ @@ -292,8 +297,12 @@ async fn log_build_stats(index: &Arc>) - /// The async index uses `u32` internal ids, so positions in the dataset must not exceed /// `u32::MAX`. fn u32_try_from(value: usize) -> ANNResult { - u32::try_from(value) - .map_err(|_| ANNError::log_index_error(format_args!("id {value} exceeds u32::MAX"))) + u32::try_from(value).map_err(|_| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("id {value} exceeds u32::MAX"), + ) + }) } fn set_start_point_to_medoid( @@ -338,7 +347,10 @@ where for _ in partition { let vector_data = { let mut guard = iterator_clone.lock().map_err(|_| { - ANNError::log_index_error("Poisoned mutex during construction") + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Poisoned mutex during construction", + ) })?; guard.next() }; @@ -357,7 +369,12 @@ where // Wait for all tasks to complete. while let Some(res) = tasks.join_next().await { - res.map_err(|_| ANNError::log_index_error("A spawned insert task failed"))??; + res.map_err(|_| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "A spawned insert task failed", + ) + })??; } info!("Linked all points. Num points: #{}", total_points); @@ -382,7 +399,12 @@ async fn run_final_prune( // Wait for all final prune tasks to complete while let Some(res) = tasks.join_next().await { - res.map_err(|_| ANNError::log_index_error("A spawned final prune task failed"))??; + res.map_err(|_| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "A spawned final prune task failed", + ) + })??; } Ok(()) diff --git a/diskann-disk/src/build/builder/quantizer.rs b/diskann-disk/src/build/builder/quantizer.rs index 7bbfacf3c..cfd8dc077 100644 --- a/diskann-disk/src/build/builder/quantizer.rs +++ b/diskann-disk/src/build/builder/quantizer.rs @@ -86,9 +86,9 @@ impl BuildQuantizer { standard_deviation, } => { if nbits != 1 { - return Err(ANNError::log_index_config_error( - "build_quantization_type".to_string(), - "SQ quantization is only supported for 1 bit".to_string(), + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexConfigError, + "build_quantization_type is invalid, err = SQ quantization is only supported for 1 bit", )); } let rng = diskann_providers::utils::create_rnd_provider_from_optional_seed( diff --git a/diskann-disk/src/build/builder/tokio.rs b/diskann-disk/src/build/builder/tokio.rs index 4b66c37ce..6651551e0 100644 --- a/diskann-disk/src/build/builder/tokio.rs +++ b/diskann-disk/src/build/builder/tokio.rs @@ -15,7 +15,10 @@ pub fn create_runtime(num_threads: usize) -> ANNResult } builder.build().map_err(|err| { - ANNError::log_index_error(format!("Failed to initialize tokio runtime: {}", err)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Failed to initialize tokio runtime: {}", err), + ) }) } diff --git a/diskann-disk/src/build/configuration/disk_index_build_parameter.rs b/diskann-disk/src/build/configuration/disk_index_build_parameter.rs index 077c5090d..c2d327691 100644 --- a/diskann-disk/src/build/configuration/disk_index_build_parameter.rs +++ b/diskann-disk/src/build/configuration/disk_index_build_parameter.rs @@ -7,7 +7,7 @@ //! Parameters for disk index construction. use std::num::NonZeroUsize; -use diskann::ANNError; +use diskann::{ANNError, ANNErrorKind}; use thiserror::Error; use super::QuantizationType; @@ -28,7 +28,10 @@ pub struct InvalidMemBudget; impl From for ANNError { fn from(value: InvalidMemBudget) -> Self { - ANNError::log_index_config_error("MemoryBudget".to_string(), format!("{value:?}")) + ANNError::from_display( + ANNErrorKind::IndexConfigError, + format!("MemoryBudget is invalid, err = {value:?}"), + ) } } @@ -71,7 +74,10 @@ pub enum PQChunksError { impl From for ANNError { fn from(value: PQChunksError) -> Self { - ANNError::log_index_config_error("NumPQChunks".to_string(), format!("{value:?}")) + ANNError::from_display( + ANNErrorKind::IndexConfigError, + format!("NumPQChunks is invalid, err = {value:?}"), + ) } } diff --git a/diskann-disk/src/data_model/cache.rs b/diskann-disk/src/data_model/cache.rs index e0b18d00d..4afcb5073 100644 --- a/diskann-disk/src/data_model/cache.rs +++ b/diskann-disk/src/data_model/cache.rs @@ -91,7 +91,8 @@ where associated_data: Data::AssociatedDataType, ) -> ANNResult<()> { if self.dimension != vector.len() { - return ANNResult::Err(ANNError::log_index_error( + return ANNResult::Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension does not match the dimension set in cache.", )); } @@ -103,7 +104,8 @@ where } if self.mapping.len() >= self.capacity { - return ANNResult::Err(ANNError::log_index_error( + return ANNResult::Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Cache is full, cannot insert more nodes", )); } diff --git a/diskann-disk/src/data_model/graph_header.rs b/diskann-disk/src/data_model/graph_header.rs index f04803e4a..118ca9918 100644 --- a/diskann-disk/src/data_model/graph_header.rs +++ b/diskann-disk/src/data_model/graph_header.rs @@ -34,7 +34,7 @@ pub enum GraphHeaderError { impl From for ANNError { #[track_caller] fn from(value: GraphHeaderError) -> Self { - ANNError::log_index_error(value) + ANNError::from_display(diskann::ANNErrorKind::IndexError, value) } } @@ -124,10 +124,9 @@ impl<'a> TryFrom<&'a [u8]> for GraphHeader { /// | GraphMetadata (80 bytes) | BlockSize (8 bytes) | GraphLayoutVersion (8 bytes) | fn try_from(value: &'a [u8]) -> ANNResult { if value.len() < Self::get_size() { - Err(ANNError::log_parse_slice_error( - "&[u8]".to_string(), - "GraphHeader".to_string(), - "The given bytes are not long enough to create a valid graph header.".to_string(), + Err(ANNError::from_display( + diskann::ANNErrorKind::ParseSliceError, + "source: &[u8] target: GraphHeader error: The given bytes are not long enough to create a valid graph header.", )) } else { // Parse metadata. diff --git a/diskann-disk/src/data_model/graph_layout_version.rs b/diskann-disk/src/data_model/graph_layout_version.rs index 62e665cc8..e039a6f29 100644 --- a/diskann-disk/src/data_model/graph_layout_version.rs +++ b/diskann-disk/src/data_model/graph_layout_version.rs @@ -69,11 +69,9 @@ impl<'a> TryFrom<&'a [u8]> for GraphLayoutVersion { /// | MajorVersion (4 bytes) | MinorVersion (4 bytes) | fn try_from(value: &'a [u8]) -> ANNResult { if value.len() < std::mem::size_of::() { - Err(ANNError::log_parse_slice_error( - "&[u8]".to_string(), - "GraphLayoutVersion".to_string(), - "The given bytes are not long enough to create a valid graph layout version." - .to_string(), + Err(ANNError::from_display( + diskann::ANNErrorKind::ParseSliceError, + "source: &[u8] target: GraphLayoutVersion error: The given bytes are not long enough to create a valid graph layout version.", )) } else { let mut cursor = Cursor::new(&value); diff --git a/diskann-disk/src/data_model/graph_metadata.rs b/diskann-disk/src/data_model/graph_metadata.rs index 4ff35916b..8ea456c17 100644 --- a/diskann-disk/src/data_model/graph_metadata.rs +++ b/diskann-disk/src/data_model/graph_metadata.rs @@ -109,10 +109,9 @@ impl<'a> TryFrom<&'a [u8]> for GraphMetadata { /// ...| vamana_frozen_loc (8 bytes) | append_reorder_data (8 bytes) | disk_index_file_size (8 bytes) | associated_data_length (8 bytes) | fn try_from(value: &'a [u8]) -> ANNResult { if value.len() < Self::get_size() { - return Err(ANNError::log_parse_slice_error( - "&[u8]".to_string(), - "GraphMetadata".to_string(), - "The given bytes are not long enough to create a valid graph metadata.".to_string(), + return Err(ANNError::from_display( + diskann::ANNErrorKind::ParseSliceError, + "source: &[u8] target: GraphMetadata error: The given bytes are not long enough to create a valid graph metadata.", )); } diff --git a/diskann-disk/src/search/pq/pq_scratch.rs b/diskann-disk/src/search/pq/pq_scratch.rs index ff4b49b1a..50ef8a8a3 100644 --- a/diskann-disk/src/search/pq/pq_scratch.rs +++ b/diskann-disk/src/search/pq/pq_scratch.rs @@ -42,12 +42,12 @@ impl PQScratch { ) -> ANNResult { let aligned_pq_coord_scratch = Poly::broadcast(0u8, graph_degree * num_pq_chunks, AlignedAllocator::A128) - .map_err(ANNError::log_index_error)?; + .map_err(|err| ANNError::new(diskann::ANNErrorKind::IndexError, err))?; let aligned_pqtable_dist_scratch = Poly::broadcast(0f32, num_centers * num_pq_chunks, AlignedAllocator::A128) - .map_err(ANNError::log_index_error)?; + .map_err(|err| ANNError::new(diskann::ANNErrorKind::IndexError, err))?; let aligned_dist_scratch = Poly::broadcast(0f32, graph_degree, AlignedAllocator::A128) - .map_err(ANNError::log_index_error)?; + .map_err(|err| ANNError::new(diskann::ANNErrorKind::IndexError, err))?; let query_scratch = vec![0.0f32; dim]; Ok(Self { @@ -68,10 +68,13 @@ impl PQScratch { pub fn set(&mut self, query: &[f32]) -> ANNResult<()> { let dim = self.query_scratch.len(); if query.len() != dim { - return Err(ANNError::log_dimension_mismatch_error(format!( - "PQScratch::set: expected query of length {dim}, got {}", - query.len() - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::DimensionMismatchError, + format!( + "PQScratch::set: expected query of length {dim}, got {}", + query.len() + ), + )); } self.query_scratch.copy_from_slice(query); Ok(()) diff --git a/diskann-disk/src/search/provider/aligned_file_reader/aligned_read.rs b/diskann-disk/src/search/provider/aligned_file_reader/aligned_read.rs index 8261d2c26..0b24afce7 100644 --- a/diskann-disk/src/search/provider/aligned_file_reader/aligned_read.rs +++ b/diskann-disk/src/search/provider/aligned_file_reader/aligned_read.rs @@ -69,9 +69,10 @@ impl<'a, T, A: Alignment> AlignedRead<'a, T, A> { if val.is_multiple_of(align) { Ok(()) } else { - Err(ANNError::log_disk_io_request_alignment_error(format!( - "{kind} {val} not aligned to {align}", - ))) + Err(ANNError::from_display( + diskann::ANNErrorKind::DiskIOAlignmentError, + format!("{kind} {val} not aligned to {align}",), + )) } } diff --git a/diskann-disk/src/search/provider/aligned_file_reader/reader/linux.rs b/diskann-disk/src/search/provider/aligned_file_reader/reader/linux.rs index a8cf8184c..d77ff4c8f 100644 --- a/diskann-disk/src/search/provider/aligned_file_reader/reader/linux.rs +++ b/diskann-disk/src/search/provider/aligned_file_reader/reader/linux.rs @@ -42,7 +42,7 @@ impl LinuxAlignedFileReader { let file = match open_result { Ok(file_handle) => file_handle, Err(err) => { - return Err(ANNError::log_io_error(err)); + return Err(ANNError::new(diskann::ANNErrorKind::IOError, err)); } }; @@ -80,7 +80,7 @@ impl LinuxAlignedFileReader { unsafe { ring.submission() .push(&read) - .map_err(ANNError::log_push_error)? + .map_err(|err| ANNError::new(diskann::ANNErrorKind::PushError, err))? }; Ok(()) } @@ -117,9 +117,10 @@ impl AlignedFileReader for LinuxAlignedFileReader { // Flush the completion queue. for cqe in ring.completion() { if cqe.result() < 0 { - return Err(ANNError::log_io_error(std::io::Error::from_raw_os_error( - cqe.result(), - ))); + return Err(ANNError::new( + diskann::ANNErrorKind::IOError, + std::io::Error::from_raw_os_error(cqe.result()), + )); } } } diff --git a/diskann-disk/src/search/provider/aligned_file_reader/reader/windows.rs b/diskann-disk/src/search/provider/aligned_file_reader/reader/windows.rs index c54fb036a..207cda66c 100644 --- a/diskann-disk/src/search/provider/aligned_file_reader/reader/windows.rs +++ b/diskann-disk/src/search/provider/aligned_file_reader/reader/windows.rs @@ -38,7 +38,7 @@ impl WindowsAlignedFileReader { match unsafe { FileHandle::new(fname) } { Ok(file_handle) => io_context.file_handle = file_handle, Err(err) => { - return Err(ANNError::log_io_error(err)); + return Err(ANNError::new(diskann::ANNErrorKind::IOError, err)); } } @@ -46,7 +46,7 @@ impl WindowsAlignedFileReader { match IOCompletionPort::new(&io_context.file_handle, None, 0, 0) { Ok(io_completion_port) => io_context.io_completion_port = io_completion_port, Err(err) => { - return Err(ANNError::log_io_error(err)); + return Err(ANNError::new(diskann::ANNErrorKind::IOError, err)); } } @@ -82,7 +82,7 @@ impl AlignedFileReader for WindowsAlignedFileReader { } { Ok(_) => {} Err(error) => { - return Err(ANNError::log_io_error(error)); + return Err(ANNError::new(diskann::ANNErrorKind::IOError, error)); } } } @@ -108,7 +108,7 @@ impl AlignedFileReader for WindowsAlignedFileReader { thread::sleep(ASYNC_IO_COMPLETION_CHECK_INTERVAL); } // An error ocurred. - Err(error) => return Err(ANNError::log_io_error(error)), + Err(error) => return Err(ANNError::new(diskann::ANNErrorKind::IOError, error)), } } } diff --git a/diskann-disk/src/search/provider/disk_sector_graph.rs b/diskann-disk/src/search/provider/disk_sector_graph.rs index 68a47eb92..c9044c26f 100644 --- a/diskann-disk/src/search/provider/disk_sector_graph.rs +++ b/diskann-disk/src/search/provider/disk_sector_graph.rs @@ -78,7 +78,7 @@ impl DiskSectorGraph { max_n_batch_sector_read * num_sectors_per_node * block_size, AlignedAllocator::new(AlignedReaderType::Alignment::VALUE), ) - .map_err(ANNError::log_index_error)?, + .map_err(|err| ANNError::new(diskann::ANNErrorKind::IndexError, err))?, cur_sector_idx: 0, num_nodes_per_sector, node_len, @@ -97,7 +97,7 @@ impl DiskSectorGraph { max_n_batch_sector_read * self.num_sectors_per_node * self.block_size, AlignedAllocator::new(AlignedReaderType::Alignment::VALUE), ) - .map_err(ANNError::log_index_error)?; + .map_err(|err| ANNError::new(diskann::ANNErrorKind::IndexError, err))?; } Ok(()) } @@ -112,7 +112,7 @@ impl DiskSectorGraph { pub fn read_graph(&mut self, sectors_to_fetch: &[u64]) -> ANNResult<()> { let cur_sector_idx_usize: usize = self.cur_sector_idx.try_into()?; if sectors_to_fetch.len() > self.max_n_batch_sector_read - cur_sector_idx_usize { - return Err(ANNError::log_index_error(format_args!( + return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "Trying to read too many sectors. number of sectors to read: {}, max number of sectors can read: {}", sectors_to_fetch.len(), self.max_n_batch_sector_read - cur_sector_idx_usize, @@ -121,10 +121,13 @@ impl DiskSectorGraph { let len_per_node = self.num_sectors_per_node * self.block_size; if len_per_node == 0 { - return Err(ANNError::log_index_error(format_args!( - "len_per_node is 0 (num_sectors_per_node={}, block_size={})", - self.num_sectors_per_node, self.block_size, - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "len_per_node is 0 (num_sectors_per_node={}, block_size={})", + self.num_sectors_per_node, self.block_size, + ), + )); } let range = cur_sector_idx_usize * len_per_node ..(cur_sector_idx_usize + sectors_to_fetch.len()) * len_per_node; diff --git a/diskann-disk/src/search/provider/disk_vertex_provider.rs b/diskann-disk/src/search/provider/disk_vertex_provider.rs index 80b701752..3a9154a3f 100644 --- a/diskann-disk/src/search/provider/disk_vertex_provider.rs +++ b/diskann-disk/src/search/provider/disk_vertex_provider.rs @@ -80,9 +80,9 @@ where match self.loaded_nodes.get(vertex_id) { Some(local_offset) => Ok(&self.vector_buf [local_offset.idx * self.dim..(local_offset.idx * self.dim) + self.dim]), - None => Err(ANNError::log_get_vertex_data_error( - vertex_id.to_string(), - "Vector".to_string(), + None => Err(ANNError::from_display( + diskann::ANNErrorKind::GetVertexDataError, + format!("vertex_id: {vertex_id} data_type: Vector"), )), } } @@ -93,9 +93,9 @@ where ) -> ANNResult<&[Data::VectorIdType]> { match self.loaded_nodes.get(vertex_id) { Some(local_offset) => Ok(&self.cached_adjacency_list[local_offset.vec_idx]), - None => Err(ANNError::log_get_vertex_data_error( - vertex_id.to_string(), - "AdjacencyList".to_string(), + None => Err(ANNError::from_display( + diskann::ANNErrorKind::GetVertexDataError, + format!("vertex_id: {vertex_id} data_type: AdjacencyList"), )), } } @@ -106,9 +106,9 @@ where ) -> ANNResult<&Data::AssociatedDataType> { match self.loaded_nodes.get(vertex_id) { Some(local_offset) => Ok(&self.cached_associated_data[local_offset.vec_idx]), - None => Err(ANNError::log_get_vertex_data_error( - vertex_id.to_string(), - "AssociatedData".to_string(), + None => Err(ANNError::from_display( + diskann::ANNErrorKind::GetVertexDataError, + format!("vertex_id: {vertex_id} data_type: AssociatedData"), )), } } @@ -171,9 +171,9 @@ where &neighbor_and_data_buf[data_end - self.associated_data_size..data_end], ) .map_err(|err| { - ANNError::log_serde_error( - "Error deserializing associated data from bytes".to_string(), - *err, + ANNError::from_display( + diskann::ANNErrorKind::SerdeError, + format!("Operation: Error deserializing associated data from bytes Error: {err}"), ) })?; self.cached_associated_data.push(associated_data); diff --git a/diskann-disk/src/search/provider/disk_vertex_provider_factory.rs b/diskann-disk/src/search/provider/disk_vertex_provider_factory.rs index f57dc12c8..000cce56f 100644 --- a/diskann-disk/src/search/provider/disk_vertex_provider_factory.rs +++ b/diskann-disk/src/search/provider/disk_vertex_provider_factory.rs @@ -5,7 +5,7 @@ use std::{cmp::min, collections::VecDeque, sync::Arc, time::Instant}; use crate::data_model::GraphDataType; -use diskann::{graph::AdjacencyList, ANNError, ANNResult}; +use diskann::{graph::AdjacencyList, ANNError, ANNErrorKind, ANNResult}; use diskann_quantization::{ alloc::{AlignedAllocator, Poly}, num::PowerOfTwo, @@ -58,9 +58,12 @@ where let mut read_buf = Poly::broadcast( 0u8, buffer_len, - AlignedAllocator::new(PowerOfTwo::new(buffer_len).map_err(ANNError::log_index_error)?), + AlignedAllocator::new( + PowerOfTwo::new(buffer_len) + .map_err(|err| ANNError::new(ANNErrorKind::IndexError, err))?, + ), ) - .map_err(ANNError::log_index_error)?; + .map_err(|err| ANNError::new(ANNErrorKind::IndexError, err))?; let aligned_read = AlignedRead::new(0_u64, &mut read_buf)?; self.aligned_reader_factory .build()? @@ -84,7 +87,8 @@ where sector_reader, cache.clone(), ), - None => Err(ANNError::log_index_error( + None => Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Cache must be initialised for StaticCacheWithBfsNodes caching strategy", )), }, @@ -149,7 +153,7 @@ impl, ReaderFactory: AlignedReaderFactor match self.caching_strategy { CachingStrategy::StaticCacheWithBfsNodes(mut num_nodes_to_cache) => { if num_nodes_to_cache == 0 { - ANNError::log_index_error( + ANNError::from_display(diskann::ANNErrorKind::IndexError, "num_nodes_to_cache should be greater than 0 for StaticCacheWithBfsNodes caching strategy", ); } @@ -202,7 +206,10 @@ impl, ReaderFactory: AlignedReaderFactor let batch_size = min(queue.len(), BEAM_WIDTH_FOR_BFS); for _ in 0..batch_size { let node = queue.pop_front().ok_or_else(|| { - ANNError::log_index_error("Error while caching Nodes via BFS: Queue is empty") + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Error while caching Nodes via BFS: Queue is empty", + ) })?; nodes_in_a_batch.push(node); } @@ -212,7 +219,7 @@ impl, ReaderFactory: AlignedReaderFactor for (idx, node) in nodes_in_a_batch.iter().enumerate() { Self::insert_in_cache(node, idx, &mut vertex_provider, &mut cache)?; let adjacency_list = cache.get_adjacency_list(node).ok_or_else(|| { - ANNError::log_index_error(format!("Error while caching Nodes via BFS: Adjacency List not found for inserted node {} in cache.", node)) + ANNError::from_display(diskann::ANNErrorKind::IndexError, format!("Error while caching Nodes via BFS: Adjacency List not found for inserted node {} in cache.", node)) })?; for neighbor_id in adjacency_list.iter() { if !visited.contains(neighbor_id) { diff --git a/diskann-disk/src/storage/cached_reader.rs b/diskann-disk/src/storage/cached_reader.rs index 3326d7607..6e7187871 100644 --- a/diskann-disk/src/storage/cached_reader.rs +++ b/diskann-disk/src/storage/cached_reader.rs @@ -76,7 +76,7 @@ where // case 2: cache contains some data let cached_bytes = self.cache_size - self.cur_off; if n_bytes - cached_bytes > self.size - self.reader.stream_position()? { - return Err(ANNError::log_index_error(format_args!( + return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "Reading beyond end of file, n_bytes: {} cached_bytes: {} fsize: {} current pos: {}", n_bytes, cached_bytes, diff --git a/diskann-disk/src/storage/disk_index_writer.rs b/diskann-disk/src/storage/disk_index_writer.rs index 7c26180f2..b3507faa9 100644 --- a/diskann-disk/src/storage/disk_index_writer.rs +++ b/diskann-disk/src/storage/disk_index_writer.rs @@ -99,10 +99,10 @@ impl DiskIndexWriter { block_size: usize, ) -> ANNResult { if block_size < GraphMetadata::get_size() { - return Err(ANNError::log_index_config_error( - "index_block_size".to_string(), + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexConfigError, format!( - "block_size should be greater than the size of GraphMetadata: {}", + "index_block_size is invalid, err = block_size should be greater than the size of GraphMetadata: {}", GraphMetadata::get_size() ), )); @@ -138,7 +138,10 @@ impl DiskIndexWriter { if let Some(vamana_reader) = state.muti_shard_index_reader.as_mut() { num_nbrs = vamana_reader.read_u32::()?; } else { - return Err(ANNError::log_index_error("invalid index reader")); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "invalid index reader", + )); } Ok(num_nbrs) @@ -154,7 +157,10 @@ impl DiskIndexWriter { if let Some(vamana_reader) = state.muti_shard_index_reader.as_mut() { vamana_reader.read_exact(nbrs_buf)?; } else { - return Err(ANNError::log_index_error("invalid index reader")); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "invalid index reader", + )); } Ok(()) @@ -193,7 +199,10 @@ impl DiskIndexWriter { return Ok(()); } - Err(ANNError::log_index_error("invalid index reader")) + Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "invalid index reader", + )) } fn open_associated_data_reader( @@ -218,7 +227,7 @@ impl DiskIndexWriter { let length = associated_data_reader.read_u32()? as usize; if state.num_pts != associated_data_num_pts { - return Err(ANNError::log_index_error(format_args!( + return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "Number of points in dataset file ({}) does not match number of points in associated data file ({}).", state.num_pts, associated_data_num_pts ))); diff --git a/diskann-disk/src/storage/quant/generator.rs b/diskann-disk/src/storage/quant/generator.rs index 7c09c1182..1fb3dd756 100644 --- a/diskann-disk/src/storage/quant/generator.rs +++ b/diskann-disk/src/storage/quant/generator.rs @@ -78,12 +78,14 @@ where let metadata = load_metadata_from_file(storage_provider, &self.data_path)?; let (num_points, dim) = metadata.into_dims(); if max_block_size == 0 { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Data compression chunk vector count must be greater than zero", )); } if num_points == 0 { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Cannot generate compressed data for an empty dataset", )); } diff --git a/diskann-disk/src/storage/quant/pq/pq_dataset.rs b/diskann-disk/src/storage/quant/pq/pq_dataset.rs index 5dc31e3b3..5adec9ff2 100644 --- a/diskann-disk/src/storage/quant/pq/pq_dataset.rs +++ b/diskann-disk/src/storage/quant/pq/pq_dataset.rs @@ -28,7 +28,12 @@ impl PQData { pq_pivot_table.view_pivots(), pq_pivot_table.view_offsets().to_owned(), ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })?; Ok(Self { pq_pivot_table, @@ -64,7 +69,10 @@ impl PQData { // Get compressed vector with the given vector id from the pq_compressed_data. pub fn get_compressed_vector(&self, vector_id: usize) -> ANNResult<&[u8]> { self.pq_compressed_data.get_row(vector_id).ok_or_else(|| { - ANNError::log_index_error("Vector id is out of boundary in the compressed dataset.") + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Vector id is out of boundary in the compressed dataset.", + ) }) } } diff --git a/diskann-disk/src/storage/quant/pq/pq_generation.rs b/diskann-disk/src/storage/quant/pq/pq_generation.rs index b1eae30c3..824b649d6 100644 --- a/diskann-disk/src/storage/quant/pq/pq_generation.rs +++ b/diskann-disk/src/storage/quant/pq/pq_generation.rs @@ -59,7 +59,8 @@ where fn new(context: &Self::CompressorContext) -> diskann::ANNResult { // validate that the number of chunks is correct. if context.num_chunks > context.dim { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: number of chunks more than dimension.", )); } @@ -134,7 +135,12 @@ where .bridge_err()? .to_owned(), ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })?; Ok(Self { table, @@ -149,9 +155,12 @@ where vector: MatrixBase<&[f32]>, output: MatrixBase<&mut [u8]>, ) -> Result<(), diskann::ANNError> { - self.table - .compress_into(vector, output) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err))) + self.table.compress_into(vector, output).map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + }) } fn compressed_bytes(&self) -> usize { diff --git a/diskann-disk/src/utils/kmeans.rs b/diskann-disk/src/utils/kmeans.rs index 7ee6ba384..417001cac 100644 --- a/diskann-disk/src/utils/kmeans.rs +++ b/diskann-disk/src/utils/kmeans.rs @@ -138,7 +138,8 @@ pub fn run_lloyds( for i in 0..max_reps { if *cancellation_token { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Cancellation requested by caller.", )); } @@ -178,18 +179,24 @@ fn select_random_pivots( rng: &mut impl Rng, ) -> ANNResult<()> { if num_points < num_centers { - return Err(ANNError::log_kmeans_error(format!( - "Number of points {} is less than number of centers {}", - num_points, num_centers - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, + format!( + "Number of points {} is less than number of centers {}", + num_points, num_centers + ), + )); } if pivot_data.len() != num_centers * dim { - return Err(ANNError::log_kmeans_error(format!( - "Pivot data buffer should be of size num_centers * dim = {} * {} = {}", - num_centers, - dim, - num_centers * dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, + format!( + "Pivot data buffer should be of size num_centers * dim = {} * {} = {}", + num_centers, + dim, + num_centers * dim + ), + )); } let mut picked = HashSet::new(); @@ -238,23 +245,30 @@ pub fn k_meanspp_selecting_pivots( pool: RayonThreadPoolRef<'_>, ) -> ANNResult<()> { if num_points > (1 << 23) { - return Err(ANNError::log_kmeans_error(format!( - "Number of points {} is greater than 8388608, and k-means++ can not process this. + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, + format!( + "Number of points {} is greater than 8388608, and k-means++ can not process this. Try selecting_random_pivots instead.", - num_points - ))); + num_points + ), + )); } if pivot_data.len() != num_centers * dim { - return Err(ANNError::log_kmeans_error(format!( - "Pivot data buffer should be of size num_centers * dim = {} * {} = {}", - num_centers, - dim, - num_centers * dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, + format!( + "Pivot data buffer should be of size num_centers * dim = {} * {} = {}", + num_centers, + dim, + num_centers * dim + ), + )); } if *cancellation_token { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Cancellation requested by caller.", )); } @@ -263,8 +277,12 @@ pub fn k_meanspp_selecting_pivots( let mut picked = HashSet::with_capacity(num_centers); let real_distribution = StandardUniform; - let int_distribution = Uniform::new(0, num_points) - .map_err(|_| ANNError::log_kmeans_error("cannot cluster an empty dataset".into()))?; + let int_distribution = Uniform::new(0, num_points).map_err(|_| { + ANNError::from_display( + diskann::ANNErrorKind::KMeansError, + "cannot cluster an empty dataset", + ) + })?; // Randomly select a node as the first pivot. let init_id = int_distribution.sample(rng); @@ -291,7 +309,8 @@ pub fn k_meanspp_selecting_pivots( // At the end of the loop we should have num_centers pivots. for _ in 1..num_centers { if *cancellation_token { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Cancellation requested by caller.", )); } @@ -329,7 +348,7 @@ pub fn k_meanspp_selecting_pivots( || (dart_val <= prefix_sum && *pivot_dist != 0.0f32)) { if picked.contains(&i) { - return Err(ANNError::log_kmeans_error( + return Err(ANNError::from_display(diskann::ANNErrorKind::KMeansError, "A pivot was sampled again, the condition on dart_val range should not have happened".to_string(), )); } @@ -341,7 +360,8 @@ pub fn k_meanspp_selecting_pivots( prefix_sum += *pivot_dist as f64; } if prefix_sum > sum { - return Err(ANNError::log_kmeans_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, "Prefix sum should not be greater than sum. If the for loop above ran to conclusion without break, prefix_sum should be equal to sum" @@ -351,7 +371,8 @@ pub fn k_meanspp_selecting_pivots( // We should have picked a pivot in this loop. // If not, there is a corner condition we might have missed and we should fix this function. if picked_pivot_id == num_points { - return Err(ANNError::log_kmeans_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::KMeansError, "Did not pick a pivot in this loop".to_string(), )); } diff --git a/diskann-disk/src/utils/math_util.rs b/diskann-disk/src/utils/math_util.rs index 16cfe612a..6547a4519 100644 --- a/diskann-disk/src/utils/math_util.rs +++ b/diskann-disk/src/utils/math_util.rs @@ -83,26 +83,33 @@ pub fn compute_vecs_l2sq( pool: RayonThreadPoolRef<'_>, ) -> ANNResult<()> { if dim == 0 { - return Err(ANNError::log_index_error(format_args!( - "dim must be non-zero" - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "dim must be non-zero", + )); } let expected_data_len = vecs_l2sq.len().checked_mul(dim).ok_or_else(|| { - ANNError::log_index_error(format_args!( - "vecs_l2sq.len() * dim overflowed: vecs_l2sq.len() ({}) * dim ({})", - vecs_l2sq.len(), - dim - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "vecs_l2sq.len() * dim overflowed: vecs_l2sq.len() ({}) * dim ({})", + vecs_l2sq.len(), + dim + ), + ) })?; if data.len() != expected_data_len { - return Err(ANNError::log_index_error(format_args!( - "data.len() ({}) should be vecs_l2sq.len() ({}) * dim ({})", - data.len(), - vecs_l2sq.len(), - dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "data.len() ({}) should be vecs_l2sq.len() ({}) * dim ({})", + data.len(), + vecs_l2sq.len(), + dim + ), + )); } if dim < 5 { @@ -144,10 +151,13 @@ pub fn compute_closest_centers_in_block( pool: RayonThreadPoolRef<'_>, ) -> ANNResult<()> { if k > num_centers { - return Err(ANNError::log_index_error(format_args!( - "k ({}) should be equal or less than num_centers ({})", - k, num_centers - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "k ({}) should be equal or less than num_centers ({})", + k, num_centers + ), + )); } let ones_a: Vec = vec![1.0; num_centers]; @@ -260,70 +270,94 @@ pub fn compute_closest_centers( pool: RayonThreadPoolRef<'_>, ) -> ANNResult<()> { if k > num_centers { - return Err(ANNError::log_index_error(format_args!( - "k ({}) should be equal or less than num_centers ({})", - k, num_centers - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "k ({}) should be equal or less than num_centers ({})", + k, num_centers + ), + )); } // Validate data slice length let expected_data_len = num_points.checked_mul(dim).ok_or_else(|| { - ANNError::log_index_error(format_args!( - "num_points * dim overflowed: num_points ({}) * dim ({})", - num_points, dim - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "num_points * dim overflowed: num_points ({}) * dim ({})", + num_points, dim + ), + ) })?; if data.len() != expected_data_len { - return Err(ANNError::log_index_error(format_args!( - "data.len() ({}) should equal num_points ({}) * dim ({})", - data.len(), - num_points, - dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "data.len() ({}) should equal num_points ({}) * dim ({})", + data.len(), + num_points, + dim + ), + )); } // Validate pivot_data slice length let expected_pivot_len = num_centers.checked_mul(dim).ok_or_else(|| { - ANNError::log_index_error(format_args!( - "num_centers * dim overflowed: num_centers ({}) * dim ({})", - num_centers, dim - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "num_centers * dim overflowed: num_centers ({}) * dim ({})", + num_centers, dim + ), + ) })?; if pivot_data.len() != expected_pivot_len { - return Err(ANNError::log_index_error(format_args!( - "pivot_data.len() ({}) should equal num_centers ({}) * dim ({})", - pivot_data.len(), - num_centers, - dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "pivot_data.len() ({}) should equal num_centers ({}) * dim ({})", + pivot_data.len(), + num_centers, + dim + ), + )); } let expected_closest_centers_len = num_points.checked_mul(k).ok_or_else(|| { - ANNError::log_index_error(format_args!( - "num_points * k overflowed: num_points ({}) * k ({})", - num_points, k - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "num_points * k overflowed: num_points ({}) * k ({})", + num_points, k + ), + ) })?; if closest_centers_ivf.len() != expected_closest_centers_len { - return Err(ANNError::log_index_error(format_args!( - "closest_centers_ivf.len() ({}) should equal num_points ({}) * k ({})", - closest_centers_ivf.len(), - num_points, - k - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "closest_centers_ivf.len() ({}) should equal num_points ({}) * k ({})", + closest_centers_ivf.len(), + num_points, + k + ), + )); } let mut owned_pts_norms_squared; let pts_norms_squared: &[f32] = if let Some(pts_norms) = pts_norms_squared { if pts_norms.len() != num_points { - return Err(ANNError::log_index_error(format_args!( - "pts_norms_squared.len() ({}) should equal num_points ({})", - pts_norms.len(), - num_points - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "pts_norms_squared.len() ({}) should equal num_points ({})", + pts_norms.len(), + num_points + ), + )); } pts_norms } else { diff --git a/diskann-disk/src/utils/partition.rs b/diskann-disk/src/utils/partition.rs index a8556f5d5..b8fe7fe6c 100644 --- a/diskann-disk/src/utils/partition.rs +++ b/diskann-disk/src/utils/partition.rs @@ -254,7 +254,8 @@ where let num_points = dataset_reader.read_u32()?; let base_dim = dataset_reader.read_u32()?; if base_dim != dim as u32 { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "dimensions dont match for train set and base set", )); } diff --git a/diskann-providers/src/common/minmax_repr.rs b/diskann-providers/src/common/minmax_repr.rs index 19dc8ec96..c04a18675 100644 --- a/diskann-providers/src/common/minmax_repr.rs +++ b/diskann-providers/src/common/minmax_repr.rs @@ -54,10 +54,10 @@ pub enum MMConvertError { impl From for ANNError { fn from(value: MMConvertError) -> Self { - ANNError::log_index_error(format_args!( - "Unable to convert MinMaxElement slice, error : {:?}", - value - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Unable to convert MinMaxElement slice, error : {:?}", value), + ) } } diff --git a/diskann-providers/src/model/graph/provider/async_/common.rs b/diskann-providers/src/model/graph/provider/async_/common.rs index 74d0949dc..1b667beca 100644 --- a/diskann-providers/src/model/graph/provider/async_/common.rs +++ b/diskann-providers/src/model/graph/provider/async_/common.rs @@ -33,7 +33,8 @@ impl StartPoints { end: match valid_points.checked_add(frozen_points.get() as u32) { Some(end) => end, None => { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Sum of valid points and frozen points exceeds u32::MAX", )); } @@ -277,7 +278,7 @@ impl std::error::Error for Panics {} impl From for ANNError { #[cold] fn from(_: Panics) -> ANNError { - ANNError::log_async_error("unreachable") + ANNError::from_display(diskann::ANNErrorKind::AsyncError, "unreachable") } } diff --git a/diskann-providers/src/model/graph/provider/async_/experimental/multi_pq_async.rs b/diskann-providers/src/model/graph/provider/async_/experimental/multi_pq_async.rs index db158a4b8..c6bd4ae17 100644 --- a/diskann-providers/src/model/graph/provider/async_/experimental/multi_pq_async.rs +++ b/diskann-providers/src/model/graph/provider/async_/experimental/multi_pq_async.rs @@ -79,7 +79,10 @@ impl TestMultiPQProviderAsync { T: VectorRepr, { let table = self.multi_table().map_err(|err| { - ANNError::log_index_error(format_args!("Table construction failed with: {}", err)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Table construction failed with: {}", err), + ) })?; Ok(NoneToInfinity(QueryComputer::new( table, @@ -90,7 +93,10 @@ impl TestMultiPQProviderAsync { pub fn get_distance_computer(&self) -> ANNResult>> { let table = self.multi_table().map_err(|err| { - ANNError::log_index_error(format_args!("Table construction failed with: {}", err)) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!("Table construction failed with: {}", err), + ) })?; Ok(NoneToInfinity(DistanceComputer::new(table, self.metric))) } @@ -98,7 +104,8 @@ impl TestMultiPQProviderAsync { pub fn get_vector(&self, id: usize) -> ANNResult>> { match self.quant_vectors.get(id) { Some(vector) => Ok(vector.load()), - None => Err(ANNError::log_index_error( + None => Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )), } @@ -109,12 +116,14 @@ impl TestMultiPQProviderAsync { T: Copy + Into, { if id >= self.max_vectors + self.num_start_points { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } if v.len() != self.table_new.get_dim() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } @@ -132,7 +141,10 @@ impl TestMultiPQProviderAsync { Some(table_old) => { let v: f64 = { let mut guard = self.rng.lock().map_err(|_| { - ANNError::log_lock_poison_error("in multi provider".to_string()) + ANNError::from_display( + diskann::ANNErrorKind::LockPoisonError, + "in multi provider".to_string(), + ) })?; guard.random() }; @@ -154,7 +166,10 @@ impl TestMultiPQProviderAsync { ) .is_err() { - return Err(ANNError::log_index_error("Error in generating PQ data.")); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "Error in generating PQ data.", + )); } let new = Arc::new(VersionedPQVector::new(quant_vector, version)); diff --git a/diskann-providers/src/model/graph/provider/async_/fast_memory_quant_vector_provider.rs b/diskann-providers/src/model/graph/provider/async_/fast_memory_quant_vector_provider.rs index 420d6af37..502b76c28 100644 --- a/diskann-providers/src/model/graph/provider/async_/fast_memory_quant_vector_provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/fast_memory_quant_vector_provider.rs @@ -161,7 +161,8 @@ impl FastMemoryQuantVectorProviderAsync { T: VectorRepr, { if i >= self.total() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } @@ -169,7 +170,8 @@ impl FastMemoryQuantVectorProviderAsync { let vf32: &[f32] = &T::as_f32(v).into_ann_result()?; if vf32.len() != self.full_dim() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector f32 dimension is not equal to the expected dimension.", )); } @@ -208,12 +210,14 @@ impl FastMemoryQuantVectorProviderAsync { /// 2. Be okay with racey data. pub(crate) unsafe fn set_quant_vector(&self, i: usize, v: &[u8]) -> ANNResult<()> { if i >= self.total() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } if v.len() != self.pq_chunks() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } diff --git a/diskann-providers/src/model/graph/provider/async_/fast_memory_vector_provider.rs b/diskann-providers/src/model/graph/provider/async_/fast_memory_vector_provider.rs index ff5d24008..51b029e5d 100644 --- a/diskann-providers/src/model/graph/provider/async_/fast_memory_vector_provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/fast_memory_vector_provider.rs @@ -144,12 +144,14 @@ impl FastMemoryVectorProviderAsync { #[inline(always)] pub(crate) unsafe fn set_vector_sync(&self, i: usize, v: &[T]) -> ANNResult<()> { if v.len() != self.dim { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } if i >= self.total() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/provider.rs b/diskann-providers/src/model/graph/provider/async_/inmem/provider.rs index 79c7ccdce..5e00fc313 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/provider.rs @@ -402,11 +402,14 @@ where { let start_points = self.start_points.range(); if itr.len() != start_points.len() { - return Err(ANNError::log_async_index_error(format!( - "expected `itr` to contain `{}` items, instead it has {}", - start_points.len(), - itr.len(), - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::AsyncIndexError, + format!( + "expected `itr` to contain `{}` items, instead it has {}", + start_points.len(), + itr.len(), + ), + )); } for (i, v) in std::iter::zip(start_points, itr) { @@ -504,11 +507,14 @@ where let valid_points = npts .checked_sub(ctx.num_frozen_points.get()) .ok_or_else(|| { - ANNError::log_index_error(format_args!( - "Expected {} start points but the stored index only has {} total points", - ctx.num_frozen_points.get(), - base_vectors.total(), - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "Expected {} start points but the stored index only has {} total points", + ctx.num_frozen_points.get(), + base_vectors.total(), + ), + ) })?; let start_points = StartPoints::new(valid_points as u32, ctx.num_frozen_points)?; Ok(Self { diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs index 561eaaec5..70dbdcb51 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs @@ -883,7 +883,7 @@ pub enum SQError { impl From for ANNError { #[cold] fn from(err: SQError) -> Self { - ANNError::log_sq_error(err) + ANNError::new(diskann::ANNErrorKind::SQError, err) } } diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs index 10f174a87..77fda0202 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs @@ -711,7 +711,7 @@ impl From for ANNError { #[cold] #[track_caller] fn from(err: RQError) -> Self { - ANNError::log_sq_error(err) + ANNError::new(diskann::ANNErrorKind::SQError, err) } } diff --git a/diskann-providers/src/model/graph/provider/async_/memory_quant_vector_provider.rs b/diskann-providers/src/model/graph/provider/async_/memory_quant_vector_provider.rs index 760f431cd..dd9692db8 100644 --- a/diskann-providers/src/model/graph/provider/async_/memory_quant_vector_provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/memory_quant_vector_provider.rs @@ -109,7 +109,8 @@ impl MemoryQuantVectorProviderAsync { self.num_get_calls.increment(); match self.quant_vectors.get(i) { Some(vector) => Ok(vector.load()), - None => Err(ANNError::log_index_error( + None => Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )), } @@ -129,7 +130,8 @@ impl MemoryQuantVectorProviderAsync { { let v_f32 = T::as_f32(v).map_err(|x| x.into())?; if v_f32.len() != self.full_dim() { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector f32 dimension is not equal to the expected dimension.", )); } @@ -151,7 +153,8 @@ impl MemoryQuantVectorProviderAsync { let slot = match self.quant_vectors.get(i) { Some(slot) => slot, None => { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } diff --git a/diskann-providers/src/model/graph/provider/async_/memory_vector_provider.rs b/diskann-providers/src/model/graph/provider/async_/memory_vector_provider.rs index b0523c1cf..b7132ce7b 100644 --- a/diskann-providers/src/model/graph/provider/async_/memory_vector_provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/memory_vector_provider.rs @@ -58,7 +58,8 @@ impl MemoryVectorProviderAsync { self.num_get_calls.increment(); match self.vectors.get(i) { Some(vector) => Ok(VectorGuard::from_guard(vector.load())), - None => Err(ANNError::log_index_error( + None => Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )), } @@ -72,14 +73,16 @@ impl MemoryVectorProviderAsync { /// * `v.dim() != self.dim()`: The slice must have the proper length. pub(crate) fn set_vector_sync(&self, i: usize, v: &[T]) -> ANNResult<()> { if v.len() != self.dim { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector dimension is not equal to the expected dimension.", )); } let slot = match self.vectors.get(i) { Some(slot) => slot, None => { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector id is out of boundary in the dataset.", )); } diff --git a/diskann-providers/src/model/graph/provider/async_/simple_neighbor_provider.rs b/diskann-providers/src/model/graph/provider/async_/simple_neighbor_provider.rs index 2125fb06a..56e246d7f 100644 --- a/diskann-providers/src/model/graph/provider/async_/simple_neighbor_provider.rs +++ b/diskann-providers/src/model/graph/provider/async_/simple_neighbor_provider.rs @@ -156,7 +156,7 @@ impl SimpleNeighborProviderAsync { // // Work backwards from this value to determine the internal `max_points`. let max_points = num_points.checked_sub(num_start_points).ok_or_else(|| { - ANNError::log_index_error(format_args!( + ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "expected {} start points but the on-disk dataset only has {} total points", num_start_points, num_points, )) diff --git a/diskann-providers/src/model/pq/distance/dynamic.rs b/diskann-providers/src/model/pq/distance/dynamic.rs index c3ee138ed..2202f5c0d 100644 --- a/diskann-providers/src/model/pq/distance/dynamic.rs +++ b/diskann-providers/src/model/pq/distance/dynamic.rs @@ -69,10 +69,13 @@ impl<'a> QueryComputer<'a> { ) -> ANNResult { let dim = table.get_dim(); if query.len() != dim { - return Err(ANNError::log_dimension_mismatch_error(format!( - "QueryComputer::new: expected query of length {dim}, got {}", - query.len() - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::DimensionMismatchError, + format!( + "QueryComputer::new: expected query of length {dim}, got {}", + query.len() + ), + )); } let result = match metric { Metric::L2 => Self::L2(TableL2::new(table, query, pool)?), diff --git a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs index 2973db8fd..42f7307f9 100644 --- a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs +++ b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs @@ -136,7 +136,12 @@ impl FixedChunkPQTable { MatrixBase::try_from(pq_table, len / dim, dim).bridge_err()?, ChunkOffsetsBase::new(chunk_offsets).bridge_err()?, ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })?; Ok(Self { table }) } @@ -159,7 +164,8 @@ impl FixedChunkPQTable { let dim = self.get_dim(); debug_assert_eq!(query.len(), dim); if aligned_pq_table_dist_scratch.len() < num_chunks * num_centers { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "aligned_pq_table_dist_scratch.len() should at least be num_pq_chunks * num_centers", )); } @@ -433,7 +439,10 @@ impl FixedChunkPQTable { // `ANNError` without violating the orphan rule. impl From> for ANNError { fn from(value: Bridge) -> ANNError { - ANNError::log_pq_error(diskann_quantization::error::format(&value.into_inner())) + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&value.into_inner()), + ) } } @@ -492,11 +501,14 @@ fn pq_dist_lookup( let dists_out = match dists_out.get_mut(..n_pts) { None => { - return Err(ANNError::log_pq_error(format_args!( - "ERROR: dists_out length: {} is less than n_pts: {}", - dists_out.len(), - n_pts - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "ERROR: dists_out length: {} is less than n_pts: {}", + dists_out.len(), + n_pts + ), + )); } Some(slice) => { slice.fill(0.0); @@ -604,11 +616,14 @@ fn aggregate_coords( pq_coordinate_scratch: &mut [u8], ) -> ANNResult<()> { if pq_coordinate_scratch.len() < ids.len() * num_pq_chunks { - return Err(ANNError::log_pq_error(format_args!( - "pq_coordinate_scratch doesn't have enough length. It has length {} but requires length {}", - pq_coordinate_scratch.len(), - ids.len() * num_pq_chunks - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "pq_coordinate_scratch doesn't have enough length. It has length {} but requires length {}", + pq_coordinate_scratch.len(), + ids.len() * num_pq_chunks + ), + )); } pq_coordinate_scratch[0..num_pq_chunks * ids.len()] @@ -1002,38 +1017,47 @@ mod fixed_chunk_pq_table_test { let offsets = read_bin_from::(&mut reader, 0)?; if offsets.nrows() != 4 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. \ Offsets don't contain correct metadata, \ # offsets = {}, but expecting 4.", - pq_pivots_path, - offsets.nrows() - ))); + pq_pivots_path, + offsets.nrows() + ), + )); } let file_offset_data = offsets.map(|x| x.into_usize()); let mut pivots = read_bin_from::(&mut reader, file_offset_data[(0, 0)])?; if pivots.nrows() != NUM_PQ_CENTROIDS { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_num_centers = {}, but expecting {} centers.", - pq_pivots_path, - pivots.nrows(), - NUM_PQ_CENTROIDS - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_num_centers = {}, but expecting {} centers.", + pq_pivots_path, + pivots.nrows(), + NUM_PQ_CENTROIDS + ), + )); } let dim = pivots.ncols(); let centroids = read_bin_from::(&mut reader, file_offset_data[(1, 0)])?; if centroids.nrows() != dim || centroids.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_dim = {}, \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_dim = {}, \ file_cols = {} but expecting {} entries in 1 dimension.", - pq_pivots_path, - centroids.nrows(), - centroids.ncols(), - dim - ))); + pq_pivots_path, + centroids.nrows(), + centroids.ncols(), + dim + ), + )); } pivots.row_iter_mut().for_each(|row| { @@ -1042,13 +1066,16 @@ mod fixed_chunk_pq_table_test { let chunk_offsets_m = read_bin_from::(&mut reader, file_offset_data[(2, 0)])?; if chunk_offsets_m.nrows() != num_pq_chunks + 1 || chunk_offsets_m.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file at chunk offsets; \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file at chunk offsets; \ file has nr={}, nc={} but expecting nr={} and nc=1.", - chunk_offsets_m.nrows(), - chunk_offsets_m.ncols(), - num_pq_chunks + 1 - ))); + chunk_offsets_m.nrows(), + chunk_offsets_m.ncols(), + num_pq_chunks + 1 + ), + )); } let chunk_offsets = chunk_offsets_m.map(|x| x.into_usize()); diff --git a/diskann-providers/src/model/pq/generate_pivot_arguments.rs b/diskann-providers/src/model/pq/generate_pivot_arguments.rs index a70252f8a..16d32a777 100644 --- a/diskann-providers/src/model/pq/generate_pivot_arguments.rs +++ b/diskann-providers/src/model/pq/generate_pivot_arguments.rs @@ -62,7 +62,7 @@ pub enum GeneratePivotArgumentsError { impl From for ANNError { #[track_caller] fn from(value: GeneratePivotArgumentsError) -> Self { - ANNError::log_pq_error(value) + ANNError::from_display(diskann::ANNErrorKind::PQError, value) } } diff --git a/diskann-providers/src/model/pq/pq_construction.rs b/diskann-providers/src/model/pq/pq_construction.rs index 8ca3f11a4..e70b626db 100644 --- a/diskann-providers/src/model/pq/pq_construction.rs +++ b/diskann-providers/src/model/pq/pq_construction.rs @@ -108,10 +108,15 @@ where None }; - let dim = NonZeroUsize::new(parameters.dim()) - .ok_or_else(|| ANNError::log_pq_error("dim must be non-zero"))?; - let num_chunks = NonZeroUsize::new(parameters.num_pq_chunks()) - .ok_or_else(|| ANNError::log_pq_error("num_pq_chunks must be non-zero"))?; + let dim = NonZeroUsize::new(parameters.dim()).ok_or_else(|| { + ANNError::from_display(diskann::ANNErrorKind::PQError, "dim must be non-zero") + })?; + let num_chunks = NonZeroUsize::new(parameters.num_pq_chunks()).ok_or_else(|| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + "num_pq_chunks must be non-zero", + ) + })?; let chunk_offsets = ChunkOffsets::partition(dim, num_chunks).bridge_err()?; let trainer = diskann_quantization::product::train::LightPQTrainingParameters::new( @@ -129,7 +134,12 @@ where &random_provider, &diskann_quantization::cancel::DontCancel, ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))? + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })? .flatten(); Ok(result) })?; @@ -170,19 +180,22 @@ pub fn generate_pq_pivots_from_membuf>( pool: RayonThreadPoolRef<'_>, ) -> ANNResult<()> { if full_pivot_data.len() != parameters.num_centers() * parameters.dim() { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: full_pivot_data size is not num_centers * dim.", )); } if offsets.len() != parameters.num_pq_chunks() + 1 { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: invalid offsets buffer input size.", )); } if *cancellation_token { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Cancellation requested by caller.", )); } @@ -194,8 +207,9 @@ pub fn generate_pq_pivots_from_membuf>( .collect::>(); // Calculate the chunk offsets, filling the caller-owned buffer. - let dim = NonZeroUsize::new(parameters.dim()) - .ok_or_else(|| ANNError::log_pq_error("dim must be non-zero"))?; + let dim = NonZeroUsize::new(parameters.dim()).ok_or_else(|| { + ANNError::from_display(diskann::ANNErrorKind::PQError, "dim must be non-zero") + })?; let chunk_offsets_view = ChunkOffsetsView::partition_into(dim, offsets).bridge_err()?; let trainer = diskann_quantization::product::train::LightPQTrainingParameters::new( @@ -233,7 +247,12 @@ pub fn generate_pq_pivots_from_membuf>( &rng_builder, &cancelation, ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))? + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })? .flatten(); Ok(result) })?; @@ -346,7 +365,8 @@ where let full_dim: usize; if !pq_storage.pivot_data_exist(storage_provider) { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "ERROR: PQ k-means pivot file not found.", )); } else { @@ -395,7 +415,12 @@ where .bridge_err()? .to_owned(), ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })?; let mut buffer = vec![0.0; full_dim * block_size]; @@ -439,7 +464,10 @@ where .zip_eq(compressed_block.par_window_iter_mut(BATCH_SIZE)) .try_for_each_in_pool(pool, |(src, dst)| { table.compress_into(src, dst).map_err(|err| { - ANNError::log_pq_error(diskann_quantization::error::format(&err)) + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) }) })?; @@ -505,16 +533,24 @@ pub fn generate_pq_data_from_pivots_from_membuf>( MatrixView::try_from(pivot_data, num_pivots, dim).bridge_err()?, diskann_quantization::views::ChunkOffsetsView::new(offsets).bridge_err()?, ) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; + .map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + })?; let data = vector_data .iter() .map(|x| (*x).into()) .collect::>(); - table - .compress_into(data.as_slice(), pq_out) - .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err))) + table.compress_into(data.as_slice(), pq_out).map_err(|err| { + ANNError::from_display( + diskann::ANNErrorKind::PQError, + diskann_quantization::error::format(&err), + ) + }) } /// Legacy compatibility function for providing an batch data generation. @@ -542,12 +578,14 @@ pub fn generate_pq_data_from_pivots_from_membuf_batch let dim = parameters.dim(); if vector_data.len() != num_train * dim { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Vector data length has the incorrect size!", )); } if pq_out.len() != num_train * num_pq_chunks { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "Error: Invalid PQ buffer input size.", )); } diff --git a/diskann-providers/src/model/pq/strided.rs b/diskann-providers/src/model/pq/strided.rs index 4930e6b79..324c348d0 100644 --- a/diskann-providers/src/model/pq/strided.rs +++ b/diskann-providers/src/model/pq/strided.rs @@ -12,7 +12,10 @@ use crate::utils::Bridge; impl From>> for ANNError { #[track_caller] fn from(value: Bridge>) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new( + diskann::ANNErrorKind::PQError, + value.into_inner().as_static(), + ) } } diff --git a/diskann-providers/src/model/pq/views.rs b/diskann-providers/src/model/pq/views.rs index 17028de3c..d36569f7c 100644 --- a/diskann-providers/src/model/pq/views.rs +++ b/diskann-providers/src/model/pq/views.rs @@ -12,7 +12,7 @@ use crate::utils::Bridge; impl From> for ANNError { #[track_caller] fn from(value: Bridge) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new(diskann::ANNErrorKind::PQError, value.into_inner()) } } @@ -20,7 +20,7 @@ impl From> for ANNError { impl From> for ANNError { #[track_caller] fn from(value: Bridge) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new(diskann::ANNErrorKind::PQError, value.into_inner()) } } @@ -28,7 +28,7 @@ impl From> for ANNError { impl From> for ANNError { #[track_caller] fn from(value: Bridge) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new(diskann::ANNErrorKind::PQError, value.into_inner()) } } @@ -36,7 +36,7 @@ impl From> for ANNError impl From> for ANNError { #[track_caller] fn from(value: Bridge) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new(diskann::ANNErrorKind::PQError, value.into_inner()) } } @@ -44,7 +44,10 @@ impl From> for ANNError { impl From>> for ANNError { #[track_caller] fn from(value: Bridge>) -> Self { - ANNError::log_pq_error(value.into_inner()) + ANNError::new( + diskann::ANNErrorKind::PQError, + value.into_inner().as_static(), + ) } } diff --git a/diskann-providers/src/storage/bin.rs b/diskann-providers/src/storage/bin.rs index 9b607e715..4915d0625 100644 --- a/diskann-providers/src/storage/bin.rs +++ b/diskann-providers/src/storage/bin.rs @@ -136,10 +136,13 @@ where T: VectorRepr, { let metadata = load_metadata_from_file(provider, path).map_err(|err| { - ANNError::log_index_error(format_args!( - "failed to load data file \"{}\" due to the following error: {}", - path, err - )) + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "failed to load data file \"{}\" due to the following error: {}", + path, err + ), + ) })?; tracing::info!( @@ -195,7 +198,8 @@ where let len = slice.len(); if len != dim { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "data provider returned a vector with a dimension other than advertised", )); } diff --git a/diskann-providers/src/storage/index_storage.rs b/diskann-providers/src/storage/index_storage.rs index fc526aa1f..27125ed33 100644 --- a/diskann-providers/src/storage/index_storage.rs +++ b/diskann-providers/src/storage/index_storage.rs @@ -197,16 +197,21 @@ fn get_and_validate_single_starting_point( let num_starting_points = start_ids.len(); if num_starting_points > 1 { - return Err(ANNError::log_index_error(format_args!( - "ERROR: Save index does not support multiple starting points. Found {} starting points.", - num_starting_points - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "ERROR: Save index does not support multiple starting points. Found {} starting points.", + num_starting_points + ), + )); } - start_ids - .first() - .cloned() - .ok_or_else(|| ANNError::log_index_error("ERROR: No starting points found")) + start_ids.first().cloned().ok_or_else(|| { + ANNError::from_display( + diskann::ANNErrorKind::IndexError, + "ERROR: No starting points found", + ) + }) } /////////// // Tests // diff --git a/diskann-providers/src/storage/pq_storage.rs b/diskann-providers/src/storage/pq_storage.rs index a2d49391b..80f0d445a 100644 --- a/diskann-providers/src/storage/pq_storage.rs +++ b/diskann-providers/src/storage/pq_storage.rs @@ -184,12 +184,15 @@ impl PQStorage { let offsets = read_bin_from::(reader, 0)?; if offsets.nrows() != 4 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. Offsets don't contain correct \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. Offsets don't contain correct \ metadata, # offsets = {}, but expecting 4.", - &self.pivot_data_path, - offsets.nrows() - ))); + &self.pivot_data_path, + offsets.nrows() + ), + )); } let file_offset_data = offsets.map(|x| x.into_usize()); @@ -197,38 +200,47 @@ impl PQStorage { let pivots = read_bin_from::(reader, file_offset_data[(0, 0)])?; if pivots.nrows() != *num_centers || pivots.ncols() != *dim { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_num_centers = {}, \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_num_centers = {}, \ file_dim = {} but expecting {} centers in {} dimensions.", - &self.pivot_data_path, - pivots.nrows(), - pivots.ncols(), - num_centers, - dim - ))); + &self.pivot_data_path, + pivots.nrows(), + pivots.ncols(), + num_centers, + dim + ), + )); } let centroid_m = read_bin_from::(reader, file_offset_data[(1, 0)])?; if centroid_m.nrows() != *dim || centroid_m.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_dim = {}, \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_dim = {}, \ file_cols = {} but expecting {} entries in 1 dimension.", - &self.pivot_data_path, - centroid_m.nrows(), - centroid_m.ncols(), - dim - ))); + &self.pivot_data_path, + centroid_m.nrows(), + centroid_m.ncols(), + dim + ), + )); } let chunk_offsets_m = read_bin_from::(reader, file_offset_data[(2, 0)])?; if chunk_offsets_m.nrows() != *num_pq_chunks + 1 || chunk_offsets_m.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file at chunk offsets; \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file at chunk offsets; \ file has nr={}, nc={} but expecting nr={} and nc=1.", - chunk_offsets_m.nrows(), - chunk_offsets_m.ncols(), - num_pq_chunks + 1 - ))); + chunk_offsets_m.nrows(), + chunk_offsets_m.ncols(), + num_pq_chunks + 1 + ), + )); } let chunk_offsets = chunk_offsets_m.map(|x| x.into_usize()); @@ -261,13 +273,16 @@ impl PQStorage { let data = read_bin::(&mut storage_provider.open_reader(pq_compressed_data)?)?; if data.nrows() != num_points_to_load || data.ncols() != num_pq_chunks { - return Err(ANNError::log_pq_error(format_args!( - "PQ compressed data mismatch: file has {}x{} but expected {}x{}", - data.nrows(), - data.ncols(), - num_points_to_load, - num_pq_chunks - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "PQ compressed data mismatch: file has {}x{} but expected {}x{}", + data.nrows(), + data.ncols(), + num_points_to_load, + num_pq_chunks + ), + )); } info!("PQ compressed dataset loaded."); @@ -282,7 +297,8 @@ impl PQStorage { storage_provider: &Storage, ) -> ANNResult { if !storage_provider.exists(pq_pivots) { - return Err(ANNError::log_pq_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, "ERROR: PQ k-means pivot file not found.", )); } @@ -292,50 +308,62 @@ impl PQStorage { let mut reader = storage_provider.open_reader(pq_pivots)?; let offsets = read_bin_from::(&mut reader, 0)?; if offsets.nrows() != 4 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. Offsets don't contain correct metadata, \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. Offsets don't contain correct metadata, \ # offsets = {}, but expecting 4.", - pq_pivots, - offsets.nrows() - ))); + pq_pivots, + offsets.nrows() + ), + )); } let file_offset_data = offsets.map(|x| x.into_usize()); let mut pivots = read_bin_from::(&mut reader, file_offset_data[(0, 0)])?; if pivots.nrows() > NUM_PQ_CENTROIDS { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_num_centers = {}, but expecting {} centers.", - pq_pivots, - pivots.nrows(), - NUM_PQ_CENTROIDS - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_num_centers = {}, but expecting {} centers.", + pq_pivots, + pivots.nrows(), + NUM_PQ_CENTROIDS + ), + )); } let dim = pivots.ncols(); let centroids = read_bin_from::(&mut reader, file_offset_data[(1, 0)])?; if centroids.nrows() != dim || centroids.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file {}. file_dim = {}, file_cols = {} \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file {}. file_dim = {}, file_cols = {} \ but expecting {} entries in 1 dimension.", - pq_pivots, - centroids.nrows(), - centroids.ncols(), - dim - ))); + pq_pivots, + centroids.nrows(), + centroids.ncols(), + dim + ), + )); } let chunk_offsets_m = read_bin_from::(&mut reader, file_offset_data[(2, 0)])?; if (chunk_offsets_m.nrows() != num_pq_chunks + 1 && num_pq_chunks as u32 != 0) || chunk_offsets_m.ncols() != 1 { - return Err(ANNError::log_pq_error(format_args!( - "Error reading pq_pivots file at chunk offsets; file has nr={}, nc={} \ + return Err(ANNError::from_display( + diskann::ANNErrorKind::PQError, + format!( + "Error reading pq_pivots file at chunk offsets; file has nr={}, nc={} \ but expecting nr={} and nc=1. The expected num_pq_chunks should be \ passed as 0 if we want to infer.", - chunk_offsets_m.nrows(), - chunk_offsets_m.ncols(), - num_pq_chunks + 1 - ))); + chunk_offsets_m.nrows(), + chunk_offsets_m.ncols(), + num_pq_chunks + 1 + ), + )); } let chunk_offsets = chunk_offsets_m.map(|x| x.into_usize()); @@ -373,9 +401,9 @@ impl PQStorage { self.data_path .as_ref() .ok_or_else(|| { - ANNError::log_index_config_error( - "data_path".to_string(), - "pq_storage.data_path is not defined".to_string(), + ANNError::from_display( + diskann::ANNErrorKind::IndexConfigError, + "data_path is invalid, err = pq_storage.data_path is not defined", ) }) .map(|s| s.as_str()) diff --git a/diskann-providers/src/utils/file_util.rs b/diskann-providers/src/utils/file_util.rs index f5ebdadc6..f6a9762e9 100644 --- a/diskann-providers/src/utils/file_util.rs +++ b/diskann-providers/src/utils/file_util.rs @@ -72,18 +72,22 @@ pub fn load_multivec_bin> = Vec::with_capacity(num_points); diff --git a/diskann-providers/src/utils/medoid.rs b/diskann-providers/src/utils/medoid.rs index 696f3ee98..b69aceae6 100644 --- a/diskann-providers/src/utils/medoid.rs +++ b/diskann-providers/src/utils/medoid.rs @@ -33,7 +33,8 @@ where for (v, _) in iter { let vector = T::as_f32(&v).map_err(|x| x.into())?; if vector.len() != dimension { - return Err(ANNError::log_index_error( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Vector f32 dimension doesn't match input dim.", )); } @@ -111,7 +112,8 @@ where // If no vectors were processed, return error if !centroid_initialized { - Err(ANNError::log_index_error( + Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Trying to compute centroid on zero vectors", )) } else { @@ -184,12 +186,15 @@ where // Find medoid (point closest to centroid) let iter = VectorDataIterator::::new(path, None, reader)?; - let (medoid, medoid_id) = find_nearest_vector_with_id(iter, ¢roid)? - .ok_or_else(|| ANNError::log_index_error("medoid not found"))?; + let (medoid, medoid_id) = + find_nearest_vector_with_id(iter, ¢roid)?.ok_or_else(|| { + ANNError::from_display(diskann::ANNErrorKind::IndexError, "medoid not found") + })?; Ok((medoid.to_vec(), medoid_id)) } else { - Err(ANNError::log_index_error( + Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Medoid not calculable on zero length iterator", )) } @@ -240,8 +245,9 @@ where // Find medoid (point closest to centroid) from the full dataset let iter = VectorDataIterator::::new(path, None, reader)?; - let (medoid, medoid_id) = find_nearest_vector_with_id(iter, ¢roid)? - .ok_or_else(|| ANNError::log_index_error("medoid not found"))?; + let (medoid, medoid_id) = find_nearest_vector_with_id(iter, ¢roid)?.ok_or_else(|| { + ANNError::from_display(diskann::ANNErrorKind::IndexError, "medoid not found") + })?; Ok((medoid.to_vec(), medoid_id)) } diff --git a/diskann-providers/src/utils/rayon_util.rs b/diskann-providers/src/utils/rayon_util.rs index ac5c2101d..9c05fc01c 100644 --- a/diskann-providers/src/utils/rayon_util.rs +++ b/diskann-providers/src/utils/rayon_util.rs @@ -11,7 +11,9 @@ pub fn create_thread_pool(num_threads: usize) -> ANNResult { let pool = rayon::ThreadPoolBuilder::new() .num_threads(num_threads) .build() - .map_err(|err| ANNError::log_thread_pool_error(err.to_string()))?; + .map_err(|err| { + ANNError::from_display(diskann::ANNErrorKind::ThreadPoolError, err.to_string()) + })?; Ok(RayonThreadPool(pool)) } @@ -37,7 +39,9 @@ pub fn create_thread_pool_for_test() -> RayonThreadPool { pub fn create_thread_pool_for_bench() -> RayonThreadPool { let pool = rayon::ThreadPoolBuilder::new() .build() - .map_err(|err| ANNError::log_thread_pool_error(err.to_string())) + .map_err(|err| { + ANNError::from_display(diskann::ANNErrorKind::ThreadPoolError, err.to_string()) + }) .unwrap(); RayonThreadPool(pool) } diff --git a/diskann-providers/src/utils/sampling.rs b/diskann-providers/src/utils/sampling.rs index f5af47a07..08abd1da9 100644 --- a/diskann-providers/src/utils/sampling.rs +++ b/diskann-providers/src/utils/sampling.rs @@ -146,10 +146,13 @@ where let expected_size = 8 + (npts as u64 * dim as u64 * std::mem::size_of::() as u64); let actual_size = storage_provider.get_length(data_file)?; if actual_size != expected_size { - return Err(ANNError::log_invalid_file_format(format!( - "Vector file '{}' has invalid format: size {} bytes doesn't match expected size of {} bytes based on header ({} vectors of dimension {})", - data_file, actual_size, expected_size, npts, dim - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::InvalidFileFormatError, + format!( + "Vector file '{}' has invalid format: size {} bytes doesn't match expected size of {} bytes based on header ({} vectors of dimension {})", + data_file, actual_size, expected_size, npts, dim + ), + )); } Ok(Self { @@ -179,11 +182,14 @@ where for idx in indices { // Check if the index is within bounds if idx >= self.npts { - return Err(ANNError::log_index_error(format!( - "Vector index {} is out of bounds (max: {})", - idx, - self.npts - 1 - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "Vector index {} is out of bounds (max: {})", + idx, + self.npts - 1 + ), + )); } let offset = (idx as i64 - self.cur_pos as i64) * vector_len as i64; if offset != 0 { @@ -270,7 +276,8 @@ pub fn gen_random_slice( Ok((sampled_vectors, sampled_count, full_dim)) } else { - Err(ANNError::log_index_error( + Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, "Could not read vectors to sample from.", )) } diff --git a/diskann-tools/src/utils/search_index_utils.rs b/diskann-tools/src/utils/search_index_utils.rs index 176f2e1ec..91a68b693 100644 --- a/diskann-tools/src/utils/search_index_utils.rs +++ b/diskann-tools/src/utils/search_index_utils.rs @@ -221,19 +221,25 @@ pub fn calculate_filtered_search_recall( k_recall: u32, ) -> ANNResult { if k_recall == 0 { - return Err(ANNError::log_index_error(format_args!( - "k_recall value must be greater than 0, but got {}", - k_recall - ))); + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( + "k_recall value must be greater than 0, but got {}", + k_recall + ), + )); } if groundtruth.len() != num_queries || our_results.len() != num_queries { - return Err(ANNError::log_index_error(format_args!( + return Err(ANNError::from_display( + diskann::ANNErrorKind::IndexError, + format!( "groundtruth length ({}) or our_results length ({}) does not match num_queries ({})", groundtruth.len(), our_results.len(), num_queries - ))); + ), + )); } let mut total_recall = 0.0; @@ -257,7 +263,7 @@ pub fn calculate_filtered_search_recall( let gt_dist_vec = gt_dist[i].as_slice(); if gt_dist_vec.len() != groundtruth[i].len() { - return Err(ANNError::log_index_error(format_args!( + return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "Ground truth distance for query ({}) vector length ({}) is not equal to groundtruth len ({})", i, gt_dist_vec.len(), @@ -314,7 +320,7 @@ pub fn load_truthset( let truthset_type : i32 = match actual_file_size { x if x == expected_file_size_with_dists => 1, x if x == expected_file_size_just_ids => 2, - _ => return Err(ANNError::log_index_error(format_args!( + _ => return Err(ANNError::from_display(diskann::ANNErrorKind::IndexError, format!( "Error. File size mismatch. File should have bin format, with npts followed by ngt followed by npts*ngt ids and optionally followed by npts*ngt distance values; actual size: {}, expected: {} or {}", actual_file_size, expected_file_size_with_dists, diff --git a/diskann/src/error/ann_error.rs b/diskann/src/error/ann_error.rs index c27e622c1..ee15714b5 100644 --- a/diskann/src/error/ann_error.rs +++ b/diskann/src/error/ann_error.rs @@ -14,6 +14,28 @@ use std::{ use crate::always_escalate; +/// Error wrapper for values that should be carried by `ANNError` through their +/// `Display` implementation. +#[derive(Debug)] +pub struct DisplayError(D); + +impl DisplayError { + pub fn new(display: D) -> Self { + Self(display) + } +} + +impl Display for DisplayError +where + D: Display, +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + Display::fmt(&self.0, formatter) + } +} + +impl std::error::Error for DisplayError where D: Display + Debug + Send + Sync + 'static {} + /// Convenience alias for a `Result`. pub type ANNResult = Result; @@ -66,20 +88,6 @@ pub type ANNResult = Result; /// /// Backtrace collection adds a time overhead to error collection. /// -/// # Legacy API -/// -/// The `log_*` prefixed constructors exist to maintain compatibility with an earlier -/// iteration of this struct. These constructors set an internal `ANNErrorKind` and have -/// the side effect of logging the constructed object at an `Error` level. -/// -/// The log records associated with these messages contain the following keyed metadata: -/// -/// * "diskann.file" (&str) - The file of the constructor's caller. -/// * "diskann.line" (&str) - The line within the file of the constructor's caller. -/// -/// This can lead to double logging as errors are logged upon creation, and the logged again -/// upon reaching the top level. -/// /// # Properties /// /// `ANNError` has the following properties to support efficiency: @@ -190,6 +198,20 @@ impl ANNError { } } + /// Construct a new `ANNError` from a display value. + /// + /// Prefer a concrete error type with [`ANNError::new`] when the callsite can describe + /// a precise failure. This helper is useful when adapting existing display-only error + /// paths away from the legacy `log_*` constructors. + #[track_caller] + #[inline(never)] + pub fn from_display(kind: ANNErrorKind, display: D) -> Self + where + D: Display + Debug + Send + Sync + 'static, + { + Self::new(kind, DisplayError::new(display)) + } + /// Attempt to downcast the error object to a concrete type. pub fn downcast(self) -> Result where @@ -250,252 +272,6 @@ impl ANNError { pub fn kind(&self) -> ANNErrorKind { self.kind } - - ///////////////////////////// - // Compatibility interface // - ///////////////////////////// - - /// Create, log and return IndexError - #[track_caller] - #[inline(never)] - pub fn log_index_error(err: D) -> Self { - Self::message(ANNErrorKind::IndexError, err.to_string()) - } - - /// Create, log and return FileHandleError - #[track_caller] - #[inline(never)] - pub fn log_file_handle_error(err: D) -> Self { - Self::message(ANNErrorKind::FileHandleError, err.to_string()) - } - - /// Create, log and return FileNotFoundError - #[track_caller] - #[inline(never)] - pub fn log_file_not_found_error(err: String) -> Self { - Self::message(ANNErrorKind::FileNotFoundError, err) - } - - /// Create, log and return GroundTruthError - #[track_caller] - #[inline(never)] - pub fn log_ground_truth_error(err: String) -> Self { - Self::message(ANNErrorKind::GroundTruthError, err) - } - - /// Create, log and return IndexConfigError - #[track_caller] - #[inline(never)] - pub fn log_index_config_error(parameter: String, err: String) -> Self { - Self::message( - ANNErrorKind::IndexConfigError, - format!("{} is invalid, err = {}", parameter, err), - ) - } - - /// Create, log and return TryFromIntError - #[track_caller] - #[inline(never)] - pub fn log_try_from_int_error(err: TryFromIntError) -> Self { - Self::new(ANNErrorKind::TryFromIntError, err) - } - - /// Create, log and return IOError - #[track_caller] - #[inline(never)] - pub fn log_io_error(err: io::Error) -> Self { - Self::new(ANNErrorKind::IOError, err) - } - - /// Create, log and return IOSendError - #[track_caller] - #[inline(never)] - pub fn log_io_send_error(err: mpsc::SendError) -> Self { - Self::new(ANNErrorKind::IOSendError, err) - } - - /// Create, log and return DiskIOAlignmentError - #[track_caller] - #[inline(never)] - pub fn log_disk_io_request_alignment_error(err: String) -> Self { - Self::message(ANNErrorKind::DiskIOAlignmentError, err) - } - - /// Create, log and return IOError - #[track_caller] - #[inline(never)] - pub fn log_mem_alloc_layout_error(err: LayoutError) -> Self { - Self::new(ANNErrorKind::MemoryAllocLayoutError, err) - } - - /// Create, log and return LockPoisonError - #[track_caller] - #[inline(never)] - pub fn log_lock_poison_error(err: String) -> Self { - Self::message(ANNErrorKind::LockPoisonError, err) - } - - /// Create, log and return PQError - #[track_caller] - #[inline(never)] - pub fn log_pq_error(err: D) -> Self { - Self::message(ANNErrorKind::PQError, err.to_string()) - } - - /// Create, log and return SQError - #[track_caller] - #[inline(never)] - pub fn log_sq_error(err: E) -> Self - where - E: std::error::Error + Send + Sync + 'static, - { - Self::new(ANNErrorKind::SQError, err) - } - - /// Create, log and return KMeansError - #[track_caller] - #[inline(never)] - pub fn log_kmeans_error(err: String) -> Self { - Self::message(ANNErrorKind::KMeansError, err) - } - - /// Create, log and return KMeansError - #[track_caller] - #[inline(never)] - pub fn log_push_error(err: E) -> Self - where - E: std::error::Error + Send + Sync + 'static, - { - Self::new(ANNErrorKind::PushError, err) - } - - /// Create, log and return TryFromSliceError - #[track_caller] - #[inline(never)] - pub fn log_try_from_slice_error(err: TryFromSliceError) -> Self { - Self::new(ANNErrorKind::TryFromSliceError, err) - } - - /// Create, log and return Serde error. - #[track_caller] - #[inline(never)] - pub fn log_serde_error(operation: String, err: D) -> Self - where - D: Display, - { - Self::message( - ANNErrorKind::SerdeError, - format!("Operation: {} Error: {}", operation, err), - ) - } - - /// Create, log and return get vertex data error. - #[track_caller] - #[inline(never)] - pub fn log_get_vertex_data_error(vertex_id: String, data_type: String) -> Self { - Self::message( - ANNErrorKind::GetVertexDataError, - format!("vertex_id: {} data_type: {}", vertex_id, data_type), - ) - } - - /// Create, log and return parse slice error. - #[track_caller] - #[inline(never)] - pub fn log_parse_slice_error( - parsing_source: String, - parsing_target: String, - err: String, - ) -> Self { - Self::message( - ANNErrorKind::ParseSliceError, - format!( - "source: {} target: {} error: {}", - parsing_source, parsing_target, err - ), - ) - } - - #[track_caller] - #[inline(never)] - pub fn log_thread_pool_error(err: String) -> Self { - Self::message(ANNErrorKind::ThreadPoolError, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_invalid_operation_error(err: String) -> Self { - Self::message(ANNErrorKind::InvalidOperation, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_async_error(err: D) -> Self { - Self::message(ANNErrorKind::AsyncError, err.to_string()) - } - - #[track_caller] - #[inline(never)] - pub fn log_async_index_error(err: D) -> Self { - Self::message(ANNErrorKind::AsyncIndexError, err.to_string()) - } - - #[track_caller] - #[inline(never)] - pub fn log_async_shutdown_error(err: D) -> Self { - Self::message(ANNErrorKind::AsyncShutdownError, err.to_string()) - } - - #[track_caller] - #[inline(never)] - pub fn log_async_runtime_error(err: String) -> Self { - Self::message(ANNErrorKind::RustRuntimeError, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_dimension_mismatch_error(err: String) -> Self { - Self::message(ANNErrorKind::DimensionMismatchError, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_paged_search_error(err: String) -> Self { - Self::message(ANNErrorKind::PagedSearchError, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_profiler_error(err: String) -> Self { - Self::message(ANNErrorKind::ProfilerError, err) - } - - #[track_caller] - #[inline(never)] - pub fn log_pq_schema_registration_error(err: T) -> Self - where - T: Display, - { - Self::message(ANNErrorKind::PQSchemaRegistrationError, err.to_string()) - } - - #[track_caller] - #[inline(never)] - pub fn log_invalid_file_format(err: T) -> Self - where - T: Display, - { - Self::message(ANNErrorKind::InvalidFileFormatError, err.to_string()) - } - - #[track_caller] - #[inline(never)] - pub fn log_build_interrupted(err: T) -> Self - where - T: Display, - { - Self::message(ANNErrorKind::BuildInterrupted, err.to_string()) - } } impl Display for ANNError { @@ -524,7 +300,7 @@ impl From for ANNError { impl From for ANNError { #[track_caller] fn from(err: io::Error) -> Self { - ANNError::log_io_error(err) + ANNError::new(ANNErrorKind::IOError, err) } } @@ -535,7 +311,7 @@ where { #[track_caller] fn from(err: mpsc::SendError) -> Self { - ANNError::log_io_send_error(err) + ANNError::new(ANNErrorKind::IOSendError, err) } } @@ -543,7 +319,7 @@ where impl From for ANNError { #[track_caller] fn from(err: LayoutError) -> Self { - ANNError::log_mem_alloc_layout_error(err) + ANNError::new(ANNErrorKind::MemoryAllocLayoutError, err) } } @@ -551,7 +327,7 @@ impl From for ANNError { impl From for ANNError { #[track_caller] fn from(err: TryFromIntError) -> Self { - ANNError::log_try_from_int_error(err) + ANNError::new(ANNErrorKind::TryFromIntError, err) } } @@ -559,7 +335,7 @@ impl From for ANNError { impl From for ANNError { #[track_caller] fn from(err: TryFromSliceError) -> Self { - ANNError::log_try_from_slice_error(err) + ANNError::new(ANNErrorKind::TryFromSliceError, err) } } @@ -1253,206 +1029,6 @@ Caused by: ); } - ///////////////////////// - // Direct Constructors // - ///////////////////////// - - #[test] - fn test_log_disk_io_request_alignment_error() { - let err_msg = "Disk I/O request alignment error"; - let ann_err = ANNError::log_disk_io_request_alignment_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::DiskIOAlignmentError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_mem_alloc_layout_error() { - let layout_err = std::alloc::Layout::from_size_align(0, 0).unwrap_err(); - let formatted = layout_err.to_string(); - let ann_err = ANNError::log_mem_alloc_layout_error(layout_err); - assert_eq!(ANNErrorKind::MemoryAllocLayoutError, ann_err.kind()); - assert!(ann_err.to_string().contains(&formatted)); - } - - #[test] - fn test_log_lock_poison_error() { - let err_msg = "Lock poison error"; - let ann_err = ANNError::log_lock_poison_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::LockPoisonError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_serde_error() { - let op = "serialize"; - let err = "custom error".to_string(); - let ann_err = ANNError::log_serde_error(op.to_string(), &err); - assert_eq!(ANNErrorKind::SerdeError, ann_err.kind()); - - let formatted = ann_err.to_string(); - assert!(formatted.contains(op)); - assert!(formatted.contains(&err)); - } - - #[test] - fn test_log_get_vertex_data_error() { - let id = "vertex_id".to_string(); - let data_t = "data_type".to_string(); - let ann_err = ANNError::log_get_vertex_data_error(id.clone(), data_t.clone()); - assert_eq!(ANNErrorKind::GetVertexDataError, ann_err.kind()); - - let formatted = ann_err.to_string(); - assert!(formatted.contains(&id)); - assert!(formatted.contains(&data_t)); - } - - #[test] - fn test_log_parse_slice_error() { - let parsing_source = "source".to_string(); - let parsing_target = "target".to_string(); - let err = "error".to_string(); - let ann_err = ANNError::log_parse_slice_error( - parsing_source.clone(), - parsing_target.clone(), - err.clone(), - ); - assert_eq!(ANNErrorKind::ParseSliceError, ann_err.kind()); - - let formatted = ann_err.to_string(); - assert!(formatted.contains(&parsing_source)); - assert!(formatted.contains(&parsing_target)); - assert!(formatted.contains(&err)); - } - - #[test] - fn test_log_try_from_slice_error() { - let mut bytes: [u8; 3] = [1, 0, 2]; - let bytes_head = <[u8; 2]>::try_from(&mut bytes[1..2]); - let ann_err = ANNError::log_try_from_slice_error(bytes_head.unwrap_err()); - assert_eq!(ANNErrorKind::TryFromSliceError, ann_err.kind()); - } - - #[test] - fn test_log_try_from_int_error() { - let err = u8::try_from(-1i8); - let ann_err = ANNError::log_try_from_int_error(err.unwrap_err()); - assert_eq!(ANNErrorKind::TryFromIntError, ann_err.kind()); - } - - #[test] - fn test_thread_pool_error() { - let err_msg = "Thread pool error"; - let ann_err = ANNError::log_thread_pool_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::ThreadPoolError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_invalid_operation_error() { - let err_msg = "Invalid operation error"; - let ann_err = ANNError::log_invalid_operation_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::InvalidOperation, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_async_error() { - let err_msg = "Async error"; - let ann_err = ANNError::log_async_error(err_msg); - assert_eq!(ANNErrorKind::AsyncError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_async_index_error() { - let err_msg = "Async index error"; - let ann_err = ANNError::log_async_index_error(err_msg); - assert_eq!(ANNErrorKind::AsyncIndexError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_async_shutdown_error() { - let err_msg = "Async shutdown error"; - let ann_err = ANNError::log_async_shutdown_error(err_msg); - assert_eq!(ANNErrorKind::AsyncShutdownError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_async_runtime_error() { - let err_msg = "Async runtime error"; - let ann_err = ANNError::log_async_runtime_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::RustRuntimeError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_dimension_mismatch_error() { - let err_msg = "Dimension mismatch error"; - let ann_err = ANNError::log_dimension_mismatch_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::DimensionMismatchError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_profiler_error() { - let err_msg = "Profiler error"; - let ann_err = ANNError::log_profiler_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::ProfilerError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_pq_schema_registration_error() { - let err_msg = "PQ schema registration error"; - let ann_err = ANNError::log_pq_schema_registration_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::PQSchemaRegistrationError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_kmeans_error() { - let err_msg = "KMeans error"; - let ann_err = ANNError::log_kmeans_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::KMeansError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_io_send_error() { - let err_msg = "IO send error"; - let send_err: mpsc::SendError = mpsc::SendError(err_msg.to_string()); - let expected = send_err.to_string(); - let ann_err = ANNError::log_io_send_error(send_err); - assert_eq!(ANNErrorKind::IOSendError, ann_err.kind()); - assert!(ann_err.to_string().contains(&expected)); - } - - #[test] - fn test_log_file_handle_error() { - let err_msg = "File handle error"; - let ann_err = ANNError::log_file_handle_error(err_msg); - assert_eq!(ANNErrorKind::FileHandleError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_file_not_found_error() { - let err_msg = "File not found error"; - let ann_err = ANNError::log_file_not_found_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::FileNotFoundError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - - #[test] - fn test_log_ground_truth_error() { - let err_msg = "Ground truth error"; - let ann_err = ANNError::log_ground_truth_error(err_msg.to_string()); - assert_eq!(ANNErrorKind::GroundTruthError, ann_err.kind()); - assert!(ann_err.to_string().contains(err_msg)); - } - #[test] fn test_io_error_to_ann_error() { let io_err = io::Error::other("test error"); @@ -1503,14 +1079,14 @@ Caused by: #[test] fn test_invaild_file_format_error() { let err_msg = String::from("Invalid file format error"); - let ann_err = ANNError::log_invalid_file_format(err_msg.clone()); + let ann_err = ANNError::from_display(ANNErrorKind::InvalidFileFormatError, err_msg.clone()); assert_eq!(ann_err.kind(), ANNErrorKind::InvalidFileFormatError); } #[test] fn test_build_interrupted() { let message = "BuildIndicesOnShards"; - let ann_err = ANNError::log_build_interrupted(message); + let ann_err = ANNError::from_display(ANNErrorKind::BuildInterrupted, message); assert_eq!(ann_err.kind(), ANNErrorKind::BuildInterrupted); } diff --git a/diskann/src/error/ranked.rs b/diskann/src/error/ranked.rs index b10253e18..9de99db78 100644 --- a/diskann/src/error/ranked.rs +++ b/diskann/src/error/ranked.rs @@ -447,6 +447,8 @@ mod tests { use thiserror::Error; + use crate::ANNErrorKind; + use super::*; // Check that the layout of Ranked "Always Escalate" types `T` is the same as the layout @@ -457,7 +459,7 @@ mod tests { impl From for ANNError { fn from(value: AlwaysEscalate) -> ANNError { - ANNError::log_index_error(value) + ANNError::new(ANNErrorKind::IndexError, value) } } @@ -560,7 +562,7 @@ mod tests { impl From> for ANNError { #[track_caller] fn from(value: Disarmed<'_>) -> ANNError { - ANNError::log_index_error(&value) + ANNError::from_display(ANNErrorKind::IndexError, value.to_string()) } } @@ -842,7 +844,7 @@ mod tests { // We can't actually construct an Infallible value to test this directly since it's unconstructable // But we can verify the From implementation exists by checking the type constraint fn _test_infallible_into_ann_error(_: Infallible) -> ANNError { - ANNError::log_index_error("This should never be called") + ANNError::from_display(ANNErrorKind::IndexError, "This should never be called") } } } diff --git a/diskann/src/graph/index.rs b/diskann/src/graph/index.rs index 37d5bc946..a69e44ccf 100644 --- a/diskann/src/graph/index.rs +++ b/diskann/src/graph/index.rs @@ -1401,7 +1401,7 @@ where #[error("Spawning a task failed in inplace-delete: {0}")] struct LocalError(tokio::task::JoinError); - ANNError::log_async_error(LocalError(err)) + ANNError::from_display(crate::ANNErrorKind::AsyncError, LocalError(err)) }); edge_collection.push(res); } @@ -1458,7 +1458,10 @@ where loop { let result = { let mut guard = edges_clone.lock().map_err(|_| { - ANNError::log_async_error("Poisoned mutex during construction") + ANNError::from_display( + crate::ANNErrorKind::AsyncError, + "Poisoned mutex during construction", + ) })?; guard.next() }; diff --git a/diskann/src/graph/search/paged.rs b/diskann/src/graph/search/paged.rs index 791cd7acb..1ddd672e3 100644 --- a/diskann/src/graph/search/paged.rs +++ b/diskann/src/graph/search/paged.rs @@ -56,12 +56,14 @@ where ) -> impl SendFuture>>> { async move { if k > self.search_param_l { - return ANNResult::Err(ANNError::log_paged_search_error( + return ANNResult::Err(ANNError::from_display( + crate::ANNErrorKind::PagedSearchError, "k should be less than or equal to search_param_l".to_string(), )); } if k == 0 { - return ANNResult::Err(ANNError::log_paged_search_error( + return ANNResult::Err(ANNError::from_display( + crate::ANNErrorKind::PagedSearchError, "k should be greater than 0".to_string(), )); } diff --git a/diskann/src/utils/async_tools.rs b/diskann/src/utils/async_tools.rs index 87f72b7e0..c419468c7 100644 --- a/diskann/src/utils/async_tools.rs +++ b/diskann/src/utils/async_tools.rs @@ -14,7 +14,7 @@ use std::{ use thiserror::Error; -use crate::ANNError; +use crate::{ANNError, ANNErrorKind}; //////////// // Around // @@ -372,7 +372,7 @@ pub struct PartitionError { impl From for ANNError { fn from(err: PartitionError) -> Self { - Self::log_async_error(err) + Self::new(ANNErrorKind::AsyncError, err) } } diff --git a/diskann/src/utils/vector_repr.rs b/diskann/src/utils/vector_repr.rs index 4f33caab3..d03c1a626 100644 --- a/diskann/src/utils/vector_repr.rs +++ b/diskann/src/utils/vector_repr.rs @@ -13,7 +13,7 @@ use diskann_vector::{ use half::f16; use thiserror::Error; -use crate::{ANNError, internal::convert_f32::ConvertF32}; +use crate::{ANNError, ANNErrorKind, internal::convert_f32::ConvertF32}; /// This is the data type for values stored in the graph. This type should implement the /// following traits: @@ -112,10 +112,7 @@ pub struct NativeTypeLengthError { impl From for ANNError { fn from(err: NativeTypeLengthError) -> ANNError { - ANNError::log_index_error(format!( - "Unable to set full-precision vector of length {} into slice of length {}", - err.src, err.dst - )) + ANNError::new(ANNErrorKind::IndexError, err) } }