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