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