Skip to main content

reth_db/static_file/
cursor.rs

1use super::mask::{ColumnSelectorOne, ColumnSelectorThree, ColumnSelectorTwo};
2use alloy_primitives::B256;
3use derive_more::{Deref, DerefMut};
4use reth_db_api::table::Decompress;
5use reth_nippy_jar::{DataReader, NippyJar, NippyJarCursor, RefRow};
6use reth_static_file_types::SegmentHeader;
7use reth_storage_errors::provider::{ProviderError, ProviderResult};
8use std::sync::Arc;
9
10/// Cursor of a static file segment.
11#[derive(Debug, Deref, DerefMut)]
12pub struct StaticFileCursor<'a>(NippyJarCursor<'a, SegmentHeader>);
13
14/// Type alias for column results with optional values.
15type ColumnResult<T> = ProviderResult<Option<T>>;
16
17impl<'a> StaticFileCursor<'a> {
18    /// Returns a new [`StaticFileCursor`].
19    pub fn new(jar: &'a NippyJar<SegmentHeader>, reader: Arc<DataReader>) -> ProviderResult<Self> {
20        Ok(Self(NippyJarCursor::with_reader(jar, reader).map_err(ProviderError::other)?))
21    }
22
23    /// Returns the current `BlockNumber` or `TxNumber` of the cursor depending on the kind of
24    /// static file segment.
25    pub fn number(&self) -> Option<u64> {
26        self.jar().user_header().start().map(|start| self.row_index() + start)
27    }
28
29    /// Gets a row of values.
30    ///
31    /// Returns `None` if the requested row is absent. Read and decompression failures are returned
32    /// as errors.
33    pub fn get(
34        &mut self,
35        key_or_num: KeyOrNumber<'_>,
36        mask: usize,
37    ) -> ProviderResult<Option<RefRow<'_>>> {
38        if self.jar().rows() == 0 {
39            return Ok(None)
40        }
41
42        match key_or_num {
43            KeyOrNumber::Key(_) => unimplemented!(),
44            KeyOrNumber::Number(n) => match self.jar().user_header().start() {
45                Some(offset) => {
46                    if offset > n {
47                        return Ok(None)
48                    }
49                    self.row_by_number_with_cols((n - offset) as usize, mask)
50                }
51                None => Ok(None),
52            },
53        }
54        .map_err(ProviderError::other)
55    }
56
57    /// Gets one column value from a row.
58    pub fn get_one<M: ColumnSelectorOne>(
59        &mut self,
60        key_or_num: KeyOrNumber<'_>,
61    ) -> ColumnResult<M::FIRST> {
62        let row = self.get(key_or_num, M::MASK)?;
63
64        match row {
65            Some(row) => Ok(Some(M::FIRST::decompress(row[0])?)),
66            None => Ok(None),
67        }
68    }
69
70    /// Gets two column values from a row.
71    pub fn get_two<M: ColumnSelectorTwo>(
72        &mut self,
73        key_or_num: KeyOrNumber<'_>,
74    ) -> ColumnResult<(M::FIRST, M::SECOND)> {
75        let row = self.get(key_or_num, M::MASK)?;
76
77        match row {
78            Some(row) => Ok(Some((M::FIRST::decompress(row[0])?, M::SECOND::decompress(row[1])?))),
79            None => Ok(None),
80        }
81    }
82
83    /// Gets three column values from a row.
84    pub fn get_three<M: ColumnSelectorThree>(
85        &mut self,
86        key_or_num: KeyOrNumber<'_>,
87    ) -> ColumnResult<(M::FIRST, M::SECOND, M::THIRD)> {
88        let row = self.get(key_or_num, M::MASK)?;
89
90        match row {
91            Some(row) => Ok(Some((
92                M::FIRST::decompress(row[0])?,
93                M::SECOND::decompress(row[1])?,
94                M::THIRD::decompress(row[2])?,
95            ))),
96            None => Ok(None),
97        }
98    }
99}
100
101/// Either a key _or_ a block/tx number
102#[derive(Debug)]
103pub enum KeyOrNumber<'a> {
104    /// A slice used as a key. Usually a block/tx hash
105    Key(&'a [u8]),
106    /// A block/tx number
107    Number(u64),
108}
109
110impl<'a> From<&'a B256> for KeyOrNumber<'a> {
111    fn from(value: &'a B256) -> Self {
112        KeyOrNumber::Key(value.as_slice())
113    }
114}
115
116impl From<u64> for KeyOrNumber<'_> {
117    fn from(value: u64) -> Self {
118        KeyOrNumber::Number(value)
119    }
120}