refactor(provider): extract heal_segment for NippyJar consistency (#20508)

This commit is contained in:
YK
2025-12-22 22:01:12 +08:00
committed by GitHub
parent f3aea8dac0
commit 535d97f39e

View File

@@ -1084,31 +1084,13 @@ impl<N: NodePrimitives> StaticFileProvider<N> {
}
}
let initial_highest_block = self.get_highest_static_file_block(segment);
debug!(target: "reth::providers::static_file", ?segment, ?initial_highest_block, "Initial highest block for segment");
// File consistency is broken if:
//
// * appending data was interrupted before a config commit, then data file will be
// truncated according to the config.
//
// * pruning data was interrupted before a config commit, then we have deleted data that
// we are expected to still have. We need to check the Database and unwind everything
// accordingly.
if self.access.is_read_only() {
debug!(target: "reth::providers::static_file", ?segment, "Checking segment consistency (read-only)");
self.check_segment_consistency(segment)?;
} else {
debug!(target: "reth::providers::static_file", ?segment, "Fetching latest writer which might heal any potential inconsistency");
// Fetching the writer will attempt to heal any file level inconsistency.
self.latest_writer(segment)?;
}
// Heal file-level inconsistencies and get before/after highest block
let (initial_highest_block, mut highest_block) = self.maybe_heal_segment(segment)?;
// Only applies to block-based static files. (Headers)
//
// The updated `highest_block` may have decreased if we healed from a pruning
// interruption.
let mut highest_block = self.get_highest_static_file_block(segment);
if initial_highest_block != highest_block {
info!(
target: "reth::providers::static_file",
@@ -1223,6 +1205,47 @@ impl<N: NodePrimitives> StaticFileProvider<N> {
Ok(())
}
/// Attempts to heal file-level (`NippyJar`) inconsistencies for a single static file segment.
///
/// Returns the highest block before and after healing, which can be used to detect
/// if healing from a pruning interruption decreased the highest block.
///
/// File consistency is broken if:
///
/// * appending data was interrupted before a config commit, then data file will be truncated
/// according to the config.
///
/// * pruning data was interrupted before a config commit, then we have deleted data that we are
/// expected to still have. We need to check the Database and unwind everything accordingly.
///
/// **Note:** In read-only mode, this will return an error if a consistency issue is detected,
/// since healing requires write access.
fn maybe_heal_segment(
&self,
segment: StaticFileSegment,
) -> ProviderResult<(Option<BlockNumber>, Option<BlockNumber>)> {
let initial_highest_block = self.get_highest_static_file_block(segment);
debug!(target: "reth::providers::static_file", ?segment, ?initial_highest_block, "Initial highest block for segment");
if self.access.is_read_only() {
// Read-only mode: cannot modify files, so just validate consistency and error if
// broken.
debug!(target: "reth::providers::static_file", ?segment, "Checking segment consistency (read-only)");
self.check_segment_consistency(segment)?;
} else {
// Writable mode: fetching the writer will automatically heal any file-level
// inconsistency by truncating data to match the last committed config.
debug!(target: "reth::providers::static_file", ?segment, "Fetching latest writer which might heal any potential inconsistency");
self.latest_writer(segment)?;
}
// The updated `highest_block` may have decreased if we healed from a pruning
// interruption.
let highest_block = self.get_highest_static_file_block(segment);
Ok((initial_highest_block, highest_block))
}
/// Check invariants for each corresponding table and static file segment:
///
/// * the corresponding database table should overlap or have continuity in their keys