Skip to main content

reth_storage_errors/
db.rs

1use alloc::{
2    boxed::Box,
3    format,
4    string::{String, ToString},
5    sync::Arc,
6    vec::Vec,
7};
8use core::{
9    error::Error,
10    fmt::{Debug, Display},
11    str::FromStr,
12};
13use reth_codecs::DecompressError;
14
15/// Database error type.
16#[derive(Clone, Debug, thiserror::Error)]
17pub enum DatabaseError {
18    /// Failed to open the database.
19    #[error("failed to open the database: {_0}")]
20    Open(DatabaseErrorInfo),
21    /// Failed to create a table in the database.
22    #[error("failed to create a table: {_0}")]
23    CreateTable(DatabaseErrorInfo),
24    /// Failed to write a value into a table.
25    #[error(transparent)]
26    Write(Box<DatabaseWriteError>),
27    /// Failed to read a value from a table.
28    #[error("failed to read a value from a database table: {_0}")]
29    Read(DatabaseErrorInfo),
30    /// Failed to delete a `(key, value)` pair from a table.
31    #[error("database delete error code: {_0}")]
32    Delete(DatabaseErrorInfo),
33    /// Failed to commit transaction changes into the database.
34    #[error("failed to commit transaction changes: {_0}")]
35    Commit(DatabaseErrorInfo),
36    /// Failed to initialize a transaction.
37    #[error("failed to initialize a transaction: {_0}")]
38    InitTx(DatabaseErrorInfo),
39    /// Failed to initialize a cursor.
40    #[error("failed to initialize a cursor: {_0}")]
41    InitCursor(DatabaseErrorInfo),
42    /// Failed to decode a key from a table.
43    #[error("failed to decode a key from a table")]
44    Decode,
45    /// Failed to get database stats.
46    #[error("failed to get stats: {_0}")]
47    Stats(DatabaseErrorInfo),
48    /// Failed to use the specified log level, as it's not available.
49    #[error("log level {_0:?} is not available")]
50    LogLevelUnavailable(LogLevel),
51    /// Other unspecified error.
52    #[error("{_0}")]
53    Other(String),
54    /// Other unspecified error.
55    #[error(transparent)]
56    Custom(#[from] Arc<dyn Error + Send + Sync>),
57}
58
59/// Common error struct to propagate implementation-specific error information.
60#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
61#[display("{message} ({code})")]
62pub struct DatabaseErrorInfo {
63    /// Human-readable error message.
64    pub message: Box<str>,
65    /// Error code.
66    pub code: i32,
67}
68
69impl<E> From<E> for DatabaseErrorInfo
70where
71    E: Display + Into<i32>,
72{
73    #[inline]
74    fn from(error: E) -> Self {
75        Self { message: error.to_string().into(), code: error.into() }
76    }
77}
78
79impl From<DatabaseWriteError> for DatabaseError {
80    #[inline]
81    fn from(error: DatabaseWriteError) -> Self {
82        Self::Write(Box::new(error))
83    }
84}
85
86impl From<reth_codecs::DecompressError> for DatabaseError {
87    #[inline]
88    fn from(_: DecompressError) -> Self {
89        Self::Decode
90    }
91}
92
93/// Database write error.
94#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
95#[error("write operation {:?} failed for key \"{}\" in table {}: {}",
96            self.operation,
97            alloy_primitives::hex::encode(&self.key),
98            self.table_name,
99            self.info)]
100pub struct DatabaseWriteError {
101    /// The error code and message.
102    pub info: DatabaseErrorInfo,
103    /// The write operation type.
104    pub operation: DatabaseWriteOperation,
105    /// The table name.
106    pub table_name: &'static str,
107    /// The write key.
108    pub key: Vec<u8>,
109}
110
111/// Database write operation type.
112#[derive(Clone, Copy, Debug, PartialEq, Eq)]
113pub enum DatabaseWriteOperation {
114    /// Append cursor.
115    CursorAppend,
116    /// Upsert cursor.
117    CursorUpsert,
118    /// Insert cursor.
119    CursorInsert,
120    /// Append duplicate cursor.
121    CursorAppendDup,
122    /// Put upsert.
123    PutUpsert,
124    /// Put append.
125    PutAppend,
126    /// Flush to disk.
127    Flush,
128}
129
130/// Database log level.
131#[derive(Debug, PartialEq, Eq, Clone, Copy)]
132pub enum LogLevel {
133    /// Enables logging for critical conditions, i.e. assertion failures.
134    Fatal,
135    /// Enables logging for error conditions.
136    Error,
137    /// Enables logging for warning conditions.
138    Warn,
139    /// Enables logging for normal but significant condition.
140    Notice,
141    /// Enables logging for verbose informational.
142    Verbose,
143    /// Enables logging for debug-level messages.
144    Debug,
145    /// Enables logging for trace debug-level messages.
146    Trace,
147    /// Enables logging for extra debug-level messages.
148    Extra,
149}
150
151impl LogLevel {
152    /// All possible variants of the `LogLevel` enum
153    pub const fn value_variants() -> &'static [Self] {
154        &[
155            Self::Fatal,
156            Self::Error,
157            Self::Warn,
158            Self::Notice,
159            Self::Verbose,
160            Self::Debug,
161            Self::Trace,
162            Self::Extra,
163        ]
164    }
165
166    /// Static str reference to `LogLevel` enum, required for `Clap::Builder::PossibleValue::new()`
167    pub const fn variant_name(&self) -> &'static str {
168        match self {
169            Self::Fatal => "fatal",
170            Self::Error => "error",
171            Self::Warn => "warn",
172            Self::Notice => "notice",
173            Self::Verbose => "verbose",
174            Self::Debug => "debug",
175            Self::Trace => "trace",
176            Self::Extra => "extra",
177        }
178    }
179
180    /// Returns all variants descriptions
181    pub const fn help_message(&self) -> &'static str {
182        match self {
183            Self::Fatal => "Enables logging for critical conditions, i.e. assertion failures",
184            Self::Error => "Enables logging for error conditions",
185            Self::Warn => "Enables logging for warning conditions",
186            Self::Notice => "Enables logging for normal but significant condition",
187            Self::Verbose => "Enables logging for verbose informational",
188            Self::Debug => "Enables logging for debug-level messages",
189            Self::Trace => "Enables logging for trace debug-level messages",
190            Self::Extra => "Enables logging for extra debug-level messages",
191        }
192    }
193}
194
195impl FromStr for LogLevel {
196    type Err = String;
197
198    fn from_str(s: &str) -> Result<Self, Self::Err> {
199        match s.to_lowercase().as_str() {
200            "fatal" => Ok(Self::Fatal),
201            "error" => Ok(Self::Error),
202            "warn" => Ok(Self::Warn),
203            "notice" => Ok(Self::Notice),
204            "verbose" => Ok(Self::Verbose),
205            "debug" => Ok(Self::Debug),
206            "trace" => Ok(Self::Trace),
207            "extra" => Ok(Self::Extra),
208            _ => Err(format!("Invalid log level: {s}")),
209        }
210    }
211}