solana_runtime/
accounts_file.rs

1use {
2    crate::{append_vec::*, storable_accounts::StorableAccounts},
3    solana_sdk::{account::ReadableAccount, clock::Slot, hash::Hash, pubkey::Pubkey},
4    std::{borrow::Borrow, io, path::PathBuf},
5};
6
7#[derive(Debug)]
8/// An enum for accessing an accounts file which can be implemented
9/// under different formats.
10pub enum AccountsFile {
11    AppendVec(AppendVec),
12}
13
14impl AccountsFile {
15    /// By default, all AccountsFile will remove its underlying file on
16    /// drop.  Calling this function to disable such behavior for this
17    /// instance.
18    pub fn set_no_remove_on_drop(&mut self) {
19        match self {
20            Self::AppendVec(av) => av.set_no_remove_on_drop(),
21        }
22    }
23
24    pub fn flush(&self) -> io::Result<()> {
25        match self {
26            Self::AppendVec(av) => av.flush(),
27        }
28    }
29
30    pub fn reset(&self) {
31        match self {
32            Self::AppendVec(av) => av.reset(),
33        }
34    }
35
36    pub fn remaining_bytes(&self) -> u64 {
37        match self {
38            Self::AppendVec(av) => av.remaining_bytes(),
39        }
40    }
41
42    pub fn len(&self) -> usize {
43        match self {
44            Self::AppendVec(av) => av.len(),
45        }
46    }
47
48    pub fn is_empty(&self) -> bool {
49        match self {
50            Self::AppendVec(av) => av.is_empty(),
51        }
52    }
53
54    pub fn capacity(&self) -> u64 {
55        match self {
56            Self::AppendVec(av) => av.capacity(),
57        }
58    }
59
60    pub fn file_name(slot: Slot, id: impl std::fmt::Display) -> String {
61        format!("{slot}.{id}")
62    }
63
64    /// Return (account metadata, next_index) pair for the account at the
65    /// specified `index` if any.  Otherwise return None.   Also return the
66    /// index of the next entry.
67    pub fn get_account(&self, index: usize) -> Option<(StoredAccountMeta<'_>, usize)> {
68        match self {
69            Self::AppendVec(av) => av.get_account(index),
70        }
71    }
72
73    pub fn account_matches_owners(
74        &self,
75        offset: usize,
76        owners: &[&Pubkey],
77    ) -> Result<usize, MatchAccountOwnerError> {
78        match self {
79            Self::AppendVec(av) => av.account_matches_owners(offset, owners),
80        }
81    }
82
83    /// Return the path of the underlying account file.
84    pub fn get_path(&self) -> PathBuf {
85        match self {
86            Self::AppendVec(av) => av.get_path(),
87        }
88    }
89
90    /// Return iterator for account metadata
91    pub fn account_iter(&self) -> AccountsFileIter {
92        AccountsFileIter::new(self)
93    }
94
95    /// Return a vector of account metadata for each account, starting from `offset`.
96    pub fn accounts(&self, offset: usize) -> Vec<StoredAccountMeta> {
97        match self {
98            Self::AppendVec(av) => av.accounts(offset),
99        }
100    }
101
102    /// Copy each account metadata, account and hash to the internal buffer.
103    /// If there is no room to write the first entry, None is returned.
104    /// Otherwise, returns the starting offset of each account metadata.
105    /// Plus, the final return value is the offset where the next entry would be appended.
106    /// So, return.len() is 1 + (number of accounts written)
107    /// After each account is appended, the internal `current_len` is updated
108    /// and will be available to other threads.
109    pub fn append_accounts<
110        'a,
111        'b,
112        T: ReadableAccount + Sync,
113        U: StorableAccounts<'a, T>,
114        V: Borrow<Hash>,
115    >(
116        &self,
117        accounts: &StorableAccountsWithHashesAndWriteVersions<'a, 'b, T, U, V>,
118        skip: usize,
119    ) -> Option<Vec<usize>> {
120        match self {
121            Self::AppendVec(av) => av.append_accounts(accounts, skip),
122        }
123    }
124}
125
126pub struct AccountsFileIter<'a> {
127    file_entry: &'a AccountsFile,
128    offset: usize,
129}
130
131impl<'a> AccountsFileIter<'a> {
132    pub fn new(file_entry: &'a AccountsFile) -> Self {
133        Self {
134            file_entry,
135            offset: 0,
136        }
137    }
138}
139
140impl<'a> Iterator for AccountsFileIter<'a> {
141    type Item = StoredAccountMeta<'a>;
142
143    fn next(&mut self) -> Option<Self::Item> {
144        if let Some((account, next_offset)) = self.file_entry.get_account(self.offset) {
145            self.offset = next_offset;
146            Some(account)
147        } else {
148            None
149        }
150    }
151}
152
153#[cfg(test)]
154pub mod tests {
155    use crate::accounts_file::AccountsFile;
156    impl AccountsFile {
157        pub(crate) fn set_current_len_for_tests(&self, len: usize) {
158            match self {
159                Self::AppendVec(av) => av.set_current_len_for_tests(len),
160            }
161        }
162    }
163}