mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(storage, blockchain-tree): disable backtrace on long read tx when it's safe (#6177)
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -5760,6 +5760,7 @@ dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-rlp",
|
||||
"aquamarine",
|
||||
"assert_matches",
|
||||
"backon",
|
||||
"clap",
|
||||
"comfy-table",
|
||||
@ -5774,6 +5775,7 @@ dependencies = [
|
||||
"itertools 0.12.0",
|
||||
"jemalloc-ctl",
|
||||
"jemallocator",
|
||||
"jsonrpsee",
|
||||
"metrics",
|
||||
"metrics-exporter-prometheus",
|
||||
"metrics-process",
|
||||
|
||||
@ -1174,7 +1174,13 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
|
||||
}
|
||||
None => {
|
||||
debug!(target: "blockchain_tree", blocks = ?block_hash_numbers, "Recomputing state root for insert");
|
||||
let provider = self.externals.provider_factory.provider()?;
|
||||
let provider = self
|
||||
.externals
|
||||
.provider_factory
|
||||
.provider()?
|
||||
// State root calculation can take a while, and we're sure no write transaction
|
||||
// will be open in parallel. See https://github.com/paradigmxyz/reth/issues/6168.
|
||||
.disable_backtrace_on_long_read_transaction();
|
||||
let (state_root, trie_updates) = hashed_state
|
||||
.state_root_with_updates(provider.tx_ref())
|
||||
.map_err(Into::<DatabaseError>::into)?;
|
||||
|
||||
@ -66,6 +66,8 @@ impl DbTx for TxMock {
|
||||
fn entries<T: Table>(&self) -> Result<usize, DatabaseError> {
|
||||
Ok(self._table.len())
|
||||
}
|
||||
|
||||
fn disable_backtrace_on_long_read_transaction(&mut self) {}
|
||||
}
|
||||
|
||||
impl DbTxMut for TxMock {
|
||||
|
||||
@ -24,6 +24,8 @@ pub trait DbTx: Send + Sync {
|
||||
fn cursor_dup_read<T: DupSort>(&self) -> Result<Self::DupCursor<T>, DatabaseError>;
|
||||
/// Returns number of entries in the table.
|
||||
fn entries<T: Table>(&self) -> Result<usize, DatabaseError>;
|
||||
/// Disables backtrace recording for this read transaction when it's open for too long.
|
||||
fn disable_backtrace_on_long_read_transaction(&mut self);
|
||||
}
|
||||
|
||||
/// Read write transaction that allows writing to database
|
||||
|
||||
@ -156,6 +156,9 @@ struct MetricsHandler<K: TransactionKind> {
|
||||
/// If `true`, the metric about transaction closing has already been recorded and we don't need
|
||||
/// to do anything on [Drop::drop].
|
||||
close_recorded: bool,
|
||||
/// If `true`, the backtrace of transaction will be recorded and logged.
|
||||
/// See [MetricsHandler::log_backtrace_on_long_read_transaction].
|
||||
record_backtrace: bool,
|
||||
/// If `true`, the backtrace of transaction has already been recorded and logged.
|
||||
/// See [MetricsHandler::log_backtrace_on_long_read_transaction].
|
||||
backtrace_recorded: AtomicBool,
|
||||
@ -168,6 +171,7 @@ impl<K: TransactionKind> MetricsHandler<K> {
|
||||
txn_id,
|
||||
start: Instant::now(),
|
||||
close_recorded: false,
|
||||
record_backtrace: true,
|
||||
backtrace_recorded: AtomicBool::new(false),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
@ -194,13 +198,14 @@ impl<K: TransactionKind> MetricsHandler<K> {
|
||||
}
|
||||
|
||||
/// Logs the backtrace of current call if the duration that the read transaction has been open
|
||||
/// is more than [LONG_TRANSACTION_DURATION].
|
||||
/// is more than [LONG_TRANSACTION_DURATION] and `record_backtrace == true`.
|
||||
/// The backtrace is recorded and logged just once, guaranteed by `backtrace_recorded` atomic.
|
||||
///
|
||||
/// NOTE: Backtrace is recorded using [Backtrace::force_capture], so `RUST_BACKTRACE` env var is
|
||||
/// not needed.
|
||||
fn log_backtrace_on_long_read_transaction(&self) {
|
||||
if !self.backtrace_recorded.load(Ordering::Relaxed) &&
|
||||
if self.record_backtrace &&
|
||||
!self.backtrace_recorded.load(Ordering::Relaxed) &&
|
||||
self.transaction_mode().is_read_only()
|
||||
{
|
||||
let open_duration = self.start.elapsed();
|
||||
@ -283,6 +288,13 @@ impl<K: TransactionKind> DbTx for Tx<K> {
|
||||
.map_err(|e| DatabaseError::Stats(e.into()))?
|
||||
.entries())
|
||||
}
|
||||
|
||||
/// Disables backtrace recording for this read transaction when it's open for too long.
|
||||
fn disable_backtrace_on_long_read_transaction(&mut self) {
|
||||
if let Some(metrics_handler) = self.metrics_handler.as_mut() {
|
||||
metrics_handler.record_backtrace = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DbTxMut for Tx<RW> {
|
||||
|
||||
@ -246,6 +246,17 @@ impl<TX: DbTx> DatabaseProvider<TX> {
|
||||
.collect::<Result<Vec<_>, DatabaseError>>()
|
||||
}
|
||||
|
||||
/// Disables backtrace recording for the underlying read database transaction when it's open for
|
||||
/// too long.
|
||||
///
|
||||
/// CAUTION: In most of the cases, you want to keep backtraces on long read transactions
|
||||
/// enabled. Use this only if you're sure that no write transaction is open in parallel, meaning
|
||||
/// that Reth as a node is offline and not progressing.
|
||||
pub fn disable_backtrace_on_long_read_transaction(mut self) -> Self {
|
||||
self.tx.disable_backtrace_on_long_read_transaction();
|
||||
self
|
||||
}
|
||||
|
||||
/// Gets data within a specified range, potentially spanning different snapshots and database.
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
Reference in New Issue
Block a user