spacetimedb_commitlog/
error.rs

1use std::io;
2
3use spacetimedb_sats::buffer::DecodeError;
4use thiserror::Error;
5
6use crate::segment;
7
8/// Error yielded by public commitlog iterators.
9#[derive(Debug, Error)]
10pub enum Traversal {
11    #[error("out-of-order commit: expected-offset={expected_offset} actual-offset={actual_offset}")]
12    OutOfOrder {
13        expected_offset: u64,
14        actual_offset: u64,
15        /// If the next segment starts with a commit with matching offset, a
16        /// previous bad commit will be ignored. If, however, the offset does
17        /// **not** match, `prev_error` contains the error encountered when
18        /// trying to read the previous commit (which was skipped).
19        #[source]
20        prev_error: Option<Box<Self>>,
21    },
22    /// The log is considered forked iff a commit with the same `min_tx_offset`
23    /// but a different crc32 than the previous commit is encountered.
24    ///
25    /// This may happen in rare circumstances where a write was considered
26    /// failed (e.g. due to a failed `fsync(2)`), when it was actually successful.
27    #[error("forked history: offset={offset}")]
28    Forked { offset: u64 },
29    #[error("failed to decode tx record at offset={offset}")]
30    Decode {
31        offset: u64,
32        #[source]
33        source: DecodeError,
34    },
35    #[error("checksum mismatch at offset={offset}")]
36    Checksum {
37        offset: u64,
38        #[source]
39        source: ChecksumMismatch,
40    },
41    #[error(transparent)]
42    Io(#[from] io::Error),
43}
44
45/// Error returned by [`crate::Commitlog::append`].
46#[derive(Debug, Error)]
47#[error("failed to commit during append")]
48pub struct Append<T> {
49    /// The payload which was passed to [`crate::Commitlog::append`], but was
50    /// not retained because flushing the data to the underlying storage failed.
51    pub txdata: T,
52    /// Why flushing to persistent storage failed.
53    #[source]
54    pub source: io::Error,
55}
56
57/// A checksum mismatch was detected.
58///
59/// Usually wrapped in another error, such as [`io::Error`].
60#[derive(Debug, Error)]
61#[error("checksum mismatch")]
62pub struct ChecksumMismatch;
63
64#[derive(Debug, Error)]
65pub enum SegmentMetadata {
66    #[error("invalid commit encountered")]
67    InvalidCommit {
68        sofar: segment::Metadata,
69        #[source]
70        source: io::Error,
71    },
72    #[error(transparent)]
73    Io(#[from] io::Error),
74}
75
76/// Recursively concatenate `e.source()`, separated by ": ".
77pub(crate) fn source_chain(e: &impl std::error::Error) -> String {
78    let mut s = String::new();
79    let mut source = e.source();
80    while let Some(cause) = source {
81        s.push(':');
82        s.push(' ');
83        s.push_str(&cause.to_string());
84        source = cause.source()
85    }
86
87    s
88}