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};
14
15mod masks;
16pub use masks::*;
17use reth_static_file_types::{SegmentHeader, SegmentRangeInclusive, StaticFileSegment};
18
19/// Alias type for a map of [`StaticFileSegment`] and sorted lists of existing static file ranges.
20type SortedStaticFiles =
21    HashMap<StaticFileSegment, Vec<(SegmentRangeInclusive, Option<SegmentRangeInclusive>)>>;
22
23/// Given the `static_files` directory path, it returns a list over the existing `static_files`
24/// organized by [`StaticFileSegment`]. Each segment has a sorted list of block ranges and
25/// transaction ranges as presented in the file configuration.
26pub fn iter_static_files(path: &Path) -> Result<SortedStaticFiles, NippyJarError> {
27    if !path.exists() {
28        reth_fs_util::create_dir_all(path).map_err(|err| NippyJarError::Custom(err.to_string()))?;
29    }
30
31    let mut static_files = SortedStaticFiles::default();
32    let entries = reth_fs_util::read_dir(path)
33        .map_err(|err| NippyJarError::Custom(err.to_string()))?
34        .filter_map(Result::ok);
35    for entry in entries {
36        if entry.metadata().is_ok_and(|metadata| metadata.is_file()) {
37            if let Some((segment, _)) =
38                StaticFileSegment::parse_filename(&entry.file_name().to_string_lossy())
39            {
40                let jar = NippyJar::<SegmentHeader>::load(&entry.path())?;
41
42                let (block_range, tx_range) = (
43                    jar.user_header().block_range().copied(),
44                    jar.user_header().tx_range().copied(),
45                );
46
47                if let Some(block_range) = block_range {
48                    match static_files.entry(segment) {
49                        Entry::Occupied(mut entry) => {
50                            entry.get_mut().push((block_range, tx_range));
51                        }
52                        Entry::Vacant(entry) => {
53                            entry.insert(vec![(block_range, tx_range)]);
54                        }
55                    }
56                }
57            }
58        }
59    }
60
61    for range_list in static_files.values_mut() {
62        // Sort by block end range.
63        range_list.sort_by_key(|(r, _)| r.end());
64    }
65
66    Ok(static_files)
67}