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)]
|
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
|
||||||
pub enum DatabaseError {
|
pub enum DatabaseError {
|
||||||
/// Failed to open database.
|
/// Failed to open database.
|
||||||
@ -7,13 +7,22 @@ pub enum DatabaseError {
|
|||||||
/// Failed to create a table in database.
|
/// Failed to create a table in database.
|
||||||
#[error("Table Creating error code: {0:?}")]
|
#[error("Table Creating error code: {0:?}")]
|
||||||
TableCreation(i32),
|
TableCreation(i32),
|
||||||
/// Failed to insert a value into a table.
|
/// Failed to write a value into a table.
|
||||||
#[error("Database write error code: {0:?}")]
|
#[error("Database write operation \"{operation:?}\" for key \"{key:?}\" in table \"{table_name}\" ended with error code: {code:?}")]
|
||||||
Write(i32),
|
Write {
|
||||||
/// Failed to get a value into a table.
|
/// 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:?}")]
|
#[error("Database read error code: {0:?}")]
|
||||||
Read(i32),
|
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:?}")]
|
#[error("Database delete error code: {0:?}")]
|
||||||
Delete(i32),
|
Delete(i32),
|
||||||
/// Failed to commit transaction changes into the database.
|
/// Failed to commit transaction changes into the database.
|
||||||
@ -36,6 +45,17 @@ pub enum DatabaseError {
|
|||||||
LogLevelUnavailable(LogLevel),
|
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)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
||||||
/// Database log level.
|
/// Database log level.
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
//! Cursor wrapper for libmdbx-sys.
|
//! Cursor wrapper for libmdbx-sys.
|
||||||
|
|
||||||
|
use reth_interfaces::db::DatabaseWriteOperation;
|
||||||
use std::{borrow::Cow, collections::Bound, marker::PhantomData, ops::RangeBounds};
|
use std::{borrow::Cow, collections::Bound, marker::PhantomData, ops::RangeBounds};
|
||||||
|
|
||||||
use crate::{
|
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
|
/// to properly upsert, you'll need to `seek_exact` & `delete_current` if the key+subkey was
|
||||||
/// found, before calling `upsert`.
|
/// found, before calling `upsert`.
|
||||||
fn upsert(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
fn upsert(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||||
|
let key = key.encode();
|
||||||
// Default `WriteFlags` is UPSERT
|
// Default `WriteFlags` is UPSERT
|
||||||
self.inner
|
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::UPSERT).map_err(
|
||||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::UPSERT)
|
|e| DatabaseError::Write {
|
||||||
.map_err(|e| DatabaseError::Write(e.into()))
|
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> {
|
fn insert(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||||
|
let key = key.encode();
|
||||||
self.inner
|
self.inner
|
||||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::NO_OVERWRITE)
|
.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::NO_OVERWRITE)
|
||||||
.map_err(|e| DatabaseError::Write(e.into()))
|
.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
|
/// 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
|
/// 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> {
|
fn append(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||||
self.inner
|
let key = key.encode();
|
||||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND)
|
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND).map_err(
|
||||||
.map_err(|e| DatabaseError::Write(e.into()))
|
|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> {
|
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> {
|
fn append_dup(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||||
self.inner
|
let key = key.encode();
|
||||||
.put(key.encode().as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND_DUP)
|
self.inner.put(key.as_ref(), compress_or_ref!(self, value), WriteFlags::APPEND_DUP).map_err(
|
||||||
.map_err(|e| DatabaseError::Write(e.into()))
|
|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 {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
abstraction::table::{Encode, Table},
|
||||||
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW, ReverseWalker, Walker},
|
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW, ReverseWalker, Walker},
|
||||||
database::Database,
|
database::Database,
|
||||||
models::{AccountBeforeTx, ShardedKey},
|
models::{AccountBeforeTx, ShardedKey},
|
||||||
@ -166,6 +167,7 @@ mod tests {
|
|||||||
transaction::{DbTx, DbTxMut},
|
transaction::{DbTx, DbTxMut},
|
||||||
AccountChangeSet, DatabaseError,
|
AccountChangeSet, DatabaseError,
|
||||||
};
|
};
|
||||||
|
use reth_interfaces::db::DatabaseWriteOperation;
|
||||||
use reth_libmdbx::{NoWriteMap, WriteMap};
|
use reth_libmdbx::{NoWriteMap, WriteMap};
|
||||||
use reth_primitives::{Account, Address, Header, IntegerList, StorageEntry, H160, H256, U256};
|
use reth_primitives::{Account, Address, Header, IntegerList, StorageEntry, H160, H256, U256};
|
||||||
use std::{path::Path, str::FromStr, sync::Arc};
|
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()))));
|
assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero()))));
|
||||||
|
|
||||||
// INSERT (failure)
|
// 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()))));
|
assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero()))));
|
||||||
|
|
||||||
tx.commit().expect(ERROR_COMMIT);
|
tx.commit().expect(ERROR_COMMIT);
|
||||||
@ -660,7 +670,15 @@ mod tests {
|
|||||||
let key_to_append = 2;
|
let key_to_append = 2;
|
||||||
let tx = db.tx_mut().expect(ERROR_INIT_TX);
|
let tx = db.tx_mut().expect(ERROR_INIT_TX);
|
||||||
let mut cursor = tx.cursor_write::<CanonicalHeaders>().unwrap();
|
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
|
assert_eq!(cursor.current(), Ok(Some((5, H256::zero())))); // the end of table
|
||||||
tx.commit().expect(ERROR_COMMIT);
|
tx.commit().expect(ERROR_COMMIT);
|
||||||
|
|
||||||
@ -735,14 +753,24 @@ mod tests {
|
|||||||
transition_id,
|
transition_id,
|
||||||
AccountBeforeTx { address: Address::from_low_u64_be(subkey_to_append), info: None }
|
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!(
|
assert_eq!(
|
||||||
cursor.append(
|
cursor.append(
|
||||||
transition_id - 1,
|
transition_id - 1,
|
||||||
AccountBeforeTx { address: Address::from_low_u64_be(subkey_to_append), info: None }
|
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!(
|
assert_eq!(
|
||||||
cursor.append(
|
cursor.append(
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use crate::{
|
|||||||
DatabaseError,
|
DatabaseError,
|
||||||
};
|
};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use reth_interfaces::db::DatabaseWriteOperation;
|
||||||
use reth_libmdbx::{ffi::DBI, EnvironmentKind, Transaction, TransactionKind, WriteFlags, RW};
|
use reth_libmdbx::{ffi::DBI, EnvironmentKind, Transaction, TransactionKind, WriteFlags, RW};
|
||||||
use reth_metrics::metrics::{self, histogram};
|
use reth_metrics::metrics::{self, histogram};
|
||||||
use std::{marker::PhantomData, str::FromStr, sync::Arc, time::Instant};
|
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> {
|
impl<E: EnvironmentKind> DbTxMut<'_> for Tx<'_, RW, E> {
|
||||||
fn put<T: Table>(&self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
fn put<T: Table>(&self, key: T::Key, value: T::Value) -> Result<(), DatabaseError> {
|
||||||
|
let key = key.encode();
|
||||||
self.inner
|
self.inner
|
||||||
.put(self.get_dbi::<T>()?, &key.encode(), &value.compress(), WriteFlags::UPSERT)
|
.put(self.get_dbi::<T>()?, key.as_ref(), &value.compress(), WriteFlags::UPSERT)
|
||||||
.map_err(|e| DatabaseError::Write(e.into()))
|
.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>(
|
fn delete<T: Table>(
|
||||||
|
|||||||
@ -84,7 +84,7 @@ pub mod mdbx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub use abstraction::*;
|
pub use abstraction::*;
|
||||||
pub use reth_interfaces::db::DatabaseError;
|
pub use reth_interfaces::db::{DatabaseError, DatabaseWriteOperation};
|
||||||
pub use tables::*;
|
pub use tables::*;
|
||||||
pub use utils::is_database_empty;
|
pub use utils::is_database_empty;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user