Skip to content

Commit

Permalink
[TieredStorage] OwnersBlock (#34052)
Browse files Browse the repository at this point in the history
#### 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
yhchiang-sol authored Nov 15, 2023
1 parent fb76b4c commit 7fd13c0
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
1 change: 1 addition & 0 deletions accounts-db/src/tiered_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod hot;
pub mod index;
pub mod meta;
pub mod mmap_utils;
pub mod owners;
pub mod readable;
pub mod writer;

Expand Down
98 changes: 98 additions & 0 deletions accounts-db/src/tiered_storage/owners.rs
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
);
}
}
}

0 comments on commit 7fd13c0

Please sign in to comment.