sled/
result.rs

1use std::{
2    cmp::PartialEq,
3    error::Error as StdError,
4    fmt::{self, Display},
5    io,
6};
7
8#[cfg(feature = "testing")]
9use backtrace::Backtrace;
10
11use crate::{
12    pagecache::{DiskPtr, PageView},
13    IVec,
14};
15
16/// The top-level result type for dealing with
17/// fallible operations. The errors tend to
18/// be fail-stop, and nested results are used
19/// in cases where the outer fail-stop error can
20/// have try `?` used on it, exposing the inner
21/// operation that is expected to fail under
22/// normal operation. The philosophy behind this
23/// is detailed [on the sled blog](https://sled.rs/errors).
24pub type Result<T> = std::result::Result<T, Error>;
25
26/// A compare and swap result.  If the CAS is successful,
27/// the new `PagePtr` will be returned as `Ok`.  Otherwise,
28/// the `Err` will contain a tuple of the current `PagePtr`
29/// and the old value that could not be set atomically.
30pub(crate) type CasResult<'a, R> =
31    std::result::Result<PageView<'a>, Option<(PageView<'a>, R)>>;
32
33/// An Error type encapsulating various issues that may come up
34/// in the operation of a `Db`.
35#[derive(Debug)]
36pub enum Error {
37    /// The underlying collection no longer exists.
38    CollectionNotFound(IVec),
39    /// The system has been used in an unsupported way.
40    Unsupported(String),
41    /// An unexpected bug has happened. Please open an issue on github!
42    ReportableBug(String),
43    /// A read or write error has happened when interacting with the file
44    /// system.
45    Io(io::Error),
46    /// Corruption has been detected in the storage file.
47    Corruption {
48        /// The file location that corrupted data was found at.
49        at: Option<DiskPtr>,
50        /// A backtrace for where the corruption was encountered.
51        #[cfg(feature = "testing")]
52        bt: Backtrace,
53        /// A backtrace for where the corruption was encountered.
54        #[cfg(not(feature = "testing"))]
55        bt: (),
56    },
57    // a failpoint has been triggered for testing purposes
58    #[doc(hidden)]
59    #[cfg(feature = "failpoints")]
60    FailPoint,
61}
62
63impl Error {
64    pub(crate) fn corruption(at: Option<DiskPtr>) -> Error {
65        Error::Corruption {
66            at,
67            #[cfg(feature = "testing")]
68            bt: Backtrace::new(),
69            #[cfg(not(feature = "testing"))]
70            bt: (),
71        }
72    }
73}
74
75impl Clone for Error {
76    fn clone(&self) -> Self {
77        use self::Error::*;
78
79        match self {
80            Io(ioe) => Io(io::Error::new(ioe.kind(), format!("{:?}", ioe))),
81            CollectionNotFound(name) => CollectionNotFound(name.clone()),
82            Unsupported(why) => Unsupported(why.clone()),
83            ReportableBug(what) => ReportableBug(what.clone()),
84            Corruption { at, bt } => Corruption { at: *at, bt: bt.clone() },
85            #[cfg(feature = "failpoints")]
86            FailPoint => FailPoint,
87        }
88    }
89}
90
91impl Eq for Error {}
92
93impl PartialEq for Error {
94    fn eq(&self, other: &Self) -> bool {
95        use self::Error::*;
96
97        match *self {
98            CollectionNotFound(ref l) => {
99                if let CollectionNotFound(ref r) = *other {
100                    l == r
101                } else {
102                    false
103                }
104            }
105            Unsupported(ref l) => {
106                if let Unsupported(ref r) = *other {
107                    l == r
108                } else {
109                    false
110                }
111            }
112            ReportableBug(ref l) => {
113                if let ReportableBug(ref r) = *other {
114                    l == r
115                } else {
116                    false
117                }
118            }
119            #[cfg(feature = "failpoints")]
120            FailPoint => {
121                if let FailPoint = *other {
122                    true
123                } else {
124                    false
125                }
126            }
127            Corruption { at: l, .. } => {
128                if let Corruption { at: r, .. } = *other {
129                    l == r
130                } else {
131                    false
132                }
133            }
134            Io(_) => false,
135        }
136    }
137}
138
139impl From<io::Error> for Error {
140    #[inline]
141    fn from(io_error: io::Error) -> Self {
142        Error::Io(io_error)
143    }
144}
145
146impl From<Error> for io::Error {
147    fn from(error: Error) -> io::Error {
148        use self::Error::*;
149        use std::io::ErrorKind;
150        match error {
151            Io(ioe) => ioe,
152            CollectionNotFound(name) =>
153                io::Error::new(
154                ErrorKind::NotFound,
155                format!("collection not found: {:?}", name),
156            ),
157            Unsupported(why) => io::Error::new(
158                ErrorKind::InvalidInput,
159                format!("operation not supported: {:?}", why),
160            ),
161            ReportableBug(what) => io::Error::new(
162                ErrorKind::Other,
163                format!("unexpected bug! please report this bug at <github.rs/spacejam/sled>: {:?}", what),
164            ),
165            Corruption { .. } => io::Error::new(
166                ErrorKind::InvalidData,
167                format!("corruption encountered: {:?}", error),
168            ),
169            #[cfg(feature = "failpoints")]
170            FailPoint => io::Error::new(
171                ErrorKind::Other,
172                "failpoint"
173            ),
174        }
175    }
176}
177
178impl StdError for Error {}
179
180impl Display for Error {
181    fn fmt(
182        &self,
183        f: &mut fmt::Formatter<'_>,
184    ) -> std::result::Result<(), fmt::Error> {
185        use self::Error::*;
186
187        match *self {
188            CollectionNotFound(ref name) => {
189                write!(f, "Collection {:?} does not exist", name,)
190            }
191            Unsupported(ref e) => write!(f, "Unsupported: {}", e),
192            ReportableBug(ref e) => write!(
193                f,
194                "Unexpected bug has happened: {}. \
195                 PLEASE REPORT THIS BUG!",
196                e
197            ),
198            #[cfg(feature = "failpoints")]
199            FailPoint => write!(f, "Fail point has been triggered."),
200            Io(ref e) => write!(f, "IO error: {}", e),
201            Corruption { at, ref bt } => write!(
202                f,
203                "Read corrupted data at file offset {:?} backtrace {:?}",
204                at, bt
205            ),
206        }
207    }
208}