solana_accounts_db/tiered_storage/
readable.rs

1use {
2    crate::{
3        account_storage::meta::StoredAccountMeta,
4        accounts_file::MatchAccountOwnerError,
5        append_vec::IndexInfo,
6        tiered_storage::{
7            file::TieredReadableFile,
8            footer::{AccountMetaFormat, TieredStorageFooter},
9            hot::HotStorageReader,
10            index::IndexOffset,
11            TieredStorageResult,
12        },
13    },
14    solana_sdk::{account::AccountSharedData, 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 nderlying 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 account located at the specified index offset.
79    pub fn get_stored_account_meta_callback<Ret>(
80        &self,
81        index_offset: IndexOffset,
82        callback: impl for<'local> FnMut(StoredAccountMeta<'local>) -> Ret,
83    ) -> TieredStorageResult<Option<Ret>> {
84        match self {
85            Self::Hot(hot) => hot.get_stored_account_meta_callback(index_offset, callback),
86        }
87    }
88
89    /// Returns Ok(index_of_matching_owner) if the account owner at
90    /// `account_offset` is one of the pubkeys in `owners`.
91    ///
92    /// Returns Err(MatchAccountOwnerError::NoMatch) if the account has 0
93    /// lamports or the owner is not one of the pubkeys in `owners`.
94    ///
95    /// Returns Err(MatchAccountOwnerError::UnableToLoad) if there is any internal
96    /// error that causes the data unable to load, including `account_offset`
97    /// causes a data overrun.
98    pub fn account_matches_owners(
99        &self,
100        index_offset: IndexOffset,
101        owners: &[Pubkey],
102    ) -> Result<usize, MatchAccountOwnerError> {
103        match self {
104            Self::Hot(hot) => {
105                let account_offset = hot
106                    .get_account_offset(index_offset)
107                    .map_err(|_| MatchAccountOwnerError::UnableToLoad)?;
108                hot.account_matches_owners(account_offset, owners)
109            }
110        }
111    }
112
113    /// iterate over all pubkeys
114    pub fn scan_pubkeys(&self, callback: impl FnMut(&Pubkey)) -> TieredStorageResult<()> {
115        match self {
116            Self::Hot(hot) => hot.scan_pubkeys(callback),
117        }
118    }
119
120    /// iterate over all entries to put in index
121    pub(crate) fn scan_index(&self, callback: impl FnMut(IndexInfo)) -> TieredStorageResult<()> {
122        match self {
123            Self::Hot(hot) => hot.scan_index(callback),
124        }
125    }
126
127    /// Iterate over all accounts and call `callback` with each account.
128    pub(crate) fn scan_accounts(
129        &self,
130        callback: impl for<'local> FnMut(StoredAccountMeta<'local>),
131    ) -> TieredStorageResult<()> {
132        match self {
133            Self::Hot(hot) => hot.scan_accounts(callback),
134        }
135    }
136
137    /// for each offset in `sorted_offsets`, return the account size
138    pub(crate) fn get_account_sizes(
139        &self,
140        sorted_offsets: &[usize],
141    ) -> TieredStorageResult<Vec<usize>> {
142        match self {
143            Self::Hot(hot) => hot.get_account_sizes(sorted_offsets),
144        }
145    }
146
147    /// Returns a slice suitable for use when archiving tiered storages
148    pub fn data_for_archive(&self) -> &[u8] {
149        match self {
150            Self::Hot(hot) => hot.data_for_archive(),
151        }
152    }
153}