redb_32bit/
error.rs

1use crate::tree_store::{FILE_FORMAT_VERSION, MAX_VALUE_LENGTH};
2use crate::TypeName;
3use std::fmt::{Display, Formatter};
4use std::sync::PoisonError;
5use std::{io, panic};
6
7/// General errors directly from the storage layer
8#[derive(Debug)]
9#[non_exhaustive]
10pub enum StorageError {
11    /// The Database is corrupted
12    Corrupted(String),
13    /// The value being inserted exceeds the maximum of 3GiB
14    ValueTooLarge(usize),
15    Io(io::Error),
16    LockPoisoned(&'static panic::Location<'static>),
17}
18
19impl<T> From<PoisonError<T>> for StorageError {
20    fn from(_: PoisonError<T>) -> StorageError {
21        StorageError::LockPoisoned(panic::Location::caller())
22    }
23}
24
25impl From<io::Error> for StorageError {
26    fn from(err: io::Error) -> StorageError {
27        StorageError::Io(err)
28    }
29}
30
31impl From<StorageError> for Error {
32    fn from(err: StorageError) -> Error {
33        match err {
34            StorageError::Corrupted(msg) => Error::Corrupted(msg),
35            StorageError::ValueTooLarge(x) => Error::ValueTooLarge(x),
36            StorageError::Io(x) => Error::Io(x),
37            StorageError::LockPoisoned(location) => Error::LockPoisoned(location),
38        }
39    }
40}
41
42impl Display for StorageError {
43    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44        match self {
45            StorageError::Corrupted(msg) => {
46                write!(f, "DB corrupted: {msg}")
47            }
48            StorageError::ValueTooLarge(len) => {
49                write!(
50                    f,
51                    "The value (length={len}) being inserted exceeds the maximum of {}GiB",
52                    MAX_VALUE_LENGTH / 1024 / 1024 / 1024
53                )
54            }
55            StorageError::Io(err) => {
56                write!(f, "I/O error: {err}")
57            }
58            StorageError::LockPoisoned(location) => {
59                write!(f, "Poisoned internal lock: {location}")
60            }
61        }
62    }
63}
64
65impl std::error::Error for StorageError {}
66
67/// Errors related to opening tables
68#[derive(Debug)]
69#[non_exhaustive]
70pub enum TableError {
71    /// Table types didn't match.
72    TableTypeMismatch {
73        table: String,
74        key: TypeName,
75        value: TypeName,
76    },
77    /// The table is a multimap table
78    TableIsMultimap(String),
79    /// The table is not a multimap table
80    TableIsNotMultimap(String),
81    TypeDefinitionChanged {
82        name: TypeName,
83        alignment: usize,
84        width: Option<usize>,
85    },
86    /// Table name does not match any table in database
87    TableDoesNotExist(String),
88    // Tables cannot be opened for writing multiple times, since they could retrieve immutable &
89    // mutable references to the same dirty pages, or multiple mutable references via insert_reserve()
90    TableAlreadyOpen(String, &'static panic::Location<'static>),
91    /// Error from underlying storage
92    Storage(StorageError),
93}
94
95impl TableError {
96    pub(crate) fn into_storage_error_or_corrupted(self, msg: &str) -> StorageError {
97        match self {
98            TableError::TableTypeMismatch { .. }
99            | TableError::TableIsMultimap(_)
100            | TableError::TableIsNotMultimap(_)
101            | TableError::TypeDefinitionChanged { .. }
102            | TableError::TableDoesNotExist(_)
103            | TableError::TableAlreadyOpen(_, _) => {
104                StorageError::Corrupted(format!("{}: {}", msg, &self))
105            }
106            TableError::Storage(storage) => storage,
107        }
108    }
109}
110
111impl From<TableError> for Error {
112    fn from(err: TableError) -> Error {
113        match err {
114            TableError::TypeDefinitionChanged {
115                name,
116                alignment,
117                width,
118            } => Error::TypeDefinitionChanged {
119                name,
120                alignment,
121                width,
122            },
123            TableError::TableTypeMismatch { table, key, value } => {
124                Error::TableTypeMismatch { table, key, value }
125            }
126            TableError::TableIsMultimap(table) => Error::TableIsMultimap(table),
127            TableError::TableIsNotMultimap(table) => Error::TableIsNotMultimap(table),
128            TableError::TableDoesNotExist(table) => Error::TableDoesNotExist(table),
129            TableError::TableAlreadyOpen(name, location) => Error::TableAlreadyOpen(name, location),
130            TableError::Storage(storage) => storage.into(),
131        }
132    }
133}
134
135impl From<StorageError> for TableError {
136    fn from(err: StorageError) -> TableError {
137        TableError::Storage(err)
138    }
139}
140
141impl Display for TableError {
142    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
143        match self {
144            TableError::TypeDefinitionChanged {
145                name,
146                alignment,
147                width,
148            } => {
149                write!(
150                    f,
151                    "Current definition of {} does not match stored definition (width={:?}, alignment={})",
152                    name.name(),
153                    width,
154                    alignment,
155                )
156            }
157            TableError::TableTypeMismatch { table, key, value } => {
158                write!(
159                    f,
160                    "{table} is of type Table<{}, {}>",
161                    key.name(),
162                    value.name(),
163                )
164            }
165            TableError::TableIsMultimap(table) => {
166                write!(f, "{table} is a multimap table")
167            }
168            TableError::TableIsNotMultimap(table) => {
169                write!(f, "{table} is not a multimap table")
170            }
171            TableError::TableDoesNotExist(table) => {
172                write!(f, "Table '{table}' does not exist")
173            }
174            TableError::TableAlreadyOpen(name, location) => {
175                write!(f, "Table '{name}' already opened at: {location}")
176            }
177            TableError::Storage(storage) => storage.fmt(f),
178        }
179    }
180}
181
182impl std::error::Error for TableError {}
183
184/// Errors related to opening a database
185#[derive(Debug)]
186#[non_exhaustive]
187pub enum DatabaseError {
188    /// The Database is already open. Cannot acquire lock.
189    DatabaseAlreadyOpen,
190    /// [crate::RepairSession::abort] was called.
191    RepairAborted,
192    /// The database file is in an old file format and must be manually upgraded
193    UpgradeRequired(u8),
194    /// Error from underlying storage
195    Storage(StorageError),
196}
197
198impl From<DatabaseError> for Error {
199    fn from(err: DatabaseError) -> Error {
200        match err {
201            DatabaseError::DatabaseAlreadyOpen => Error::DatabaseAlreadyOpen,
202            DatabaseError::RepairAborted => Error::RepairAborted,
203            DatabaseError::UpgradeRequired(x) => Error::UpgradeRequired(x),
204            DatabaseError::Storage(storage) => storage.into(),
205        }
206    }
207}
208
209impl From<io::Error> for DatabaseError {
210    fn from(err: io::Error) -> DatabaseError {
211        DatabaseError::Storage(StorageError::Io(err))
212    }
213}
214
215impl From<StorageError> for DatabaseError {
216    fn from(err: StorageError) -> DatabaseError {
217        DatabaseError::Storage(err)
218    }
219}
220
221impl Display for DatabaseError {
222    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223        match self {
224            DatabaseError::UpgradeRequired(actual) => {
225                write!(f, "Manual upgrade required. Expected file format version {FILE_FORMAT_VERSION}, but file is version {actual}")
226            }
227            DatabaseError::RepairAborted => {
228                write!(f, "Database repair aborted.")
229            }
230            DatabaseError::DatabaseAlreadyOpen => {
231                write!(f, "Database already open. Cannot acquire lock.")
232            }
233            DatabaseError::Storage(storage) => storage.fmt(f),
234        }
235    }
236}
237
238impl std::error::Error for DatabaseError {}
239
240/// Errors related to savepoints
241#[derive(Debug)]
242#[non_exhaustive]
243pub enum SavepointError {
244    /// This savepoint is invalid or cannot be created.
245    ///
246    /// Savepoints become invalid when an older savepoint is restored after it was created,
247    /// and savepoints cannot be created if the transaction is "dirty" (any tables have been opened)
248    InvalidSavepoint,
249    /// Error from underlying storage
250    Storage(StorageError),
251}
252
253impl From<SavepointError> for Error {
254    fn from(err: SavepointError) -> Error {
255        match err {
256            SavepointError::InvalidSavepoint => Error::InvalidSavepoint,
257            SavepointError::Storage(storage) => storage.into(),
258        }
259    }
260}
261
262impl From<StorageError> for SavepointError {
263    fn from(err: StorageError) -> SavepointError {
264        SavepointError::Storage(err)
265    }
266}
267
268impl Display for SavepointError {
269    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
270        match self {
271            SavepointError::InvalidSavepoint => {
272                write!(f, "Savepoint is invalid or cannot be created.")
273            }
274            SavepointError::Storage(storage) => storage.fmt(f),
275        }
276    }
277}
278
279impl std::error::Error for SavepointError {}
280
281/// Errors related to compaction
282#[derive(Debug)]
283#[non_exhaustive]
284pub enum CompactionError {
285    /// A persistent savepoint exists
286    PersistentSavepointExists,
287    /// A ephemeral savepoint exists
288    EphemeralSavepointExists,
289    /// Error from underlying storage
290    Storage(StorageError),
291}
292
293impl From<CompactionError> for Error {
294    fn from(err: CompactionError) -> Error {
295        match err {
296            CompactionError::PersistentSavepointExists => Error::PersistentSavepointExists,
297            CompactionError::EphemeralSavepointExists => Error::EphemeralSavepointExists,
298            CompactionError::Storage(storage) => storage.into(),
299        }
300    }
301}
302
303impl From<StorageError> for CompactionError {
304    fn from(err: StorageError) -> CompactionError {
305        CompactionError::Storage(err)
306    }
307}
308
309impl Display for CompactionError {
310    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
311        match self {
312            CompactionError::PersistentSavepointExists => {
313                write!(
314                    f,
315                    "Persistent savepoint exists. Operation cannot be performed."
316                )
317            }
318            CompactionError::EphemeralSavepointExists => {
319                write!(
320                    f,
321                    "Ephemeral savepoint exists. Operation cannot be performed."
322                )
323            }
324            CompactionError::Storage(storage) => storage.fmt(f),
325        }
326    }
327}
328
329impl std::error::Error for CompactionError {}
330
331/// Errors related to transactions
332#[derive(Debug)]
333#[non_exhaustive]
334pub enum TransactionError {
335    /// Error from underlying storage
336    Storage(StorageError),
337}
338
339impl TransactionError {
340    pub(crate) fn into_storage_error(self) -> StorageError {
341        match self {
342            TransactionError::Storage(storage) => storage,
343        }
344    }
345}
346
347impl From<TransactionError> for Error {
348    fn from(err: TransactionError) -> Error {
349        match err {
350            TransactionError::Storage(storage) => storage.into(),
351        }
352    }
353}
354
355impl From<StorageError> for TransactionError {
356    fn from(err: StorageError) -> TransactionError {
357        TransactionError::Storage(err)
358    }
359}
360
361impl Display for TransactionError {
362    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
363        match self {
364            TransactionError::Storage(storage) => storage.fmt(f),
365        }
366    }
367}
368
369impl std::error::Error for TransactionError {}
370
371/// Errors related to committing transactions
372#[derive(Debug)]
373#[non_exhaustive]
374pub enum CommitError {
375    /// Error from underlying storage
376    Storage(StorageError),
377}
378
379impl CommitError {
380    pub(crate) fn into_storage_error(self) -> StorageError {
381        match self {
382            CommitError::Storage(storage) => storage,
383        }
384    }
385}
386
387impl From<CommitError> for Error {
388    fn from(err: CommitError) -> Error {
389        match err {
390            CommitError::Storage(storage) => storage.into(),
391        }
392    }
393}
394
395impl From<StorageError> for CommitError {
396    fn from(err: StorageError) -> CommitError {
397        CommitError::Storage(err)
398    }
399}
400
401impl Display for CommitError {
402    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
403        match self {
404            CommitError::Storage(storage) => storage.fmt(f),
405        }
406    }
407}
408
409impl std::error::Error for CommitError {}
410
411/// Superset of all other errors that can occur. Convenience enum so that users can convert all errors into a single type
412#[derive(Debug)]
413#[non_exhaustive]
414pub enum Error {
415    /// The Database is already open. Cannot acquire lock.
416    DatabaseAlreadyOpen,
417    /// This savepoint is invalid or cannot be created.
418    ///
419    /// Savepoints become invalid when an older savepoint is restored after it was created,
420    /// and savepoints cannot be created if the transaction is "dirty" (any tables have been opened)
421    InvalidSavepoint,
422    /// [crate::RepairSession::abort] was called.
423    RepairAborted,
424    /// A persistent savepoint exists
425    PersistentSavepointExists,
426    /// An Ephemeral savepoint exists
427    EphemeralSavepointExists,
428    /// The Database is corrupted
429    Corrupted(String),
430    /// The database file is in an old file format and must be manually upgraded
431    UpgradeRequired(u8),
432    /// The value being inserted exceeds the maximum of 3GiB
433    ValueTooLarge(usize),
434    /// Table types didn't match.
435    TableTypeMismatch {
436        table: String,
437        key: TypeName,
438        value: TypeName,
439    },
440    /// The table is a multimap table
441    TableIsMultimap(String),
442    /// The table is not a multimap table
443    TableIsNotMultimap(String),
444    TypeDefinitionChanged {
445        name: TypeName,
446        alignment: usize,
447        width: Option<usize>,
448    },
449    /// Table name does not match any table in database
450    TableDoesNotExist(String),
451    // Tables cannot be opened for writing multiple times, since they could retrieve immutable &
452    // mutable references to the same dirty pages, or multiple mutable references via insert_reserve()
453    TableAlreadyOpen(String, &'static panic::Location<'static>),
454    Io(io::Error),
455    LockPoisoned(&'static panic::Location<'static>),
456}
457
458impl<T> From<PoisonError<T>> for Error {
459    fn from(_: PoisonError<T>) -> Error {
460        Error::LockPoisoned(panic::Location::caller())
461    }
462}
463
464impl From<io::Error> for Error {
465    fn from(err: io::Error) -> Error {
466        Error::Io(err)
467    }
468}
469
470impl Display for Error {
471    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
472        match self {
473            Error::Corrupted(msg) => {
474                write!(f, "DB corrupted: {msg}")
475            }
476            Error::UpgradeRequired(actual) => {
477                write!(f, "Manual upgrade required. Expected file format version {FILE_FORMAT_VERSION}, but file is version {actual}")
478            }
479            Error::ValueTooLarge(len) => {
480                write!(
481                    f,
482                    "The value (length={len}) being inserted exceeds the maximum of {}GiB",
483                    MAX_VALUE_LENGTH / 1024 / 1024 / 1024
484                )
485            }
486            Error::TypeDefinitionChanged {
487                name,
488                alignment,
489                width,
490            } => {
491                write!(
492                    f,
493                    "Current definition of {} does not match stored definition (width={:?}, alignment={})",
494                    name.name(),
495                    width,
496                    alignment,
497                )
498            }
499            Error::TableTypeMismatch { table, key, value } => {
500                write!(
501                    f,
502                    "{table} is of type Table<{}, {}>",
503                    key.name(),
504                    value.name(),
505                )
506            }
507            Error::TableIsMultimap(table) => {
508                write!(f, "{table} is a multimap table")
509            }
510            Error::TableIsNotMultimap(table) => {
511                write!(f, "{table} is not a multimap table")
512            }
513            Error::TableDoesNotExist(table) => {
514                write!(f, "Table '{table}' does not exist")
515            }
516            Error::TableAlreadyOpen(name, location) => {
517                write!(f, "Table '{name}' already opened at: {location}")
518            }
519            Error::Io(err) => {
520                write!(f, "I/O error: {err}")
521            }
522            Error::LockPoisoned(location) => {
523                write!(f, "Poisoned internal lock: {location}")
524            }
525            Error::DatabaseAlreadyOpen => {
526                write!(f, "Database already open. Cannot acquire lock.")
527            }
528            Error::RepairAborted => {
529                write!(f, "Database repair aborted.")
530            }
531            Error::PersistentSavepointExists => {
532                write!(
533                    f,
534                    "Persistent savepoint exists. Operation cannot be performed."
535                )
536            }
537            Error::EphemeralSavepointExists => {
538                write!(
539                    f,
540                    "Ephemeral savepoint exists. Operation cannot be performed."
541                )
542            }
543            Error::InvalidSavepoint => {
544                write!(f, "Savepoint is invalid or cannot be created.")
545            }
546        }
547    }
548}
549
550impl std::error::Error for Error {}