1use std::{ffi::c_int, result};
2
3pub type Result<T> = result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq)]
8pub enum Error {
9 #[error("key/data pair already exists")]
11 KeyExist,
12 #[error("no matching key/data pair found")]
14 NotFound,
15 #[error("the cursor is already at the end of data")]
17 NoData,
18 #[error("requested page not found")]
20 PageNotFound,
21 #[error("database is corrupted")]
23 Corrupted,
24 #[error("fatal environment error")]
26 Panic,
27 #[error("DB version mismatch")]
29 VersionMismatch,
30 #[error("file is not an MDBX file")]
32 Invalid,
33 #[error("environment map size limit reached")]
35 MapFull,
36 #[error("too many DBI-handles (maxdbs reached)")]
38 DbsFull,
39 #[error("too many readers (maxreaders reached)")]
41 ReadersFull,
42 #[error("transaction has too many dirty pages (i.e., the transaction is too big)")]
44 TxnFull,
45 #[error("cursor stack limit reached")]
47 CursorFull,
48 #[error("page has no more space")]
50 PageFull,
51 #[error("database engine was unable to extend mapping")]
61 UnableExtendMapSize,
62 #[error("environment or database is not compatible with the requested operation or flags")]
64 Incompatible,
65 #[error("invalid reuse of reader locktable slot")]
67 BadRslot,
68 #[error("transaction is not valid for requested operation")]
70 BadTxn,
71 #[error("invalid size or alignment of key or data for the target database")]
73 BadValSize,
74 #[error("the specified DBI-handle is invalid")]
76 BadDbi,
77 #[error("unexpected internal error")]
79 Problem,
80 #[error("another write transaction is running")]
82 Busy,
83 #[error("the specified key has more than one associated value")]
85 Multival,
86 #[error("wrong signature of a runtime object(s)")]
88 BadSignature,
89 #[error(
92 "database should be recovered, but cannot be done automatically since it's in read-only mode"
93 )]
94 WannaRecovery,
95 #[error("the given key value is mismatched to the current cursor position")]
97 KeyMismatch,
98 #[error("invalid parameter specified")]
100 DecodeError,
101 #[error(
103 "the environment opened in read-only, check <https://reth.rs/run/troubleshooting.html> for more"
104 )]
105 Access,
106 #[error("database is too large for the current system")]
108 TooLarge,
109 #[error("invalid parameter specified or active write transaction")]
113 DecodeErrorLenDiff,
114 #[error("nested transactions are not supported with WriteMap")]
118 NestedTransactionsUnsupportedWithWriteMap,
119 #[error("write transactions are not supported in read-only mode")]
122 WriteTransactionUnsupportedInReadOnlyMode,
123 #[error("read transaction has been timed out")]
125 ReadTransactionTimeout,
126 #[error("permission denied to setup database")]
128 Permission,
129 #[error("unknown error code: {0}")]
131 Other(i32),
132}
133
134impl Error {
135 pub const fn from_err_code(err_code: c_int) -> Self {
137 match err_code {
138 ffi::MDBX_KEYEXIST => Self::KeyExist,
139 ffi::MDBX_NOTFOUND => Self::NotFound,
140 ffi::MDBX_ENODATA => Self::NoData,
141 ffi::MDBX_PAGE_NOTFOUND => Self::PageNotFound,
142 ffi::MDBX_CORRUPTED => Self::Corrupted,
143 ffi::MDBX_PANIC => Self::Panic,
144 ffi::MDBX_VERSION_MISMATCH => Self::VersionMismatch,
145 ffi::MDBX_INVALID => Self::Invalid,
146 ffi::MDBX_MAP_FULL => Self::MapFull,
147 ffi::MDBX_DBS_FULL => Self::DbsFull,
148 ffi::MDBX_READERS_FULL => Self::ReadersFull,
149 ffi::MDBX_TXN_FULL => Self::TxnFull,
150 ffi::MDBX_CURSOR_FULL => Self::CursorFull,
151 ffi::MDBX_PAGE_FULL => Self::PageFull,
152 ffi::MDBX_UNABLE_EXTEND_MAPSIZE => Self::UnableExtendMapSize,
153 ffi::MDBX_INCOMPATIBLE => Self::Incompatible,
154 ffi::MDBX_BAD_RSLOT => Self::BadRslot,
155 ffi::MDBX_BAD_TXN => Self::BadTxn,
156 ffi::MDBX_BAD_VALSIZE => Self::BadValSize,
157 ffi::MDBX_BAD_DBI => Self::BadDbi,
158 ffi::MDBX_PROBLEM => Self::Problem,
159 ffi::MDBX_BUSY => Self::Busy,
160 ffi::MDBX_EMULTIVAL => Self::Multival,
161 ffi::MDBX_WANNA_RECOVERY => Self::WannaRecovery,
162 ffi::MDBX_EKEYMISMATCH => Self::KeyMismatch,
163 ffi::MDBX_EINVAL => Self::DecodeError,
164 ffi::MDBX_EACCESS => Self::Access,
165 ffi::MDBX_TOO_LARGE => Self::TooLarge,
166 ffi::MDBX_EBADSIGN => Self::BadSignature,
167 ffi::MDBX_EPERM => Self::Permission,
168 other => Self::Other(other),
169 }
170 }
171
172 pub const fn to_err_code(&self) -> i32 {
174 match self {
175 Self::KeyExist => ffi::MDBX_KEYEXIST,
176 Self::NotFound => ffi::MDBX_NOTFOUND,
177 Self::NoData => ffi::MDBX_ENODATA,
178 Self::PageNotFound => ffi::MDBX_PAGE_NOTFOUND,
179 Self::Corrupted => ffi::MDBX_CORRUPTED,
180 Self::Panic => ffi::MDBX_PANIC,
181 Self::VersionMismatch => ffi::MDBX_VERSION_MISMATCH,
182 Self::Invalid => ffi::MDBX_INVALID,
183 Self::MapFull => ffi::MDBX_MAP_FULL,
184 Self::DbsFull => ffi::MDBX_DBS_FULL,
185 Self::ReadersFull => ffi::MDBX_READERS_FULL,
186 Self::TxnFull => ffi::MDBX_TXN_FULL,
187 Self::CursorFull => ffi::MDBX_CURSOR_FULL,
188 Self::PageFull => ffi::MDBX_PAGE_FULL,
189 Self::UnableExtendMapSize => ffi::MDBX_UNABLE_EXTEND_MAPSIZE,
190 Self::Incompatible => ffi::MDBX_INCOMPATIBLE,
191 Self::BadRslot => ffi::MDBX_BAD_RSLOT,
192 Self::BadTxn => ffi::MDBX_BAD_TXN,
193 Self::BadValSize => ffi::MDBX_BAD_VALSIZE,
194 Self::BadDbi => ffi::MDBX_BAD_DBI,
195 Self::Problem => ffi::MDBX_PROBLEM,
196 Self::Busy => ffi::MDBX_BUSY,
197 Self::Multival => ffi::MDBX_EMULTIVAL,
198 Self::WannaRecovery => ffi::MDBX_WANNA_RECOVERY,
199 Self::KeyMismatch => ffi::MDBX_EKEYMISMATCH,
200 Self::DecodeErrorLenDiff | Self::DecodeError => ffi::MDBX_EINVAL,
201 Self::TooLarge => ffi::MDBX_TOO_LARGE,
202 Self::BadSignature => ffi::MDBX_EBADSIGN,
203 Self::Access |
204 Self::WriteTransactionUnsupportedInReadOnlyMode |
205 Self::NestedTransactionsUnsupportedWithWriteMap => ffi::MDBX_EACCESS,
206 Self::ReadTransactionTimeout => -96000, Self::Permission => ffi::MDBX_EPERM,
208 Self::Other(err_code) => *err_code,
209 }
210 }
211}
212
213impl From<Error> for i32 {
214 fn from(value: Error) -> Self {
215 value.to_err_code()
216 }
217}
218
219#[inline]
220pub(crate) const fn mdbx_result(err_code: c_int) -> Result<bool> {
221 match err_code {
222 ffi::MDBX_SUCCESS => Ok(false),
223 ffi::MDBX_RESULT_TRUE => Ok(true),
224 other => Err(Error::from_err_code(other)),
225 }
226}
227
228#[macro_export]
229macro_rules! mdbx_try_optional {
230 ($expr:expr) => {{
231 match $expr {
232 Err(Error::NotFound | Error::NoData) => return Ok(None),
233 Err(e) => return Err(e),
234 Ok(v) => v,
235 }
236 }};
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn test_description() {
245 assert_eq!(
246 "the environment opened in read-only, check <https://reth.rs/run/troubleshooting.html> for more",
247 Error::from_err_code(13).to_string()
248 );
249
250 assert_eq!("file is not an MDBX file", Error::Invalid.to_string());
251 }
252
253 #[test]
254 fn test_conversion() {
255 assert_eq!(Error::from_err_code(ffi::MDBX_KEYEXIST), Error::KeyExist);
256 }
257}