2023-02-15 17:24:04 -08:00
|
|
|
use {
|
2023-02-22 11:13:58 -08:00
|
|
|
crate::{
|
2023-03-06 09:52:05 -08:00
|
|
|
account_storage::meta::{
|
|
|
|
StorableAccountsWithHashesAndWriteVersions, StoredAccountInfo, StoredAccountMeta,
|
|
|
|
},
|
2023-10-18 15:58:19 -07:00
|
|
|
accounts_hash::AccountHash,
|
2023-11-21 10:39:56 -08:00
|
|
|
append_vec::{AppendVec, AppendVecError},
|
2023-02-22 11:13:58 -08:00
|
|
|
storable_accounts::StorableAccounts,
|
2023-05-23 15:06:55 -07:00
|
|
|
tiered_storage::error::TieredStorageError,
|
2023-02-22 11:13:58 -08:00
|
|
|
},
|
2023-10-18 15:58:19 -07:00
|
|
|
solana_sdk::{account::ReadableAccount, clock::Slot, pubkey::Pubkey},
|
2023-03-15 20:38:20 -07:00
|
|
|
std::{
|
|
|
|
borrow::Borrow,
|
2023-05-22 14:09:09 -07:00
|
|
|
mem,
|
2023-03-15 20:38:20 -07:00
|
|
|
path::{Path, PathBuf},
|
|
|
|
},
|
2023-05-22 14:09:09 -07:00
|
|
|
thiserror::Error,
|
2023-02-15 17:24:04 -08:00
|
|
|
};
|
|
|
|
|
2023-03-20 11:34:18 -07:00
|
|
|
// Data placement should be aligned at the next boundary. Without alignment accessing the memory may
|
|
|
|
// crash on some architectures.
|
|
|
|
pub const ALIGN_BOUNDARY_OFFSET: usize = mem::size_of::<u64>();
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! u64_align {
|
|
|
|
($addr: expr) => {
|
|
|
|
($addr + (ALIGN_BOUNDARY_OFFSET - 1)) & !(ALIGN_BOUNDARY_OFFSET - 1)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-22 14:09:09 -07:00
|
|
|
#[derive(Error, Debug)]
|
|
|
|
/// An enum for AccountsFile related errors.
|
|
|
|
pub enum AccountsFileError {
|
|
|
|
#[error("I/O error: {0}")]
|
|
|
|
Io(#[from] std::io::Error),
|
2023-05-23 15:06:55 -07:00
|
|
|
|
2023-05-24 12:18:17 -07:00
|
|
|
#[error("AppendVecError: {0}")]
|
|
|
|
AppendVecError(#[from] AppendVecError),
|
|
|
|
|
2023-05-23 15:06:55 -07:00
|
|
|
#[error("TieredStorageError: {0}")]
|
|
|
|
TieredStorageError(#[from] TieredStorageError),
|
2023-05-22 14:09:09 -07:00
|
|
|
}
|
|
|
|
|
2023-11-21 10:39:56 -08:00
|
|
|
#[derive(Error, Debug, PartialEq, Eq)]
|
|
|
|
pub enum MatchAccountOwnerError {
|
|
|
|
#[error("The account owner does not match with the provided list")]
|
|
|
|
NoMatch,
|
|
|
|
#[error("Unable to load the account")]
|
|
|
|
UnableToLoad,
|
|
|
|
}
|
|
|
|
|
2023-05-22 14:09:09 -07:00
|
|
|
pub type Result<T> = std::result::Result<T, AccountsFileError>;
|
|
|
|
|
2023-02-15 17:24:04 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
/// An enum for accessing an accounts file which can be implemented
|
|
|
|
/// under different formats.
|
|
|
|
pub enum AccountsFile {
|
|
|
|
AppendVec(AppendVec),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AccountsFile {
|
2023-03-15 20:38:20 -07:00
|
|
|
/// Create an AccountsFile instance from the specified path.
|
|
|
|
///
|
|
|
|
/// The second element of the returned tuple is the number of accounts in the
|
|
|
|
/// accounts file.
|
2023-05-22 14:09:09 -07:00
|
|
|
pub fn new_from_file(path: impl AsRef<Path>, current_len: usize) -> Result<(Self, usize)> {
|
2023-03-15 20:38:20 -07:00
|
|
|
let (av, num_accounts) = AppendVec::new_from_file(path, current_len)?;
|
|
|
|
Ok((Self::AppendVec(av), num_accounts))
|
|
|
|
}
|
|
|
|
|
2023-05-22 14:09:09 -07:00
|
|
|
pub fn flush(&self) -> Result<()> {
|
2023-02-15 17:24:04 -08:00
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.flush(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset(&self) {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.reset(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remaining_bytes(&self) -> u64 {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.remaining_bytes(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.len(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.is_empty(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn capacity(&self) -> u64 {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.capacity(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-19 11:36:44 -07:00
|
|
|
pub fn is_recyclable(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(_) => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 17:24:04 -08:00
|
|
|
pub fn file_name(slot: Slot, id: impl std::fmt::Display) -> String {
|
|
|
|
format!("{slot}.{id}")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return (account metadata, next_index) pair for the account at the
|
|
|
|
/// specified `index` if any. Otherwise return None. Also return the
|
|
|
|
/// index of the next entry.
|
|
|
|
pub fn get_account(&self, index: usize) -> Option<(StoredAccountMeta<'_>, usize)> {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.get_account(index),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn account_matches_owners(
|
|
|
|
&self,
|
|
|
|
offset: usize,
|
2023-09-18 08:59:03 -07:00
|
|
|
owners: &[Pubkey],
|
2023-05-22 14:09:09 -07:00
|
|
|
) -> std::result::Result<usize, MatchAccountOwnerError> {
|
2023-02-15 17:24:04 -08:00
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.account_matches_owners(offset, owners),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the path of the underlying account file.
|
|
|
|
pub fn get_path(&self) -> PathBuf {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.get_path(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return iterator for account metadata
|
|
|
|
pub fn account_iter(&self) -> AccountsFileIter {
|
|
|
|
AccountsFileIter::new(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return a vector of account metadata for each account, starting from `offset`.
|
|
|
|
pub fn accounts(&self, offset: usize) -> Vec<StoredAccountMeta> {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.accounts(offset),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Copy each account metadata, account and hash to the internal buffer.
|
|
|
|
/// If there is no room to write the first entry, None is returned.
|
|
|
|
/// Otherwise, returns the starting offset of each account metadata.
|
|
|
|
/// Plus, the final return value is the offset where the next entry would be appended.
|
|
|
|
/// So, return.len() is 1 + (number of accounts written)
|
|
|
|
/// After each account is appended, the internal `current_len` is updated
|
|
|
|
/// and will be available to other threads.
|
|
|
|
pub fn append_accounts<
|
|
|
|
'a,
|
|
|
|
'b,
|
|
|
|
T: ReadableAccount + Sync,
|
|
|
|
U: StorableAccounts<'a, T>,
|
2023-10-18 15:58:19 -07:00
|
|
|
V: Borrow<AccountHash>,
|
2023-02-15 17:24:04 -08:00
|
|
|
>(
|
|
|
|
&self,
|
|
|
|
accounts: &StorableAccountsWithHashesAndWriteVersions<'a, 'b, T, U, V>,
|
|
|
|
skip: usize,
|
2023-03-06 09:52:05 -08:00
|
|
|
) -> Option<Vec<StoredAccountInfo>> {
|
2023-02-15 17:24:04 -08:00
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.append_accounts(accounts, skip),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct AccountsFileIter<'a> {
|
|
|
|
file_entry: &'a AccountsFile,
|
|
|
|
offset: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> AccountsFileIter<'a> {
|
|
|
|
pub fn new(file_entry: &'a AccountsFile) -> Self {
|
|
|
|
Self {
|
|
|
|
file_entry,
|
|
|
|
offset: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for AccountsFileIter<'a> {
|
|
|
|
type Item = StoredAccountMeta<'a>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if let Some((account, next_offset)) = self.file_entry.get_account(self.offset) {
|
|
|
|
self.offset = next_offset;
|
|
|
|
Some(account)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
|
|
|
use crate::accounts_file::AccountsFile;
|
|
|
|
impl AccountsFile {
|
|
|
|
pub(crate) fn set_current_len_for_tests(&self, len: usize) {
|
|
|
|
match self {
|
|
|
|
Self::AppendVec(av) => av.set_current_len_for_tests(len),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|