cuprate_database/backend/heed/error.rs
1//! Conversion from `heed::Error` -> `cuprate_database`'s errors.
2
3//---------------------------------------------------------------------------------------------------- Use
4use crate::constants::DATABASE_CORRUPT_MSG;
5
6//---------------------------------------------------------------------------------------------------- InitError
7impl From<heed::Error> for crate::InitError {
8 fn from(error: heed::Error) -> Self {
9 use heed::Error as E1;
10 use heed::MdbError as E2;
11
12 // Reference of all possible errors `heed` will return
13 // upon using [`heed::EnvOpenOptions::open`]:
14 // <https://docs.rs/heed/latest/src/heed/env.rs.html#149-219>
15 match error {
16 E1::Io(io_error) => Self::Io(io_error),
17 E1::DatabaseClosing => Self::ShuttingDown,
18
19 // LMDB errors.
20 E1::Mdb(mdb_error) => match mdb_error {
21 E2::Invalid => Self::Invalid,
22 E2::VersionMismatch => Self::InvalidVersion,
23
24 // "Located page was wrong type".
25 // <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.Corrupted>
26 //
27 // "Requested page not found - this usually indicates corruption."
28 // <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
29 E2::BadDbi | E2::Corrupted | E2::PageNotFound => Self::Corrupt,
30
31 // These errors shouldn't be returned on database init.
32 E2::Incompatible
33 | E2::Other(_)
34 | E2::BadTxn
35 | E2::Problem
36 | E2::KeyExist
37 | E2::NotFound
38 | E2::MapFull
39 | E2::ReadersFull
40 | E2::PageFull
41 | E2::DbsFull
42 | E2::TlsFull
43 | E2::TxnFull
44 | E2::CursorFull
45 | E2::MapResized
46 | E2::BadRslot
47 | E2::BadValSize
48 | E2::Panic => Self::Unknown(Box::new(mdb_error)),
49 },
50
51 E1::BadOpenOptions { .. } | E1::Encoding(_) | E1::Decoding(_) => {
52 Self::Unknown(Box::new(error))
53 }
54 }
55 }
56}
57
58//---------------------------------------------------------------------------------------------------- RuntimeError
59#[expect(
60 clippy::fallible_impl_from,
61 reason = "We need to panic sometimes for safety"
62)]
63impl From<heed::Error> for crate::RuntimeError {
64 /// # Panics
65 /// This will panic on unrecoverable errors for safety.
66 fn from(error: heed::Error) -> Self {
67 use heed::Error as E1;
68 use heed::MdbError as E2;
69
70 match error {
71 // I/O errors.
72 E1::Io(io_error) => Self::Io(io_error),
73
74 // LMDB errors.
75 E1::Mdb(mdb_error) => match mdb_error {
76 E2::KeyExist => Self::KeyExists,
77 E2::NotFound => Self::KeyNotFound,
78 E2::MapFull => Self::ResizeNeeded,
79
80 // Corruption errors, these have special panic messages.
81 //
82 // "Located page was wrong type".
83 // <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.Corrupted>
84 //
85 // "Requested page not found - this usually indicates corruption."
86 // <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
87 E2::BadDbi | E2::Corrupted | E2::PageNotFound => panic!("{mdb_error:#?}\n{DATABASE_CORRUPT_MSG}"),
88
89 // These errors should not occur, and if they do,
90 // the best thing `cuprate_database` can do for
91 // safety is to panic right here.
92 E2::Panic
93 | E2::PageFull
94 | E2::Other(_)
95 | E2::BadTxn
96 | E2::Problem
97 | E2::Invalid
98 | E2::TlsFull
99 | E2::TxnFull
100 | E2::BadRslot
101 | E2::VersionMismatch => panic!("{mdb_error:#?}"),
102
103 // These errors are the same as above, but instead
104 // of being errors we can't control, these are errors
105 // that only happen if we write incorrect code.
106
107 // "Database contents grew beyond environment mapsize."
108 // We should be resizing the map when needed, this error
109 // occurring indicates we did _not_ do that, which is a bug
110 // and we should panic.
111 //
112 // FIXME: This can also mean _another_ process wrote to our
113 // LMDB file and increased the size. I don't think we need to accommodate for this.
114 // <http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5>
115 // Although `monerod` reacts to that instead of `MDB_MAP_FULL`
116 // which is what `mdb_put()` returns so... idk?
117 // <https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L526>
118 | E2::MapResized
119 // We should be setting `heed::EnvOpenOptions::max_readers()`
120 // with our reader thread value in [`crate::config::Config`],
121 // thus this error should never occur.
122 // <http://www.lmdb.tech/doc/group__mdb.html#gae687966c24b790630be2a41573fe40e2>
123 | E2::ReadersFull
124 // Do not open more database tables than we initially started with.
125 // We know this number at compile time (amount of `Table`'s) so this
126 // should never happen.
127 // <https://docs.rs/heed/0.20.0-alpha.9/heed/struct.EnvOpenOptions.html#method.max_dbs>
128 // <https://docs.rs/heed/0.20.0-alpha.9/src/heed/env.rs.html#251>
129 | E2::DbsFull
130 // Don't do crazy multi-nested LMDB cursor stuff.
131 | E2::CursorFull
132 // <https://docs.rs/heed/0.20.0-alpha.9/heed/enum.MdbError.html#variant.Incompatible>
133 | E2::Incompatible
134 // Unsupported size of key/DB name/data, or wrong DUP_FIXED size.
135 // Don't use a key that is `>511` bytes.
136 // <http://www.lmdb.tech/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94>
137 | E2::BadValSize
138 => panic!("E2: fix the database code! {mdb_error:#?}"),
139 },
140
141 // Only if we write incorrect code.
142 E1::DatabaseClosing | E1::BadOpenOptions { .. } | E1::Encoding(_) | E1::Decoding(_) => {
143 panic!("E1: fix the database code! {error:#?}")
144 }
145 }
146 }
147}
148
149//---------------------------------------------------------------------------------------------------- Tests
150#[cfg(test)]
151mod test {
152 // use super::*;
153}