Skip to main content

orderbook_rs/orderbook/sequencer/
error.rs

1//! Error types for the journal subsystem.
2//!
3//! [`JournalError`] covers all failure modes of the append-only event
4//! journal, including I/O errors, corruption, and capacity issues.
5
6use std::fmt;
7use std::path::PathBuf;
8
9/// Errors that can occur within the journal subsystem.
10#[derive(Debug)]
11#[non_exhaustive]
12pub enum JournalError {
13    /// An I/O error occurred while reading or writing journal files.
14    Io {
15        /// The underlying I/O error message.
16        message: String,
17        /// The file path involved, if known.
18        path: Option<PathBuf>,
19    },
20
21    /// A journal entry failed CRC32 integrity verification.
22    CorruptEntry {
23        /// The sequence number of the corrupt entry.
24        sequence: u64,
25        /// The expected CRC32 checksum.
26        expected_crc: u32,
27        /// The actual CRC32 checksum computed from the entry bytes.
28        actual_crc: u32,
29    },
30
31    /// The journal entry payload could not be deserialized.
32    DeserializationError {
33        /// The sequence number of the entry that failed to deserialize.
34        sequence: u64,
35        /// The underlying deserialization error message.
36        message: String,
37    },
38
39    /// The journal entry payload could not be serialized.
40    SerializationError {
41        /// The underlying serialization error message.
42        message: String,
43    },
44
45    /// A segment file is too small to hold the entry being appended.
46    EntryTooLarge {
47        /// The size of the serialized entry in bytes.
48        entry_bytes: usize,
49        /// The maximum segment size in bytes.
50        segment_size: usize,
51    },
52
53    /// The journal directory does not exist or is not accessible.
54    InvalidDirectory {
55        /// The path that was expected to be a valid directory.
56        path: PathBuf,
57    },
58
59    /// An internal mutex was poisoned (another thread panicked while
60    /// holding the lock).
61    MutexPoisoned,
62
63    /// The requested sequence number was not found in the journal.
64    SequenceNotFound {
65        /// The sequence number that was requested.
66        sequence: u64,
67    },
68
69    /// The journal entry has an invalid header (truncated or malformed).
70    InvalidEntryHeader {
71        /// Byte offset within the segment where the error occurred.
72        offset: usize,
73        /// Description of the header problem.
74        message: String,
75    },
76}
77
78impl fmt::Display for JournalError {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match self {
81            JournalError::Io { message, path } => {
82                if let Some(p) = path {
83                    write!(f, "journal I/O error at {}: {message}", p.display())
84                } else {
85                    write!(f, "journal I/O error: {message}")
86                }
87            }
88            JournalError::CorruptEntry {
89                sequence,
90                expected_crc,
91                actual_crc,
92            } => {
93                write!(
94                    f,
95                    "corrupt journal entry at sequence {sequence}: \
96                     expected CRC {expected_crc:#010x}, got {actual_crc:#010x}"
97                )
98            }
99            JournalError::DeserializationError { sequence, message } => {
100                write!(
101                    f,
102                    "journal deserialization error at sequence {sequence}: {message}"
103                )
104            }
105            JournalError::SerializationError { message } => {
106                write!(f, "journal serialization error: {message}")
107            }
108            JournalError::EntryTooLarge {
109                entry_bytes,
110                segment_size,
111            } => {
112                write!(
113                    f,
114                    "journal entry too large: {entry_bytes} bytes exceeds \
115                     segment size {segment_size} bytes"
116                )
117            }
118            JournalError::InvalidDirectory { path } => {
119                write!(f, "invalid journal directory: {}", path.display())
120            }
121            JournalError::MutexPoisoned => {
122                write!(f, "journal internal mutex poisoned")
123            }
124            JournalError::SequenceNotFound { sequence } => {
125                write!(f, "sequence {sequence} not found in journal")
126            }
127            JournalError::InvalidEntryHeader { offset, message } => {
128                write!(
129                    f,
130                    "invalid journal entry header at offset {offset}: {message}"
131                )
132            }
133        }
134    }
135}
136
137impl std::error::Error for JournalError {}
138
139impl From<std::io::Error> for JournalError {
140    #[cold]
141    fn from(err: std::io::Error) -> Self {
142        JournalError::Io {
143            message: err.to_string(),
144            path: None,
145        }
146    }
147}