solana_accounts_db/tiered_storage/
readable.rs

1use {
2    crate::{
3        account_info::Offset,
4        account_storage::stored_account_info::{StoredAccountInfo, StoredAccountInfoWithoutData},
5        tiered_storage::{
6            file::TieredReadableFile,
7            footer::{AccountMetaFormat, TieredStorageFooter},
8            hot::HotStorageReader,
9            index::IndexOffset,
10            TieredStorageResult,
11        },
12    },
13    solana_account::AccountSharedData,
14    solana_pubkey::Pubkey,
15    std::path::Path,
16};
17
18/// The reader of a tiered storage instance.
19#[derive(Debug)]
20pub enum TieredStorageReader {
21    Hot(HotStorageReader),
22}
23
24impl TieredStorageReader {
25    /// Creates a reader for the specified tiered storage accounts file.
26    pub fn new_from_path(path: impl AsRef<Path>) -> TieredStorageResult<Self> {
27        let file = TieredReadableFile::new(&path)?;
28        let footer = TieredStorageFooter::new_from_footer_block(&file)?;
29        match footer.account_meta_format {
30            AccountMetaFormat::Hot => Ok(Self::Hot(HotStorageReader::new(file)?)),
31        }
32    }
33
34    /// Returns the size of the underlying storage.
35    pub fn len(&self) -> usize {
36        match self {
37            Self::Hot(hot) => hot.len(),
38        }
39    }
40
41    /// Returns whether the underlying storage is empty.
42    pub fn is_empty(&self) -> bool {
43        match self {
44            Self::Hot(hot) => hot.is_empty(),
45        }
46    }
47
48    pub fn capacity(&self) -> u64 {
49        match self {
50            Self::Hot(hot) => hot.capacity(),
51        }
52    }
53
54    /// Returns the footer of the associated HotAccountsFile.
55    pub fn footer(&self) -> &TieredStorageFooter {
56        match self {
57            Self::Hot(hot) => hot.footer(),
58        }
59    }
60
61    /// Returns the total number of accounts.
62    pub fn num_accounts(&self) -> usize {
63        match self {
64            Self::Hot(hot) => hot.num_accounts(),
65        }
66    }
67
68    /// Returns the account located at the specified index offset.
69    pub fn get_account_shared_data(
70        &self,
71        index_offset: IndexOffset,
72    ) -> TieredStorageResult<Option<AccountSharedData>> {
73        match self {
74            Self::Hot(hot) => hot.get_account_shared_data(index_offset),
75        }
76    }
77
78    /// Calls `callback` with the stored account at `offset`.
79    ///
80    /// Returns `None` if there is no account at `offset`, otherwise returns the result of
81    /// `callback` in `Some`.
82    ///
83    /// This fn does *not* load the account's data, just the data length.  If the data is needed,
84    /// use `get_stored_account_callback()` instead.  However, prefer this fn when possible.
85    pub fn get_stored_account_without_data_callback<Ret>(
86        &self,
87        index_offset: IndexOffset,
88        callback: impl for<'local> FnMut(StoredAccountInfoWithoutData<'local>) -> Ret,
89    ) -> TieredStorageResult<Option<Ret>> {
90        match self {
91            Self::Hot(hot) => hot.get_stored_account_without_data_callback(index_offset, callback),
92        }
93    }
94
95    /// Calls `callback` with the stored account at `offset`.
96    ///
97    /// Returns `None` if there is no account at `offset`, otherwise returns the result of
98    /// `callback` in `Some`.
99    ///
100    /// This fn *does* load the account's data.  If the data is not needed,
101    /// use `get_stored_account_without_data_callback()` instead.
102    pub fn get_stored_account_callback<Ret>(
103        &self,
104        index_offset: IndexOffset,
105        callback: impl for<'local> FnMut(StoredAccountInfo<'local>) -> Ret,
106    ) -> TieredStorageResult<Option<Ret>> {
107        match self {
108            Self::Hot(hot) => hot.get_stored_account_callback(index_offset, callback),
109        }
110    }
111
112    /// iterate over all pubkeys
113    pub fn scan_pubkeys(&self, callback: impl FnMut(&Pubkey)) -> TieredStorageResult<()> {
114        match self {
115            Self::Hot(hot) => hot.scan_pubkeys(callback),
116        }
117    }
118
119    /// Iterate over all accounts and call `callback` with each account.
120    ///
121    /// `callback` parameters:
122    /// * Offset: the offset within the file of this account
123    /// * StoredAccountInfoWithoutData: the account itself, without account data
124    ///
125    /// Note that account data is not read/passed to the callback.
126    pub fn scan_accounts_without_data(
127        &self,
128        callback: impl for<'local> FnMut(Offset, StoredAccountInfoWithoutData<'local>),
129    ) -> TieredStorageResult<()> {
130        match self {
131            Self::Hot(hot) => hot.scan_accounts_without_data(callback),
132        }
133    }
134
135    /// Iterate over all accounts and call `callback` with each account.
136    ///
137    /// `callback` parameters:
138    /// * Offset: the offset within the file of this account
139    /// * StoredAccountInfo: the account itself, with account data
140    ///
141    /// Prefer scan_accounts_without_data() when account data is not needed,
142    /// as it can potentially read less and be faster.
143    pub fn scan_accounts(
144        &self,
145        callback: impl for<'local> FnMut(Offset, StoredAccountInfo<'local>),
146    ) -> TieredStorageResult<()> {
147        match self {
148            Self::Hot(hot) => hot.scan_accounts(callback),
149        }
150    }
151
152    /// Calculate the amount of storage required for an account with the passed
153    /// in data_len
154    pub(crate) fn calculate_stored_size(&self, data_len: usize) -> usize {
155        match self {
156            Self::Hot(hot) => hot.calculate_stored_size(data_len),
157        }
158    }
159
160    /// for each offset in `sorted_offsets`, return the length of data stored in the account
161    pub(crate) fn get_account_data_lens(
162        &self,
163        sorted_offsets: &[usize],
164    ) -> TieredStorageResult<Vec<usize>> {
165        match self {
166            Self::Hot(hot) => hot.get_account_data_lens(sorted_offsets),
167        }
168    }
169
170    /// Returns a slice suitable for use when archiving tiered storages
171    pub fn data_for_archive(&self) -> &[u8] {
172        match self {
173            Self::Hot(hot) => hot.data_for_archive(),
174        }
175    }
176}