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}