1use {
2 crate::{
3 account_info::AccountInfo,
4 account_storage::meta::StoredAccountMeta,
5 accounts_db::AccountsFileId,
6 append_vec::{AppendVec, AppendVecError, IndexInfo},
7 storable_accounts::StorableAccounts,
8 tiered_storage::{
9 error::TieredStorageError, hot::HOT_FORMAT, index::IndexOffset, TieredStorage,
10 },
11 },
12 solana_pubkey::Pubkey,
13 solana_sdk::{account::AccountSharedData, clock::Slot},
14 std::{
15 mem,
16 path::{Path, PathBuf},
17 },
18 thiserror::Error,
19};
20
21pub const ALIGN_BOUNDARY_OFFSET: usize = mem::size_of::<u64>();
24#[macro_export]
25macro_rules! u64_align {
26 ($addr: expr) => {
27 ($addr + (ALIGN_BOUNDARY_OFFSET - 1)) & !(ALIGN_BOUNDARY_OFFSET - 1)
28 };
29}
30
31#[derive(Error, Debug)]
32pub enum AccountsFileError {
34 #[error("I/O error: {0}")]
35 Io(#[from] std::io::Error),
36
37 #[error("AppendVecError: {0}")]
38 AppendVecError(#[from] AppendVecError),
39
40 #[error("TieredStorageError: {0}")]
41 TieredStorageError(#[from] TieredStorageError),
42}
43
44#[derive(Error, Debug, PartialEq, Eq)]
45pub enum MatchAccountOwnerError {
46 #[error("The account owner does not match with the provided list")]
47 NoMatch,
48 #[error("Unable to load the account")]
49 UnableToLoad,
50}
51
52#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
53pub enum StorageAccess {
54 Mmap,
56 #[default]
59 File,
60}
61
62pub type Result<T> = std::result::Result<T, AccountsFileError>;
63
64#[derive(Debug)]
65pub enum AccountsFile {
68 AppendVec(AppendVec),
69 TieredStorage(TieredStorage),
70}
71
72impl AccountsFile {
73 pub fn new_from_file(
78 path: impl Into<PathBuf>,
79 current_len: usize,
80 storage_access: StorageAccess,
81 ) -> Result<(Self, usize)> {
82 let (av, num_accounts) = AppendVec::new_from_file(path, current_len, storage_access)?;
83 Ok((Self::AppendVec(av), num_accounts))
84 }
85
86 pub(crate) fn can_append(&self) -> bool {
88 match self {
89 Self::AppendVec(av) => av.can_append(),
90 Self::TieredStorage(_) => false,
92 }
93 }
94
95 pub(crate) fn reopen_as_readonly(&self) -> Option<Self> {
97 match self {
98 Self::AppendVec(av) => av.reopen_as_readonly().map(Self::AppendVec),
99 Self::TieredStorage(_) => None,
100 }
101 }
102
103 pub(crate) fn dead_bytes_due_to_zero_lamport_single_ref(&self, count: usize) -> usize {
106 match self {
107 Self::AppendVec(av) => av.dead_bytes_due_to_zero_lamport_single_ref(count),
108 Self::TieredStorage(ts) => ts.dead_bytes_due_to_zero_lamport_single_ref(count),
109 }
110 }
111
112 pub fn flush(&self) -> Result<()> {
113 match self {
114 Self::AppendVec(av) => av.flush(),
115 Self::TieredStorage(_) => Ok(()),
116 }
117 }
118
119 pub fn reset(&self) {
120 match self {
121 Self::AppendVec(av) => av.reset(),
122 Self::TieredStorage(_) => {}
123 }
124 }
125
126 pub fn remaining_bytes(&self) -> u64 {
127 match self {
128 Self::AppendVec(av) => av.remaining_bytes(),
129 Self::TieredStorage(ts) => ts.capacity().saturating_sub(ts.len() as u64),
130 }
131 }
132
133 pub fn len(&self) -> usize {
134 match self {
135 Self::AppendVec(av) => av.len(),
136 Self::TieredStorage(ts) => ts.len(),
137 }
138 }
139
140 pub fn is_empty(&self) -> bool {
141 match self {
142 Self::AppendVec(av) => av.is_empty(),
143 Self::TieredStorage(ts) => ts.is_empty(),
144 }
145 }
146
147 pub fn capacity(&self) -> u64 {
148 match self {
149 Self::AppendVec(av) => av.capacity(),
150 Self::TieredStorage(ts) => ts.capacity(),
151 }
152 }
153
154 pub fn file_name(slot: Slot, id: AccountsFileId) -> String {
155 format!("{slot}.{id}")
156 }
157
158 pub fn get_stored_account_meta_callback<Ret>(
160 &self,
161 offset: usize,
162 callback: impl for<'local> FnMut(StoredAccountMeta<'local>) -> Ret,
163 ) -> Option<Ret> {
164 match self {
165 Self::AppendVec(av) => av.get_stored_account_meta_callback(offset, callback),
166 Self::TieredStorage(ts) => ts
170 .reader()?
171 .get_stored_account_meta_callback(
172 IndexOffset(AccountInfo::get_reduced_offset(offset)),
173 callback,
174 )
175 .ok()?,
176 }
177 }
178
179 pub(crate) fn get_account_shared_data(&self, offset: usize) -> Option<AccountSharedData> {
181 match self {
182 Self::AppendVec(av) => av.get_account_shared_data(offset),
183 Self::TieredStorage(ts) => {
184 let index_offset = IndexOffset(AccountInfo::get_reduced_offset(offset));
188 ts.reader()?.get_account_shared_data(index_offset).ok()?
189 }
190 }
191 }
192
193 pub fn account_matches_owners(
194 &self,
195 offset: usize,
196 owners: &[Pubkey],
197 ) -> std::result::Result<usize, MatchAccountOwnerError> {
198 match self {
199 Self::AppendVec(av) => av.account_matches_owners(offset, owners),
200 Self::TieredStorage(ts) => {
204 let Some(reader) = ts.reader() else {
205 return Err(MatchAccountOwnerError::UnableToLoad);
206 };
207 reader.account_matches_owners(
208 IndexOffset(AccountInfo::get_reduced_offset(offset)),
209 owners,
210 )
211 }
212 }
213 }
214
215 pub fn path(&self) -> &Path {
217 match self {
218 Self::AppendVec(av) => av.path(),
219 Self::TieredStorage(ts) => ts.path(),
220 }
221 }
222
223 pub fn scan_accounts(&self, callback: impl for<'local> FnMut(StoredAccountMeta<'local>)) {
225 match self {
226 Self::AppendVec(av) => av.scan_accounts(callback),
227 Self::TieredStorage(ts) => {
228 if let Some(reader) = ts.reader() {
229 _ = reader.scan_accounts(callback);
230 }
231 }
232 }
233 }
234
235 pub(crate) fn get_account_sizes(&self, sorted_offsets: &[usize]) -> Vec<usize> {
237 match self {
238 Self::AppendVec(av) => av.get_account_sizes(sorted_offsets),
239 Self::TieredStorage(ts) => ts
240 .reader()
241 .and_then(|reader| reader.get_account_sizes(sorted_offsets).ok())
242 .unwrap_or_default(),
243 }
244 }
245
246 pub(crate) fn scan_index(&self, callback: impl FnMut(IndexInfo)) {
248 match self {
249 Self::AppendVec(av) => av.scan_index(callback),
250 Self::TieredStorage(ts) => {
251 if let Some(reader) = ts.reader() {
252 _ = reader.scan_index(callback);
253 }
254 }
255 }
256 }
257
258 pub fn scan_pubkeys(&self, callback: impl FnMut(&Pubkey)) {
260 match self {
261 Self::AppendVec(av) => av.scan_pubkeys(callback),
262 Self::TieredStorage(ts) => {
263 if let Some(reader) = ts.reader() {
264 _ = reader.scan_pubkeys(callback);
265 }
266 }
267 }
268 }
269
270 pub fn append_accounts<'a>(
278 &self,
279 accounts: &impl StorableAccounts<'a>,
280 skip: usize,
281 ) -> Option<StoredAccountsInfo> {
282 match self {
283 Self::AppendVec(av) => av.append_accounts(accounts, skip),
284 Self::TieredStorage(ts) => ts
288 .write_accounts(accounts, skip, &HOT_FORMAT)
289 .map(|mut stored_accounts_info| {
290 stored_accounts_info.offsets.iter_mut().for_each(|offset| {
291 *offset = AccountInfo::reduced_offset_to_offset(*offset as u32);
292 });
293 stored_accounts_info
294 })
295 .ok(),
296 }
297 }
298
299 pub fn internals_for_archive(&self) -> InternalsForArchive {
301 match self {
302 Self::AppendVec(av) => av.internals_for_archive(),
303 Self::TieredStorage(ts) => InternalsForArchive::Mmap(
304 ts.reader()
305 .expect("must be a reader when archiving")
306 .data_for_archive(),
307 ),
308 }
309 }
310}
311
312#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
314pub enum AccountsFileProvider {
315 #[default]
316 AppendVec,
317 HotStorage,
318}
319
320impl AccountsFileProvider {
321 pub fn new_writable(&self, path: impl Into<PathBuf>, file_size: u64) -> AccountsFile {
322 match self {
323 Self::AppendVec => {
324 AccountsFile::AppendVec(AppendVec::new(path, true, file_size as usize))
325 }
326 Self::HotStorage => AccountsFile::TieredStorage(TieredStorage::new_writable(path)),
327 }
328 }
329}
330
331#[derive(Debug)]
333pub enum InternalsForArchive<'a> {
334 Mmap(&'a [u8]),
336 FileIo(&'a Path),
338}
339
340#[derive(Debug)]
342pub struct StoredAccountsInfo {
343 pub offsets: Vec<usize>,
345 pub size: usize,
347}
348
349#[cfg(test)]
350pub mod tests {
351 use crate::accounts_file::AccountsFile;
352 impl AccountsFile {
353 pub(crate) fn set_current_len_for_tests(&self, len: usize) {
354 match self {
355 Self::AppendVec(av) => av.set_current_len_for_tests(len),
356 Self::TieredStorage(_) => {}
357 }
358 }
359 }
360}