Skip to main content

crabka_log/
error.rs

1//! Errors returned by `Log` and `Segment`.
2
3use thiserror::Error;
4
5/// Errors returned by [`Log`](crate::Log) and [`Segment`](crate::Segment).
6#[derive(Debug, Error)]
7pub enum LogError {
8    /// An I/O operation against the filesystem failed.
9    #[error("I/O: {0}")]
10    Io(#[from] std::io::Error),
11
12    /// A partial batch was found at the tail of a `.log` file during
13    /// recovery — the trailing bytes will be truncated to the last
14    /// cleanly decoded batch.
15    #[error("partial batch at offset {file_offset} in segment {segment}: truncating")]
16    PartialBatch {
17        /// Absolute base offset of the segment containing the partial batch.
18        segment: i64,
19        /// Byte position within the `.log` file where the partial batch starts.
20        file_offset: u64,
21    },
22
23    /// A batch's stored CRC did not match the one computed over its bytes.
24    #[error(
25        "CRC mismatch at offset {file_offset} in segment {segment}: \
26         expected {expected:#x}, computed {computed:#x}"
27    )]
28    CrcMismatch {
29        /// Absolute base offset of the segment.
30        segment: i64,
31        /// Byte position within the `.log` file where the corrupt batch starts.
32        file_offset: u64,
33        /// CRC value embedded in the batch header.
34        expected: u32,
35        /// CRC value re-computed by the reader.
36        computed: u32,
37    },
38
39    /// A caller requested an offset below [`Log::log_start_offset`](crate::Log::log_start_offset).
40    #[error("offset {requested} below log start {log_start}")]
41    OffsetTooLow {
42        /// Offset the caller asked for.
43        requested: i64,
44        /// Current log start.
45        log_start: i64,
46    },
47
48    /// Encoding/decoding of a `RecordBatch` failed.
49    #[error("records: {0}")]
50    Records(#[from] crabka_protocol::records::RecordsError),
51
52    /// A segment filename couldn't be parsed (e.g., wrong length, not all digits).
53    #[error("invalid segment filename: {0}")]
54    BadSegmentName(String),
55
56    /// A caller supplied an explicit offset to [`Log::append_at`](crate::Log::append_at)
57    /// that did not match the log's current end offset. Replication paths use
58    /// this to detect divergence between leader-assigned offsets and the local
59    /// log's expected next offset.
60    #[error("offset mismatch: expected {expected}, got {actual}")]
61    OffsetMismatch {
62        /// The offset the log expected — i.e. its current end offset.
63        expected: i64,
64        /// The offset the caller actually supplied.
65        actual: i64,
66    },
67
68    /// A log file (e.g., `.txnindex`) is corrupt: wrong size, bad checksum, etc.
69    #[error("corrupt log: {0}")]
70    Corrupt(String),
71
72    /// A caller supplied an invalid argument.
73    #[error("invalid argument: {0}")]
74    InvalidArgument(String),
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use assert2::assert;
81
82    #[test]
83    fn display_partial_batch() {
84        let e = LogError::PartialBatch {
85            segment: 0,
86            file_offset: 1024,
87        };
88        assert!(e.to_string().contains("offset 1024"));
89        assert!(e.to_string().contains("segment 0"));
90    }
91}