mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(interfaces): database write error details (#4190)
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
/// Database error type. They are using u32 to represent error code.
|
||||
/// Database error type. It uses i32 to represent an error code.
|
||||
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
|
||||
pub enum DatabaseError {
|
||||
/// Failed to open database.
|
||||
@ -7,13 +7,22 @@ pub enum DatabaseError {
|
||||
/// Failed to create a table in database.
|
||||
#[error("Table Creating error code: {0:?}")]
|
||||
TableCreation(i32),
|
||||
/// Failed to insert a value into a table.
|
||||
#[error("Database write error code: {0:?}")]
|
||||
Write(i32),
|
||||
/// Failed to get a value into a table.
|
||||
/// Failed to write a value into a table.
|
||||
#[error("Database write operation \"{operation:?}\" for key \"{key:?}\" in table \"{table_name}\" ended with error code: {code:?}")]
|
||||
Write {
|
||||
/// Database error code
|
||||
code: i32,
|
||||
/// Database write operation type
|
||||
operation: DatabaseWriteOperation,
|
||||
/// Table name
|
||||
table_name: &'static str,
|
||||
/// Write key
|
||||
key: Box<[u8]>,
|
||||
},
|
||||
/// Failed to read a value from a table.
|
||||
#[error("Database read error code: {0:?}")]
|
||||
Read(i32),
|
||||
/// Failed to delete a `(key, value)` pair into a table.
|
||||
/// Failed to delete a `(key, value)` pair from a table.
|
||||
#[error("Database delete error code: {0:?}")]
|
||||
Delete(i32),
|
||||
/// Failed to commit transaction changes into the database.
|
||||
@ -36,6 +45,17 @@ pub enum DatabaseError {
|
||||
LogLevelUnavailable(LogLevel),
|
||||
}
|
||||
|
||||
/// Database write operation type
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum DatabaseWriteOperation {
|
||||
CursorAppend,
|
||||
CursorUpsert,
|
||||
CursorInsert,
|
||||
CursorAppendDup,
|
||||
Put,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
||||
/// Database log level.
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
//! Cursor wrapper for libmdbx-sys.
|
||||
|
||||
use reth_interfaces::db::DatabaseWriteOperation;
|
||||
use std::{borrow::Cow, collections::Bound, marker::PhantomData, ops::RangeBounds};
|
||||
|
||||
use crate::{
|
||||
@ -230,24 +231,42 @@ impl<'tx, T: Table> DbCursorRW<'tx, T> for Cursor<'tx, RW, T> {
|
||||
/// to properly upsert, you'll need to `seek_exact` & `delete_current` if the key+subkey was
|
||||
/// found, before calling `upsert`.
|
||||
fn upsert(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||
let key = key.encode();
|
||||
// Default `WriteFlags` is UPSERT
|
||||
self.inner
|
||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::UPSERT)
|
||||
.map_err(|e| DatabaseError::Write(e.into()))
|
||||
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::UPSERT).map_err(
|
||||
|e| DatabaseError::Write {
|
||||
code: e.into(),
|
||||
operation: DatabaseWriteOperation::CursorUpsert,
|
||||
table_name: T::NAME,
|
||||
key: Box::from(key.as_ref()),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn insert(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||
let key = key.encode();
|
||||
self.inner
|
||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::NO_OVERWRITE)
|
||||
.map_err(|e| DatabaseError::Write(e.into()))
|
||||
.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::NO_OVERWRITE)
|
||||
.map_err(|e| DatabaseError::Write {
|
||||
code: e.into(),
|
||||
operation: DatabaseWriteOperation::CursorInsert,
|
||||
table_name: T::NAME,
|
||||
key: Box::from(key.as_ref()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Appends the data to the end of the table. Consequently, the append operation
|
||||
/// will fail if the inserted key is less than the last table key
|
||||
fn append(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||
self.inner
|
||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND)
|
||||
.map_err(|e| DatabaseError::Write(e.into()))
|
||||
let key = key.encode();
|
||||
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND).map_err(
|
||||
|e| DatabaseError::Write {
|
||||
code: e.into(),
|
||||
operation: DatabaseWriteOperation::CursorAppend,
|
||||
table_name: T::NAME,
|
||||
key: Box::from(key.as_ref()),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn delete_current(&mut self) -> Result<(), DatabaseError> {
|
||||
@ -261,8 +280,14 @@ impl<'tx, T: DupSort> DbDupCursorRW<'tx, T> for Cursor<'tx, RW, T> {
|
||||
}
|
||||
|
||||
fn append_dup(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||
self.inner
|
||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND_DUP)
|
||||
.map_err(|e| DatabaseError::Write(e.into()))
|
||||
let key = key.encode();
|
||||
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND_DUP).map_err(
|
||||
|e| DatabaseError::Write {
|
||||
code: e.into(),
|
||||
operation: DatabaseWriteOperation::CursorAppendDup,
|
||||
table_name: T::NAME,
|
||||
key: Box::from(key.as_ref()),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,6 +158,7 @@ impl<E: EnvironmentKind> Deref for Env<E> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
abstraction::table::{Encode, Table},
|
||||
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW, ReverseWalker, Walker},
|
||||
database::Database,
|
||||
models::{AccountBeforeTx, ShardedKey},
|
||||
@ -166,6 +167,7 @@ mod tests {
|
||||
transaction::{DbTx, DbTxMut},
|
||||
AccountChangeSet, DatabaseError,
|
||||
};
|
||||
use reth_interfaces::db::DatabaseWriteOperation;
|
||||
use reth_libmdbx::{NoWriteMap, WriteMap};
|
||||
use reth_primitives::{Account, Address, Header, IntegerList, StorageEntry, H160, H256, U256};
|
||||
use std::{path::Path, str::FromStr, sync::Arc};
|
||||
@ -525,7 +527,15 @@ mod tests {
|
||||
assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero()))));
|
||||
|
||||
// INSERT (failure)
|
||||
assert_eq!(cursor.insert(key_to_insert, H256::zero()), Err(DatabaseError::Write(-30799)));
|
||||
assert_eq!(
|
||||
cursor.insert(key_to_insert, H256::zero()),
|
||||
Err(DatabaseError::Write {
|
||||
code: -30799,
|
||||
operation: DatabaseWriteOperation::CursorInsert,
|
||||
table_name: CanonicalHeaders::NAME,
|
||||
key: Box::from(key_to_insert.encode().as_ref())
|
||||
})
|
||||
);
|
||||
assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero()))));
|
||||
|
||||
tx.commit().expect(ERROR_COMMIT);
|
||||
@ -660,7 +670,15 @@ mod tests {
|
||||
let key_to_append = 2;
|
||||
let tx = db.tx_mut().expect(ERROR_INIT_TX);
|
||||
let mut cursor = tx.cursor_write::<CanonicalHeaders>().unwrap();
|
||||
assert_eq!(cursor.append(key_to_append, H256::zero()), Err(DatabaseError::Write(-30418)));
|
||||
assert_eq!(
|
||||
cursor.append(key_to_append, H256::zero()),
|
||||
Err(DatabaseError::Write {
|
||||
code: -30418,
|
||||
operation: DatabaseWriteOperation::CursorAppend,
|
||||
table_name: CanonicalHeaders::NAME,
|
||||
key: Box::from(key_to_append.encode().as_ref())
|
||||
})
|
||||
);
|
||||
assert_eq!(cursor.current(), Ok(Some((5, H256::zero())))); // the end of table
|
||||
tx.commit().expect(ERROR_COMMIT);
|
||||
|
||||
@ -735,14 +753,24 @@ mod tests {
|
||||
transition_id,
|
||||
AccountBeforeTx { address: Address::from_low_u64_be(subkey_to_append), info: None }
|
||||
),
|
||||
Err(DatabaseError::Write(-30418))
|
||||
Err(DatabaseError::Write {
|
||||
code: -30418,
|
||||
operation: DatabaseWriteOperation::CursorAppendDup,
|
||||
table_name: AccountChangeSet::NAME,
|
||||
key: Box::from(transition_id.encode().as_ref())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.append(
|
||||
transition_id - 1,
|
||||
AccountBeforeTx { address: Address::from_low_u64_be(subkey_to_append), info: None }
|
||||
),
|
||||
Err(DatabaseError::Write(-30418))
|
||||
Err(DatabaseError::Write {
|
||||
code: -30418,
|
||||
operation: DatabaseWriteOperation::CursorAppend,
|
||||
table_name: AccountChangeSet::NAME,
|
||||
key: Box::from((transition_id - 1).encode().as_ref())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.append(
|
||||
|
||||
@ -8,6 +8,7 @@ use crate::{
|
||||
DatabaseError,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use reth_interfaces::db::DatabaseWriteOperation;
|
||||
use reth_libmdbx::{ffi::DBI, EnvironmentKind, Transaction, TransactionKind, WriteFlags, RW};
|
||||
use reth_metrics::metrics::{self, histogram};
|
||||
use std::{marker::PhantomData, str::FromStr, sync::Arc, time::Instant};
|
||||
@ -124,9 +125,15 @@ impl<'tx, K: TransactionKind, E: EnvironmentKind> DbTx<'tx> for Tx<'tx, K, E> {
|
||||
|
||||
impl<E: EnvironmentKind> DbTxMut<'_> for Tx<'_, RW, E> {
|
||||
fn put<T: Table>(&self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||
let key = key.encode();
|
||||
self.inner
|
||||
.put(self.get_dbi::<T>()?, &key.encode(), &value.compress(), WriteFlags::UPSERT)
|
||||
.map_err(|e| DatabaseError::Write(e.into()))
|
||||
.put(self.get_dbi::<T>()?, key.as_ref(), &value.compress(), WriteFlags::UPSERT)
|
||||
.map_err(|e| DatabaseError::Write {
|
||||
code: e.into(),
|
||||
operation: DatabaseWriteOperation::Put,
|
||||
table_name: T::NAME,
|
||||
key: Box::from(key.as_ref()),
|
||||
})
|
||||
}
|
||||
|
||||
fn delete<T: Table>(
|
||||
|
||||
@ -84,7 +84,7 @@ pub mod mdbx {
|
||||
}
|
||||
|
||||
pub use abstraction::*;
|
||||
pub use reth_interfaces::db::DatabaseError;
|
||||
pub use reth_interfaces::db::{DatabaseError, DatabaseWriteOperation};
|
||||
pub use tables::*;
|
||||
pub use utils::is_database_empty;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user