cuprate_database/backend/heed/error.rs
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
//! Conversion from `heed::Error` -> `cuprate_database`'s errors.
//---------------------------------------------------------------------------------------------------- Use
use crate::constants::DATABASE_CORRUPT_MSG;
//---------------------------------------------------------------------------------------------------- InitError
impl From<heed::Error> for crate::InitError {
fn from(error: heed::Error) -> Self {
use heed::Error as E1;
use heed::MdbError as E2;
// Reference of all possible errors `heed` will return
// upon using [`heed::EnvOpenOptions::open`]:
// <https://docs.rs/heed/latest/src/heed/env.rs.html#149-219>
match error {
E1::Io(io_error) => Self::Io(io_error),
E1::DatabaseClosing => Self::ShuttingDown,
// LMDB errors.
E1::Mdb(mdb_error) => match mdb_error {
E2::Invalid => Self::Invalid,
E2::VersionMismatch => Self::InvalidVersion,
// "Located page was wrong type".
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.Corrupted>
//
// "Requested page not found - this usually indicates corruption."
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
E2::Corrupted | E2::PageNotFound => Self::Corrupt,
// These errors shouldn't be returned on database init.
E2::Incompatible
| E2::Other(_)
| E2::BadTxn
| E2::Problem
| E2::KeyExist
| E2::NotFound
| E2::MapFull
| E2::ReadersFull
| E2::PageFull
| E2::DbsFull
| E2::TlsFull
| E2::TxnFull
| E2::CursorFull
| E2::MapResized
| E2::BadRslot
| E2::BadValSize
| E2::BadDbi
| E2::Panic => Self::Unknown(Box::new(mdb_error)),
},
E1::BadOpenOptions { .. } | E1::Encoding(_) | E1::Decoding(_) => {
Self::Unknown(Box::new(error))
}
}
}
}
//---------------------------------------------------------------------------------------------------- RuntimeError
#[expect(
clippy::fallible_impl_from,
reason = "We need to panic sometimes for safety"
)]
impl From<heed::Error> for crate::RuntimeError {
/// # Panics
/// This will panic on unrecoverable errors for safety.
fn from(error: heed::Error) -> Self {
use heed::Error as E1;
use heed::MdbError as E2;
match error {
// I/O errors.
E1::Io(io_error) => Self::Io(io_error),
// LMDB errors.
E1::Mdb(mdb_error) => match mdb_error {
E2::KeyExist => Self::KeyExists,
E2::NotFound => Self::KeyNotFound,
E2::MapFull => Self::ResizeNeeded,
// Corruption errors, these have special panic messages.
//
// "Located page was wrong type".
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.Corrupted>
//
// "Requested page not found - this usually indicates corruption."
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
E2::Corrupted | E2::PageNotFound => panic!("{mdb_error:#?}\n{DATABASE_CORRUPT_MSG}"),
// These errors should not occur, and if they do,
// the best thing `cuprate_database` can do for
// safety is to panic right here.
E2::Panic
| E2::PageFull
| E2::Other(_)
| E2::BadTxn
| E2::Problem
| E2::Invalid
| E2::TlsFull
| E2::TxnFull
| E2::BadRslot
| E2::VersionMismatch
| E2::BadDbi => panic!("{mdb_error:#?}"),
// These errors are the same as above, but instead
// of being errors we can't control, these are errors
// that only happen if we write incorrect code.
// "Database contents grew beyond environment mapsize."
// We should be resizing the map when needed, this error
// occurring indicates we did _not_ do that, which is a bug
// and we should panic.
//
// FIXME: This can also mean _another_ process wrote to our
// LMDB file and increased the size. I don't think we need to accommodate for this.
// <http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5>
// Although `monerod` reacts to that instead of `MDB_MAP_FULL`
// which is what `mdb_put()` returns so... idk?
// <https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L526>
| E2::MapResized
// We should be setting `heed::EnvOpenOptions::max_readers()`
// with our reader thread value in [`crate::config::Config`],
// thus this error should never occur.
// <http://www.lmdb.tech/doc/group__mdb.html#gae687966c24b790630be2a41573fe40e2>
| E2::ReadersFull
// Do not open more database tables than we initially started with.
// We know this number at compile time (amount of `Table`'s) so this
// should never happen.
// <https://docs.rs/heed/0.20.0-alpha.9/heed/struct.EnvOpenOptions.html#method.max_dbs>
// <https://docs.rs/heed/0.20.0-alpha.9/src/heed/env.rs.html#251>
| E2::DbsFull
// Don't do crazy multi-nested LMDB cursor stuff.
| E2::CursorFull
// <https://docs.rs/heed/0.20.0-alpha.9/heed/enum.MdbError.html#variant.Incompatible>
| E2::Incompatible
// Unsupported size of key/DB name/data, or wrong DUP_FIXED size.
// Don't use a key that is `>511` bytes.
// <http://www.lmdb.tech/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94>
| E2::BadValSize
=> panic!("E2: fix the database code! {mdb_error:#?}"),
},
// Only if we write incorrect code.
E1::DatabaseClosing | E1::BadOpenOptions { .. } | E1::Encoding(_) | E1::Decoding(_) => {
panic!("E1: fix the database code! {error:#?}")
}
}
}
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
// use super::*;
}