Skip to main content

reth_engine_tree/tree/
persistence_state.rs

1//! Persistence state management for background database operations.
2//!
3//! This module manages the state of background tasks that persist cached data
4//! to the database. The persistence system works asynchronously to avoid blocking
5//! block execution while ensuring data durability.
6//!
7//! ## Background Persistence
8//!
9//! The execution engine maintains an in-memory cache of state changes that need
10//! to be persisted to disk. Rather than writing synchronously (which would slow
11//! down block processing), persistence happens in background tasks.
12//!
13//! ## Persistence Actions
14//!
15//! - **Saving Blocks**: Persist newly executed blocks and their state changes
16//! - **Removing Blocks**: Remove invalid blocks during chain reorganizations
17//!
18//! ## Coordination
19//!
20//! The [`PersistenceState`] tracks ongoing persistence operations and coordinates
21//! between the main execution thread and background persistence workers.
22
23use crate::persistence::PersistenceResult;
24use alloy_eips::BlockNumHash;
25use crossbeam_channel::Receiver as CrossbeamReceiver;
26use reth_primitives_traits::FastInstant as Instant;
27use tracing::trace;
28
29/// The state of the persistence task.
30#[derive(Debug)]
31pub struct PersistenceState {
32    /// Hash and number of the highest block whose non-state/trie outputs are persisted.
33    ///
34    /// This tracks the highest canonical block with durable block/static-file/plain-state data.
35    pub(crate) last_persisted_block: BlockNumHash,
36    /// Hash and number of the highest block whose state/trie outputs were processed for
37    /// persistence.
38    pub(crate) last_state_trie_persisted_block: BlockNumHash,
39    /// Receiver end of channel where the result of the persistence task will be
40    /// sent when done. A None value means there's no persistence task in progress.
41    pub(crate) rx:
42        Option<(CrossbeamReceiver<PersistenceResult>, Instant, CurrentPersistenceAction)>,
43}
44
45impl PersistenceState {
46    /// Determines if there is a persistence task in progress by checking if the
47    /// receiver is set.
48    pub(crate) const fn in_progress(&self) -> bool {
49        self.rx.is_some()
50    }
51
52    /// Sets the state for a block removal operation.
53    pub(crate) fn start_remove(
54        &mut self,
55        new_tip_num: u64,
56        rx: CrossbeamReceiver<PersistenceResult>,
57    ) {
58        self.rx =
59            Some((rx, Instant::now(), CurrentPersistenceAction::RemovingBlocks { new_tip_num }));
60    }
61
62    /// Sets the state for a block save operation.
63    pub(crate) fn start_save(
64        &mut self,
65        highest: BlockNumHash,
66        rx: CrossbeamReceiver<PersistenceResult>,
67    ) {
68        self.rx = Some((rx, Instant::now(), CurrentPersistenceAction::SavingBlocks { highest }));
69    }
70
71    /// Returns the current persistence action. If there is no persistence task in progress, then
72    /// this returns `None`.
73    #[cfg(test)]
74    pub(crate) fn current_action(&self) -> Option<&CurrentPersistenceAction> {
75        self.rx.as_ref().map(|rx| &rx.2)
76    }
77
78    /// Sets state for a finished persistence task.
79    pub(crate) fn finish(
80        &mut self,
81        last_persisted_block: BlockNumHash,
82        last_state_trie_persisted_block: BlockNumHash,
83    ) {
84        trace!(
85            target: "engine::tree",
86            last_persisted_block = %last_persisted_block.number,
87            last_state_trie_persisted_block = %last_state_trie_persisted_block.number,
88            "updating persistence state"
89        );
90        self.rx = None;
91        self.last_persisted_block = last_persisted_block;
92        self.last_state_trie_persisted_block = last_state_trie_persisted_block;
93    }
94}
95
96/// The currently running persistence action.
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub(crate) enum CurrentPersistenceAction {
99    /// The persistence task is saving blocks.
100    SavingBlocks {
101        /// The highest block being saved.
102        highest: BlockNumHash,
103    },
104    /// The persistence task is removing blocks.
105    RemovingBlocks {
106        /// The tip, above which we are removing blocks.
107        new_tip_num: u64,
108    },
109}