diff --git a/crates/blockchain/src/store.rs b/crates/blockchain/src/store.rs index 8ec2bc64..8a439263 100644 --- a/crates/blockchain/src/store.rs +++ b/crates/blockchain/src/store.rs @@ -569,7 +569,7 @@ fn on_block_core( signed_block: SignedBlock, verify: bool, ) -> Result<(), StoreError> { - let _timing = metrics::time_fork_choice_block_processing(); + let timing = metrics::time_fork_choice_block_processing(); let block_start = std::time::Instant::now(); let block = &signed_block.message; @@ -581,6 +581,7 @@ fn on_block_core( .has_state(&block_root) .expect("DB read should succeed") { + timing.discard(); return Ok(()); } diff --git a/crates/common/metrics/src/timing.rs b/crates/common/metrics/src/timing.rs index a3baa941..964716af 100644 --- a/crates/common/metrics/src/timing.rs +++ b/crates/common/metrics/src/timing.rs @@ -5,6 +5,11 @@ use std::time::Instant; use crate::Histogram; /// A guard that records elapsed time to a histogram when dropped. +/// +/// The measurement can be cancelled with [`TimingGuard::discard`], which +/// consumes the guard without recording a sample, for a timed path that turns +/// out to be a no-op whose duration would only skew the histogram (e.g. an +/// idempotent early return). pub struct TimingGuard { histogram: &'static Histogram, start: Instant, @@ -17,6 +22,22 @@ impl TimingGuard { start: Instant::now(), } } + + /// Consume the guard without recording a sample. + /// + /// Use when the timed work should not contribute a sample, such as a + /// duplicate/idempotent request that returns early: the elapsed time is + /// real but recording it would skew the histogram toward near-zero. + /// + /// `TimingGuard` implements [`Drop`], so its fields cannot be moved out to + /// destructure it directly. Wrapping in [`std::mem::ManuallyDrop`] inhibits + /// the recording `Drop`; the fields are `Copy`, so they are then read out + /// and their copies dropped here, leaving nothing to record. + pub fn discard(self) { + let guard = std::mem::ManuallyDrop::new(self); + let _histogram = guard.histogram; + let _start = guard.start; + } } impl Drop for TimingGuard {