#![allow(dead_code)] pub mod byte_block; pub mod error; pub mod file; pub mod footer; pub mod hot; pub mod index; pub mod meta; pub mod mmap_utils; pub mod readable; pub mod writer; use { crate::{ account_storage::meta::{StorableAccountsWithHashesAndWriteVersions, StoredAccountInfo}, storable_accounts::StorableAccounts, }, error::TieredStorageError, footer::{AccountBlockFormat, AccountMetaFormat, OwnersBlockFormat}, index::AccountIndexFormat, solana_sdk::{account::ReadableAccount, hash::Hash}, std::{ borrow::Borrow, fs::OpenOptions, path::{Path, PathBuf}, }, writer::TieredStorageWriter, }; pub type TieredStorageResult = Result; /// The struct that defines the formats of all building blocks of a /// TieredStorage. #[derive(Clone, Debug)] pub struct TieredStorageFormat { pub meta_entry_size: usize, pub account_meta_format: AccountMetaFormat, pub owners_block_format: OwnersBlockFormat, pub account_index_format: AccountIndexFormat, pub account_block_format: AccountBlockFormat, } #[derive(Debug)] pub struct TieredStorage { format: Option, path: PathBuf, } impl TieredStorage { /// Creates a new writable instance of TieredStorage based on the /// specified path and TieredStorageFormat. /// /// Note that the actual file will not be created until write_accounts /// is called. pub fn new_writable(path: impl Into, format: TieredStorageFormat) -> Self { Self { format: Some(format), path: path.into(), } } /// Returns the path to this TieredStorage. pub fn path(&self) -> &Path { self.path.as_path() } /// Writes the specified accounts into this TieredStorage. pub fn write_accounts< 'a, 'b, T: ReadableAccount + Sync, U: StorableAccounts<'a, T>, V: Borrow, >( &self, accounts: &StorableAccountsWithHashesAndWriteVersions<'a, 'b, T, U, V>, skip: usize, ) -> TieredStorageResult> { // self.format must be Some as write_accounts can only be called on a // TieredStorage instance created via new_writable() where it format // field is required. assert!(self.format.is_some()); let writer = TieredStorageWriter::new(&self.path, self.format.as_ref().unwrap())?; writer.write_accounts(accounts, skip) } /// Returns the size of the underlying accounts file. pub fn file_size(&self) -> TieredStorageResult { let file = OpenOptions::new().read(true).open(&self.path); Ok(file .and_then(|file| file.metadata()) .map(|metadata| metadata.len()) .unwrap_or(0)) } } #[cfg(test)] mod tests { use { super::*, crate::account_storage::meta::StoredMetaWriteVersion, footer::{TieredStorageFooter, TieredStorageMagicNumber}, hot::HOT_FORMAT, solana_sdk::{account::AccountSharedData, clock::Slot, pubkey::Pubkey}, tempfile::NamedTempFile, }; #[test] fn test_new_footer_only() { let path = NamedTempFile::new().unwrap().path().to_path_buf(); let tiered_storage = TieredStorage::new_writable(path.clone(), HOT_FORMAT.clone()); assert_eq!(tiered_storage.path(), path); assert_eq!(tiered_storage.file_size().unwrap(), 0); let slot_ignored = Slot::MAX; let account_refs = Vec::<(&Pubkey, &AccountSharedData)>::new(); let account_data = (slot_ignored, account_refs.as_slice()); let storable_accounts = StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions( &account_data, Vec::<&Hash>::new(), Vec::::new(), ); let result = tiered_storage.write_accounts(&storable_accounts, 0); // Expect the result to be TieredStorageError::Unsupported as the feature // is not yet fully supported, but we can still check its partial results // in the test. assert!(result.is_err()); assert_eq!( tiered_storage.file_size().unwrap() as usize, std::mem::size_of::() + std::mem::size_of::() ); } }