Skip to main content

log/
error.rs

1//! Error types for OpenData Log operations.
2//!
3//! This module defines [`Error`], the primary error type for all log
4//! operations, along with a convenient [`Result`] type alias.
5
6use common::{SequenceError, StorageError};
7
8/// Error type for OpenData Log operations.
9///
10/// This enum captures all possible error conditions that can occur when
11/// interacting with the log, including storage failures, encoding issues,
12/// and invalid input.
13///
14/// # Error Categories
15///
16/// - [`Storage`](Error::Storage): Errors from the underlying SlateDB storage layer,
17///   such as I/O failures or corruption.
18/// - [`Encoding`](Error::Encoding): Errors during serialization or deserialization
19///   of log entries.
20/// - [`InvalidInput`](Error::InvalidInput): Errors caused by invalid parameters or
21///   arguments provided by the caller.
22/// - [`Internal`](Error::Internal): Unexpected internal errors that indicate bugs
23///   or invariant violations.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum Error {
26    /// Storage-related errors from the underlying SlateDB layer.
27    ///
28    /// These errors typically indicate I/O failures, corruption, or
29    /// issues with the object store backend.
30    Storage(String),
31
32    /// Encoding or decoding errors.
33    ///
34    /// These errors occur when serializing records for storage or
35    /// deserializing entries during reads.
36    Encoding(String),
37
38    /// Invalid input or parameter errors.
39    ///
40    /// These errors indicate that the caller provided invalid arguments,
41    /// such as empty keys or malformed sequence ranges.
42    InvalidInput(String),
43
44    /// Internal errors indicating bugs or invariant violations.
45    ///
46    /// These errors should not occur during normal operation and
47    /// typically indicate a bug in the implementation.
48    Internal(String),
49}
50
51impl std::error::Error for Error {}
52
53impl std::fmt::Display for Error {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        match self {
56            Error::Storage(msg) => write!(f, "Storage error: {}", msg),
57            Error::Encoding(msg) => write!(f, "Encoding error: {}", msg),
58            Error::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
59            Error::Internal(msg) => write!(f, "Internal error: {}", msg),
60        }
61    }
62}
63
64impl From<StorageError> for Error {
65    fn from(err: StorageError) -> Self {
66        match err {
67            StorageError::Storage(msg) => Error::Storage(msg),
68            StorageError::Internal(msg) => Error::Internal(msg),
69        }
70    }
71}
72
73impl From<SequenceError> for Error {
74    fn from(err: SequenceError) -> Self {
75        match err {
76            SequenceError::Storage(storage_err) => Error::from(storage_err),
77            SequenceError::Deserialize(de_err) => Error::Encoding(de_err.message),
78        }
79    }
80}
81
82impl From<&str> for Error {
83    fn from(msg: &str) -> Self {
84        Error::InvalidInput(msg.to_string())
85    }
86}
87
88/// Result type alias for OpenData Log operations.
89///
90/// This is a convenience alias for `std::result::Result<T, Error>`.
91pub type Result<T> = std::result::Result<T, Error>;
92
93use crate::model::Record;
94
95/// Error type for append operations that preserves the batch for retry.
96///
97/// Unlike [`Error`], this type carries the original `Vec<Record>` inside
98/// retryable variants (`QueueFull`, `Timeout`) so callers can retry without
99/// cloning the batch up front.
100#[derive(Debug)]
101pub enum AppendError {
102    /// The write queue is full (non-blocking send failed). Contains the batch.
103    QueueFull(Vec<Record>),
104    /// Timed out waiting for queue space. Contains the batch.
105    Timeout(Vec<Record>),
106    /// The writer has shut down.
107    Shutdown,
108    /// A storage-level error occurred while processing the write.
109    Storage(String),
110}
111
112impl AppendError {
113    /// Returns the batch of records if this is a retryable error, or `None`
114    /// for terminal errors.
115    pub fn into_inner(self) -> Option<Vec<Record>> {
116        match self {
117            AppendError::QueueFull(records) => Some(records),
118            AppendError::Timeout(records) => Some(records),
119            AppendError::Shutdown => None,
120            AppendError::Storage(_) => None,
121        }
122    }
123}
124
125impl std::fmt::Display for AppendError {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        match self {
128            AppendError::QueueFull(_) => write!(f, "write queue full"),
129            AppendError::Timeout(_) => write!(f, "write queue timeout"),
130            AppendError::Shutdown => write!(f, "writer shut down"),
131            AppendError::Storage(msg) => write!(f, "storage error: {}", msg),
132        }
133    }
134}
135
136impl std::error::Error for AppendError {}
137
138impl From<AppendError> for Error {
139    fn from(err: AppendError) -> Self {
140        match err {
141            AppendError::QueueFull(_) => Error::Internal("write queue full".into()),
142            AppendError::Timeout(_) => Error::Internal("write queue timeout".into()),
143            AppendError::Shutdown => Error::Internal("writer shut down".into()),
144            AppendError::Storage(msg) => Error::Internal(msg),
145        }
146    }
147}
148
149/// Result type alias for append operations.
150///
151/// This is a convenience alias for `std::result::Result<T, AppendError>`.
152pub type AppendResult<T> = std::result::Result<T, AppendError>;