Spaces:
Build error
Build error
use std::backtrace::Backtrace; | |
use std::collections::TryReserveError; | |
use std::io::{Error as IoError, ErrorKind}; | |
use std::sync::atomic::{AtomicBool, Ordering}; | |
use atomicwrites::Error as AtomicIoError; | |
use io::file_operations::FileStorageError; | |
use memory::mmap_type::Error as MmapError; | |
use rayon::ThreadPoolBuildError; | |
use thiserror::Error; | |
use crate::types::{PayloadKeyType, PointIdType, SeqNumberType}; | |
use crate::utils::mem::Mem; | |
pub const PROCESS_CANCELLED_BY_SERVICE_MESSAGE: &str = "process cancelled by service"; | |
pub enum OperationError { | |
WrongVectorDimension { | |
expected_dim: usize, | |
received_dim: usize, | |
}, | |
VectorNameNotExists { received_name: String }, | |
MissedVectorName { received_name: String }, | |
PointIdError { missed_point_id: PointIdType }, | |
TypeError { | |
field_name: PayloadKeyType, | |
expected_type: String, | |
}, | |
TypeInferenceError { field_name: PayloadKeyType }, | |
/// Service Error prevents further update of the collection until it is fixed. | |
/// Should only be used for hardware, data corruption, IO, or other unexpected internal errors. | |
ServiceError { | |
description: String, | |
backtrace: Option<String>, | |
}, | |
InconsistentStorage { description: String }, | |
OutOfMemory { description: String, free: u64 }, | |
Cancelled { description: String }, | |
ValidationError { description: String }, | |
WrongSparse, | |
WrongMulti, | |
MissingRangeIndexForOrderBy { key: String }, | |
MissingMapIndexForFacet { key: String }, | |
} | |
impl OperationError { | |
/// Create a new service error with a description and a backtrace | |
/// Warning: capturing a backtrace can be an expensive operation on some platforms, so this should be used with caution in performance-sensitive parts of code. | |
pub fn service_error(description: impl Into<String>) -> OperationError { | |
OperationError::ServiceError { | |
description: description.into(), | |
backtrace: Some(Backtrace::force_capture().to_string()), | |
} | |
} | |
/// Create a new service error with a description and no backtrace | |
pub fn service_error_light(description: impl Into<String>) -> OperationError { | |
OperationError::ServiceError { | |
description: description.into(), | |
backtrace: None, | |
} | |
} | |
} | |
pub fn check_process_stopped(stopped: &AtomicBool) -> OperationResult<()> { | |
if stopped.load(Ordering::Relaxed) { | |
return Err(OperationError::Cancelled { | |
description: PROCESS_CANCELLED_BY_SERVICE_MESSAGE.to_string(), | |
}); | |
} | |
Ok(()) | |
} | |
/// Contains information regarding last operation error, which should be fixed before next operation could be processed | |
pub struct SegmentFailedState { | |
pub version: SeqNumberType, | |
pub point_id: Option<PointIdType>, | |
pub error: OperationError, | |
} | |
impl From<ThreadPoolBuildError> for OperationError { | |
fn from(error: ThreadPoolBuildError) -> Self { | |
OperationError::ServiceError { | |
description: format!("{error}"), | |
backtrace: Some(Backtrace::force_capture().to_string()), | |
} | |
} | |
} | |
impl From<FileStorageError> for OperationError { | |
fn from(err: FileStorageError) -> Self { | |
Self::service_error(err.to_string()) | |
} | |
} | |
impl From<MmapError> for OperationError { | |
fn from(err: MmapError) -> Self { | |
Self::service_error(err.to_string()) | |
} | |
} | |
impl From<serde_cbor::Error> for OperationError { | |
fn from(err: serde_cbor::Error) -> Self { | |
OperationError::service_error(format!("Failed to parse data: {err}")) | |
} | |
} | |
impl<E> From<AtomicIoError<E>> for OperationError { | |
fn from(err: AtomicIoError<E>) -> Self { | |
match err { | |
AtomicIoError::Internal(io_err) => OperationError::from(io_err), | |
AtomicIoError::User(_user_err) => { | |
OperationError::service_error("Unknown atomic write error") | |
} | |
} | |
} | |
} | |
impl From<IoError> for OperationError { | |
fn from(err: IoError) -> Self { | |
match err.kind() { | |
ErrorKind::OutOfMemory => { | |
let free_memory = Mem::new().available_memory_bytes(); | |
OperationError::OutOfMemory { | |
description: format!("IO Error: {err}"), | |
free: free_memory, | |
} | |
} | |
_ => OperationError::service_error(format!("IO Error: {err}")), | |
} | |
} | |
} | |
impl From<serde_json::Error> for OperationError { | |
fn from(err: serde_json::Error) -> Self { | |
OperationError::service_error(format!("Json error: {err}")) | |
} | |
} | |
impl From<fs_extra::error::Error> for OperationError { | |
fn from(err: fs_extra::error::Error) -> Self { | |
OperationError::service_error(format!("File system error: {err}")) | |
} | |
} | |
impl From<geohash::GeohashError> for OperationError { | |
fn from(err: geohash::GeohashError) -> Self { | |
OperationError::service_error(format!("Geohash error: {err}")) | |
} | |
} | |
impl From<quantization::EncodingError> for OperationError { | |
fn from(err: quantization::EncodingError) -> Self { | |
match err { | |
quantization::EncodingError::IOError(err) | |
| quantization::EncodingError::EncodingError(err) | |
| quantization::EncodingError::ArgumentsError(err) => { | |
OperationError::service_error(format!("Quantization encoding error: {err}")) | |
} | |
quantization::EncodingError::Stopped => OperationError::Cancelled { | |
description: PROCESS_CANCELLED_BY_SERVICE_MESSAGE.to_string(), | |
}, | |
} | |
} | |
} | |
impl From<TryReserveError> for OperationError { | |
fn from(err: TryReserveError) -> Self { | |
let free_memory = Mem::new().available_memory_bytes(); | |
OperationError::OutOfMemory { | |
description: format!("Failed to reserve memory: {err}"), | |
free: free_memory, | |
} | |
} | |
} | |
pub type OperationResult<T> = Result<T, OperationError>; | |
pub fn get_service_error<T>(err: &OperationResult<T>) -> Option<OperationError> { | |
match err { | |
Ok(_) => None, | |
Err(error) => match error { | |
OperationError::ServiceError { .. } => Some(error.clone()), | |
_ => None, | |
}, | |
} | |
} | |