Skip to main content

actionqueue_storage/wal/
reader.rs

1//! WAL reader interface.
2
3use crate::wal::event::WalEvent;
4use crate::wal::tail_validation::WalCorruption;
5
6/// A reader that can read events from the WAL.
7pub trait WalReader {
8    /// Read the next event from the WAL.
9    fn read_next(&mut self) -> Result<Option<WalEvent>, WalReaderError>;
10
11    /// Seek to a specific sequence number.
12    fn seek_to_sequence(&mut self, sequence: u64) -> Result<(), WalReaderError>;
13
14    /// Returns true if the reader is at the end of the WAL.
15    fn is_end(&self) -> bool;
16}
17
18/// Errors that can occur during WAL reading.
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum WalReaderError {
21    /// The reader reached the end of the WAL.
22    EndOfWal,
23    /// I/O error during read.
24    IoError(String),
25    /// Strict WAL corruption details with deterministic record-boundary offset.
26    Corruption(WalCorruption),
27    /// The event could not be decoded outside strict framed-record corruption paths.
28    DecodeError(String),
29    /// An error occurred during replay reduction.
30    ReducerError(String),
31}
32
33impl std::fmt::Display for WalReaderError {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            WalReaderError::EndOfWal => write!(f, "End of WAL reached"),
37            WalReaderError::IoError(e) => write!(f, "I/O error: {e}"),
38            WalReaderError::Corruption(details) => write!(f, "{details}"),
39            WalReaderError::DecodeError(e) => write!(f, "Decode error: {e}"),
40            WalReaderError::ReducerError(e) => write!(f, "Reducer error: {e}"),
41        }
42    }
43}
44
45impl std::error::Error for WalReaderError {}
46
47impl std::convert::From<crate::recovery::reducer::ReplayReducerError> for WalReaderError {
48    fn from(err: crate::recovery::reducer::ReplayReducerError) -> Self {
49        match err {
50            crate::recovery::reducer::ReplayReducerError::InvalidTransition => {
51                WalReaderError::ReducerError("Invalid state transition during replay".to_string())
52            }
53            crate::recovery::reducer::ReplayReducerError::DuplicateEvent => {
54                WalReaderError::ReducerError("Duplicate event detected".to_string())
55            }
56            crate::recovery::reducer::ReplayReducerError::CorruptedData => {
57                WalReaderError::ReducerError("Corrupted event data".to_string())
58            }
59            crate::recovery::reducer::ReplayReducerError::LeaseCausality(details) => {
60                WalReaderError::ReducerError(format!(
61                    "Lease causality violation during replay: {details}"
62                ))
63            }
64            crate::recovery::reducer::ReplayReducerError::TaskCausality(details) => {
65                WalReaderError::ReducerError(format!(
66                    "Task causality violation during replay: {details}"
67                ))
68            }
69            crate::recovery::reducer::ReplayReducerError::EngineControlCausality(details) => {
70                WalReaderError::ReducerError(format!(
71                    "Engine control causality violation during replay: {details}"
72                ))
73            }
74        }
75    }
76}