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("database should be recovered, but cannot be done automatically since it's in read-only mode")]
92 WannaRecovery,
93 #[error("the given key value is mismatched to the current cursor position")]
95 KeyMismatch,
96 #[error("invalid parameter specified")]
98 DecodeError,
99 #[error("the environment opened in read-only, check <https://reth.rs/run/troubleshooting.html> for more")]
101 Access,
102 #[error("database is too large for the current system")]
104 TooLarge,
105 #[error("invalid parameter specified or active write transaction")]
109 DecodeErrorLenDiff,
110 #[error("nested transactions are not supported with WriteMap")]
114 NestedTransactionsUnsupportedWithWriteMap,
115 #[error("write transactions are not supported in read-only mode")]
118 WriteTransactionUnsupportedInReadOnlyMode,
119 #[error("read transaction has been timed out")]
121 ReadTransactionTimeout,
122 #[error("permission denied to setup database")]
124 Permission,
125 #[error("unknown error code: {0}")]
127 Other(i32),
128}
129
130impl Error {
131 pub const fn from_err_code(err_code: c_int) -> Self {
133 match err_code {
134 ffi::MDBX_KEYEXIST => Self::KeyExist,
135 ffi::MDBX_NOTFOUND => Self::NotFound,
136 ffi::MDBX_ENODATA => Self::NoData,
137 ffi::MDBX_PAGE_NOTFOUND => Self::PageNotFound,
138 ffi::MDBX_CORRUPTED => Self::Corrupted,
139 ffi::MDBX_PANIC => Self::Panic,
140 ffi::MDBX_VERSION_MISMATCH => Self::VersionMismatch,
141 ffi::MDBX_INVALID => Self::Invalid,
142 ffi::MDBX_MAP_FULL => Self::MapFull,
143 ffi::MDBX_DBS_FULL => Self::DbsFull,
144 ffi::MDBX_READERS_FULL => Self::ReadersFull,
145 ffi::MDBX_TXN_FULL => Self::TxnFull,
146 ffi::MDBX_CURSOR_FULL => Self::CursorFull,
147 ffi::MDBX_PAGE_FULL => Self::PageFull,
148 ffi::MDBX_UNABLE_EXTEND_MAPSIZE => Self::UnableExtendMapSize,
149 ffi::MDBX_INCOMPATIBLE => Self::Incompatible,
150 ffi::MDBX_BAD_RSLOT => Self::BadRslot,
151 ffi::MDBX_BAD_TXN => Self::BadTxn,
152 ffi::MDBX_BAD_VALSIZE => Self::BadValSize,
153 ffi::MDBX_BAD_DBI => Self::BadDbi,
154 ffi::MDBX_PROBLEM => Self::Problem,
155 ffi::MDBX_BUSY => Self::Busy,
156 ffi::MDBX_EMULTIVAL => Self::Multival,
157 ffi::MDBX_WANNA_RECOVERY => Self::WannaRecovery,
158 ffi::MDBX_EKEYMISMATCH => Self::KeyMismatch,
159 ffi::MDBX_EINVAL => Self::DecodeError,
160 ffi::MDBX_EACCESS => Self::Access,
161 ffi::MDBX_TOO_LARGE => Self::TooLarge,
162 ffi::MDBX_EBADSIGN => Self::BadSignature,
163 ffi::MDBX_EPERM => Self::Permission,
164 other => Self::Other(other),
165 }
166 }
167
168 pub const fn to_err_code(&self) -> i32 {
170 match self {
171 Self::KeyExist => ffi::MDBX_KEYEXIST,
172 Self::NotFound => ffi::MDBX_NOTFOUND,
173 Self::NoData => ffi::MDBX_ENODATA,
174 Self::PageNotFound => ffi::MDBX_PAGE_NOTFOUND,
175 Self::Corrupted => ffi::MDBX_CORRUPTED,
176 Self::Panic => ffi::MDBX_PANIC,
177 Self::VersionMismatch => ffi::MDBX_VERSION_MISMATCH,
178 Self::Invalid => ffi::MDBX_INVALID,
179 Self::MapFull => ffi::MDBX_MAP_FULL,
180 Self::DbsFull => ffi::MDBX_DBS_FULL,
181 Self::ReadersFull => ffi::MDBX_READERS_FULL,
182 Self::TxnFull => ffi::MDBX_TXN_FULL,
183 Self::CursorFull => ffi::MDBX_CURSOR_FULL,
184 Self::PageFull => ffi::MDBX_PAGE_FULL,
185 Self::UnableExtendMapSize => ffi::MDBX_UNABLE_EXTEND_MAPSIZE,
186 Self::Incompatible => ffi::MDBX_INCOMPATIBLE,
187 Self::BadRslot => ffi::MDBX_BAD_RSLOT,
188 Self::BadTxn => ffi::MDBX_BAD_TXN,
189 Self::BadValSize => ffi::MDBX_BAD_VALSIZE,
190 Self::BadDbi => ffi::MDBX_BAD_DBI,
191 Self::Problem => ffi::MDBX_PROBLEM,
192 Self::Busy => ffi::MDBX_BUSY,
193 Self::Multival => ffi::MDBX_EMULTIVAL,
194 Self::WannaRecovery => ffi::MDBX_WANNA_RECOVERY,
195 Self::KeyMismatch => ffi::MDBX_EKEYMISMATCH,
196 Self::DecodeErrorLenDiff | Self::DecodeError => ffi::MDBX_EINVAL,
197 Self::TooLarge => ffi::MDBX_TOO_LARGE,
198 Self::BadSignature => ffi::MDBX_EBADSIGN,
199 Self::Access |
200 Self::WriteTransactionUnsupportedInReadOnlyMode |
201 Self::NestedTransactionsUnsupportedWithWriteMap => ffi::MDBX_EACCESS,
202 Self::ReadTransactionTimeout => -96000, Self::Permission => ffi::MDBX_EPERM,
204 Self::Other(err_code) => *err_code,
205 }
206 }
207}
208
209impl From<Error> for i32 {
210 fn from(value: Error) -> Self {
211 value.to_err_code()
212 }
213}
214
215#[inline]
216pub(crate) const fn mdbx_result(err_code: c_int) -> Result<bool> {
217 match err_code {
218 ffi::MDBX_SUCCESS => Ok(false),
219 ffi::MDBX_RESULT_TRUE => Ok(true),
220 other => Err(Error::from_err_code(other)),
221 }
222}
223
224#[macro_export]
225macro_rules! mdbx_try_optional {
226 ($expr:expr) => {{
227 match $expr {
228 Err(Error::NotFound | Error::NoData) => return Ok(None),
229 Err(e) => return Err(e),
230 Ok(v) => v,
231 }
232 }};
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn test_description() {
241 assert_eq!(
242 "the environment opened in read-only, check <https://reth.rs/run/troubleshooting.html> for more",
243 Error::from_err_code(13).to_string()
244 );
245
246 assert_eq!("file is not an MDBX file", Error::Invalid.to_string());
247 }
248
249 #[test]
250 fn test_conversion() {
251 assert_eq!(Error::from_err_code(ffi::MDBX_KEYEXIST), Error::KeyExist);
252 }
253}