1use {
2 crate::{
3 account_info::{AccountInfo, Offset},
4 account_storage::stored_account_info::{StoredAccountInfo, StoredAccountInfoWithoutData},
5 accounts_db::AccountsFileId,
6 append_vec::{AppendVec, AppendVecError},
7 storable_accounts::StorableAccounts,
8 tiered_storage::{
9 error::TieredStorageError, hot::HOT_FORMAT, index::IndexOffset, TieredStorage,
10 },
11 },
12 agave_fs::buffered_reader::RequiredLenBufFileRead,
13 solana_account::AccountSharedData,
14 solana_clock::Slot,
15 solana_pubkey::Pubkey,
16 std::{
17 mem,
18 path::{Path, PathBuf},
19 },
20 thiserror::Error,
21};
22
23pub const ALIGN_BOUNDARY_OFFSET: usize = mem::size_of::<u64>();
26#[macro_export]
27macro_rules! u64_align {
28 ($addr: expr) => {
29 ($addr + ($crate::accounts_file::ALIGN_BOUNDARY_OFFSET - 1))
30 & !($crate::accounts_file::ALIGN_BOUNDARY_OFFSET - 1)
31 };
32}
33
34pub type Result<T> = std::result::Result<T, AccountsFileError>;
35
36#[derive(Error, Debug)]
38pub enum AccountsFileError {
39 #[error("I/O error: {0}")]
40 Io(#[from] std::io::Error),
41
42 #[error("AppendVecError: {0}")]
43 AppendVecError(#[from] AppendVecError),
44
45 #[error("TieredStorageError: {0}")]
46 TieredStorageError(#[from] TieredStorageError),
47}
48
49#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
50pub enum StorageAccess {
51 Mmap,
53 #[default]
56 File,
57}
58
59#[derive(Debug)]
60pub enum AccountsFile {
63 AppendVec(AppendVec),
64 TieredStorage(TieredStorage),
65}
66
67impl AccountsFile {
68 #[cfg(feature = "dev-context-only-utils")]
73 pub fn new_from_file(
74 path: impl Into<PathBuf>,
75 current_len: usize,
76 storage_access: StorageAccess,
77 ) -> Result<(Self, usize)> {
78 let (av, num_accounts) = AppendVec::new_from_file(path, current_len, storage_access)?;
79 Ok((Self::AppendVec(av), num_accounts))
80 }
81
82 pub fn new_for_startup(
88 path: impl Into<PathBuf>,
89 current_len: usize,
90 storage_access: StorageAccess,
91 ) -> Result<Self> {
92 let av = AppendVec::new_for_startup(path, current_len, storage_access)?;
93 Ok(Self::AppendVec(av))
94 }
95
96 pub(crate) fn reopen_as_readonly(&self) -> Option<Self> {
98 match self {
99 Self::AppendVec(av) => av.reopen_as_readonly_file_io().map(Self::AppendVec),
100 Self::TieredStorage(_) => None,
101 }
102 }
103
104 pub(crate) fn dead_bytes_due_to_zero_lamport_single_ref(&self, count: usize) -> usize {
107 match self {
108 Self::AppendVec(av) => av.dead_bytes_due_to_zero_lamport_single_ref(count),
109 Self::TieredStorage(ts) => ts.dead_bytes_due_to_zero_lamport_single_ref(count),
110 }
111 }
112
113 pub fn flush(&self) -> Result<()> {
115 match self {
116 Self::AppendVec(av) => av.flush()?,
117 Self::TieredStorage(_) => {}
118 }
119 Ok(())
120 }
121
122 pub fn remaining_bytes(&self) -> u64 {
123 match self {
124 Self::AppendVec(av) => av.remaining_bytes(),
125 Self::TieredStorage(ts) => ts.capacity().saturating_sub(ts.len() as u64),
126 }
127 }
128
129 pub fn len(&self) -> usize {
131 match self {
132 Self::AppendVec(av) => av.len(),
133 Self::TieredStorage(ts) => ts.len(),
134 }
135 }
136
137 pub fn is_empty(&self) -> bool {
138 match self {
139 Self::AppendVec(av) => av.is_empty(),
140 Self::TieredStorage(ts) => ts.is_empty(),
141 }
142 }
143
144 pub fn capacity(&self) -> u64 {
146 match self {
147 Self::AppendVec(av) => av.capacity(),
148 Self::TieredStorage(ts) => ts.capacity(),
149 }
150 }
151
152 pub fn file_name(slot: Slot, id: AccountsFileId) -> String {
153 format!("{slot}.{id}")
154 }
155
156 pub fn get_stored_account_without_data_callback<Ret>(
164 &self,
165 offset: usize,
166 callback: impl for<'local> FnMut(StoredAccountInfoWithoutData<'local>) -> Ret,
167 ) -> Option<Ret> {
168 match self {
169 Self::AppendVec(av) => av.get_stored_account_without_data_callback(offset, callback),
170 Self::TieredStorage(ts) => {
171 let index_offset = IndexOffset(AccountInfo::get_reduced_offset(offset));
175 ts.reader()?
176 .get_stored_account_without_data_callback(index_offset, callback)
177 .ok()?
178 }
179 }
180 }
181
182 pub fn get_stored_account_callback<Ret>(
190 &self,
191 offset: usize,
192 callback: impl for<'local> FnMut(StoredAccountInfo<'local>) -> Ret,
193 ) -> Option<Ret> {
194 match self {
195 Self::AppendVec(av) => av.get_stored_account_callback(offset, callback),
196 Self::TieredStorage(ts) => {
197 let index_offset = IndexOffset(AccountInfo::get_reduced_offset(offset));
201 ts.reader()?
202 .get_stored_account_callback(index_offset, callback)
203 .ok()?
204 }
205 }
206 }
207
208 pub(crate) fn get_account_shared_data(&self, offset: usize) -> Option<AccountSharedData> {
210 match self {
211 Self::AppendVec(av) => av.get_account_shared_data(offset),
212 Self::TieredStorage(ts) => {
213 let index_offset = IndexOffset(AccountInfo::get_reduced_offset(offset));
217 ts.reader()?.get_account_shared_data(index_offset).ok()?
218 }
219 }
220 }
221
222 pub fn path(&self) -> &Path {
224 match self {
225 Self::AppendVec(av) => av.path(),
226 Self::TieredStorage(ts) => ts.path(),
227 }
228 }
229
230 pub fn scan_accounts_without_data(
238 &self,
239 callback: impl for<'local> FnMut(Offset, StoredAccountInfoWithoutData<'local>),
240 ) -> Result<()> {
241 match self {
242 Self::AppendVec(av) => av.scan_accounts_without_data(callback)?,
243 Self::TieredStorage(ts) => {
244 if let Some(reader) = ts.reader() {
245 reader.scan_accounts_without_data(callback)?;
246 }
247 }
248 }
249 Ok(())
250 }
251
252 pub(crate) fn scan_accounts<'a>(
261 &'a self,
262 reader: &mut impl RequiredLenBufFileRead<'a>,
263 callback: impl for<'local> FnMut(Offset, StoredAccountInfo<'local>),
264 ) -> Result<()> {
265 match self {
266 Self::AppendVec(av) => av.scan_accounts(reader, callback)?,
267 Self::TieredStorage(ts) => {
268 if let Some(reader) = ts.reader() {
269 reader.scan_accounts(callback)?;
270 }
271 }
272 }
273 Ok(())
274 }
275
276 pub(crate) fn calculate_stored_size(&self, data_len: usize) -> usize {
279 match self {
280 Self::AppendVec(_) => AppendVec::calculate_stored_size(data_len),
281 Self::TieredStorage(ts) => ts
282 .reader()
283 .expect("Reader must be initialized as stored size is specific to format")
284 .calculate_stored_size(data_len),
285 }
286 }
287
288 pub(crate) fn get_account_data_lens(&self, sorted_offsets: &[usize]) -> Vec<usize> {
290 match self {
291 Self::AppendVec(av) => av.get_account_data_lens(sorted_offsets),
292 Self::TieredStorage(ts) => ts
293 .reader()
294 .and_then(|reader| reader.get_account_data_lens(sorted_offsets).ok())
295 .unwrap_or_default(),
296 }
297 }
298
299 pub fn scan_pubkeys(&self, callback: impl FnMut(&Pubkey)) -> Result<()> {
301 match self {
302 Self::AppendVec(av) => av.scan_pubkeys(callback)?,
303 Self::TieredStorage(ts) => {
304 if let Some(reader) = ts.reader() {
305 reader.scan_pubkeys(callback)?;
306 }
307 }
308 }
309 Ok(())
310 }
311
312 pub fn write_accounts<'a>(
320 &self,
321 accounts: &impl StorableAccounts<'a>,
322 skip: usize,
323 ) -> Option<StoredAccountsInfo> {
324 match self {
325 Self::AppendVec(av) => av.append_accounts(accounts, skip),
326 Self::TieredStorage(ts) => ts
330 .write_accounts(accounts, skip, &HOT_FORMAT)
331 .map(|mut stored_accounts_info| {
332 stored_accounts_info.offsets.iter_mut().for_each(|offset| {
333 *offset = AccountInfo::reduced_offset_to_offset(*offset as u32);
334 });
335 stored_accounts_info
336 })
337 .ok(),
338 }
339 }
340
341 pub fn internals_for_archive(&self) -> InternalsForArchive<'_> {
343 match self {
344 Self::AppendVec(av) => av.internals_for_archive(),
345 Self::TieredStorage(ts) => InternalsForArchive::Mmap(
346 ts.reader()
347 .expect("must be a reader when archiving")
348 .data_for_archive(),
349 ),
350 }
351 }
352}
353
354#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
356pub enum AccountsFileProvider {
357 #[default]
358 AppendVec,
359 HotStorage,
360}
361
362impl AccountsFileProvider {
363 pub fn new_writable(
364 &self,
365 path: impl Into<PathBuf>,
366 file_size: u64,
367 storage_access: StorageAccess,
368 ) -> AccountsFile {
369 match self {
370 Self::AppendVec => AccountsFile::AppendVec(AppendVec::new(
371 path,
372 true,
373 file_size as usize,
374 storage_access,
375 )),
376 Self::HotStorage => AccountsFile::TieredStorage(TieredStorage::new_writable(path)),
377 }
378 }
379}
380
381#[derive(Debug)]
383pub enum InternalsForArchive<'a> {
384 Mmap(&'a [u8]),
386 FileIo(&'a Path),
388}
389
390#[derive(Debug)]
392pub struct StoredAccountsInfo {
393 pub offsets: Vec<usize>,
395 pub size: usize,
397}