-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TieredStorage] OwnersBlock (#34052)
#### Problem A TieredStorage file has three types of block: accounts block, index block, and owner block, but implementation of the TieredStorage OwnersBlock is missing in the current master. #### Summary of Changes This PR implements OwnersBlock which stores a set of owners' addresses in a compact but efficient way. #### Test Plan A new unit-test is included in this PR.
- Loading branch information
1 parent
fb76b4c
commit 7fd13c0
Showing
2 changed files
with
99 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use { | ||
crate::tiered_storage::{ | ||
file::TieredStorageFile, footer::TieredStorageFooter, mmap_utils::get_type, | ||
TieredStorageResult, | ||
}, | ||
memmap2::Mmap, | ||
solana_sdk::pubkey::Pubkey, | ||
}; | ||
|
||
/// Owner block holds a set of unique addresses of account owners, | ||
/// and an account meta has a owner_offset field for accessing | ||
/// it's owner address. | ||
#[derive(Debug)] | ||
pub struct OwnersBlock; | ||
|
||
/// The offset to an owner entry in the owners block. | ||
/// This is used to obtain the address of the account owner. | ||
#[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
pub struct OwnerOffset(pub usize); | ||
|
||
/// OwnersBlock is persisted as a consecutive bytes of pubkeys without any | ||
/// meta-data. For each account meta, it has a owner_offset field to | ||
/// access its owner's address in the OwnersBlock. | ||
impl OwnersBlock { | ||
/// Persists the provided owners' addresses into the specified file. | ||
pub fn write_owners_block( | ||
file: &TieredStorageFile, | ||
addresses: &[Pubkey], | ||
) -> TieredStorageResult<usize> { | ||
let mut bytes_written = 0; | ||
for address in addresses { | ||
bytes_written += file.write_type(address)?; | ||
} | ||
|
||
Ok(bytes_written) | ||
} | ||
|
||
/// Returns the owner address associated with the specified owner_offset | ||
/// and footer inside the input mmap. | ||
pub fn get_owner_address<'a>( | ||
mmap: &'a Mmap, | ||
footer: &TieredStorageFooter, | ||
owner_offset: OwnerOffset, | ||
) -> TieredStorageResult<&'a Pubkey> { | ||
let offset = | ||
footer.owners_block_offset as usize + (std::mem::size_of::<Pubkey>() * owner_offset.0); | ||
let (pubkey, _) = get_type::<Pubkey>(mmap, offset)?; | ||
|
||
Ok(pubkey) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use { | ||
super::*, crate::tiered_storage::file::TieredStorageFile, memmap2::MmapOptions, | ||
std::fs::OpenOptions, tempfile::TempDir, | ||
}; | ||
|
||
#[test] | ||
fn test_owners_block() { | ||
// Generate a new temp path that is guaranteed to NOT already have a file. | ||
let temp_dir = TempDir::new().unwrap(); | ||
let path = temp_dir.path().join("test_owners_block"); | ||
const NUM_OWNERS: u32 = 10; | ||
|
||
let addresses: Vec<_> = std::iter::repeat_with(Pubkey::new_unique) | ||
.take(NUM_OWNERS as usize) | ||
.collect(); | ||
|
||
let footer = TieredStorageFooter { | ||
// Set owners_block_offset to 0 as we didn't write any account | ||
// meta/data nor index block. | ||
owners_block_offset: 0, | ||
..TieredStorageFooter::default() | ||
}; | ||
|
||
{ | ||
let file = TieredStorageFile::new_writable(&path).unwrap(); | ||
|
||
OwnersBlock::write_owners_block(&file, &addresses).unwrap(); | ||
|
||
// while the test only focuses on account metas, writing a footer | ||
// here is necessary to make it a valid tiered-storage file. | ||
footer.write_footer_block(&file).unwrap(); | ||
} | ||
|
||
let file = OpenOptions::new().read(true).open(path).unwrap(); | ||
let mmap = unsafe { MmapOptions::new().map(&file).unwrap() }; | ||
|
||
for (i, address) in addresses.iter().enumerate() { | ||
assert_eq!( | ||
OwnersBlock::get_owner_address(&mmap, &footer, OwnerOffset(i)).unwrap(), | ||
address | ||
); | ||
} | ||
} | ||
} |