reth_db/static_file/
mod.rs

1//! reth's static file database table import and access
2
3use std::{
4    collections::{hash_map::Entry, HashMap},
5    path::Path,
6};
7
8mod cursor;
9pub use cursor::StaticFileCursor;
10
11mod mask;
12pub use mask::*;
13use reth_nippy_jar::{NippyJar, NippyJarError};
14use reth_primitives::{
15    static_file::{SegmentHeader, SegmentRangeInclusive},
16    StaticFileSegment,
17};
18
19mod masks;
20pub use masks::*;
21
22/// Alias type for a map of [`StaticFileSegment`] and sorted lists of existing static file ranges.
23type SortedStaticFiles =
24    HashMap<StaticFileSegment, Vec<(SegmentRangeInclusive, Option<SegmentRangeInclusive>)>>;
25
26/// Given the `static_files` directory path, it returns a list over the existing `static_files`
27/// organized by [`StaticFileSegment`]. Each segment has a sorted list of block ranges and
28/// transaction ranges as presented in the file configuration.
29pub fn iter_static_files(path: impl AsRef<Path>) -> Result<SortedStaticFiles, NippyJarError> {
30    let path = path.as_ref();
31    if !path.exists() {
32        reth_fs_util::create_dir_all(path).map_err(|err| NippyJarError::Custom(err.to_string()))?;
33    }
34
35    let mut static_files = SortedStaticFiles::default();
36    let entries = reth_fs_util::read_dir(path)
37        .map_err(|err| NippyJarError::Custom(err.to_string()))?
38        .filter_map(Result::ok)
39        .collect::<Vec<_>>();
40
41    for entry in entries {
42        if entry.metadata().is_ok_and(|metadata| metadata.is_file()) {
43            if let Some((segment, _)) =
44                StaticFileSegment::parse_filename(&entry.file_name().to_string_lossy())
45            {
46                let jar = NippyJar::<SegmentHeader>::load(&entry.path())?;
47
48                let (block_range, tx_range) = (
49                    jar.user_header().block_range().copied(),
50                    jar.user_header().tx_range().copied(),
51                );
52
53                if let Some(block_range) = block_range {
54                    match static_files.entry(segment) {
55                        Entry::Occupied(mut entry) => {
56                            entry.get_mut().push((block_range, tx_range));
57                        }
58                        Entry::Vacant(entry) => {
59                            entry.insert(vec![(block_range, tx_range)]);
60                        }
61                    }
62                }
63            }
64        }
65    }
66
67    for range_list in static_files.values_mut() {
68        // Sort by block end range.
69        range_list.sort_by(|a, b| a.0.end().cmp(&b.0.end()));
70    }
71
72    Ok(static_files)
73}