[TieredStorage] In-memory struct for writing OwnersBlock (#34853)
#### Problem To write the owners-block, it requires an in-memory struct that maintains a set of unique owner addresses while providing a look-up function to obtain the OwnerOffset with the specified owner address. #### Summary of Changes This PR adds OwnersTable, the in-memory struct that maintains a set of unique owner addresses while providing a look-up function to obtain the OwnerOffset with the specified owner address. #### Test Plan A new unit-test is added.
This commit is contained in:
parent
3303c2566c
commit
1810feadc2
|
@ -5307,6 +5307,7 @@ dependencies = [
|
|||
"fnv",
|
||||
"im",
|
||||
"index_list",
|
||||
"indexmap 2.1.0",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
|
|
|
@ -23,6 +23,7 @@ flate2 = { workspace = true }
|
|||
fnv = { workspace = true }
|
||||
im = { workspace = true, features = ["rayon", "serde"] }
|
||||
index_list = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
|
|
@ -470,7 +470,7 @@ pub mod tests {
|
|||
hot::{HotAccountMeta, HotStorageReader},
|
||||
index::{AccountIndexWriterEntry, IndexBlockFormat, IndexOffset},
|
||||
meta::{AccountMetaFlags, AccountMetaOptionalFields, TieredAccountMeta},
|
||||
owners::OwnersBlockFormat,
|
||||
owners::{OwnersBlockFormat, OwnersTable},
|
||||
},
|
||||
assert_matches::assert_matches,
|
||||
memoffset::offset_of,
|
||||
|
@ -823,9 +823,13 @@ pub mod tests {
|
|||
{
|
||||
let file = TieredStorageFile::new_writable(&path).unwrap();
|
||||
|
||||
let mut owners_table = OwnersTable::default();
|
||||
addresses.iter().for_each(|owner_address| {
|
||||
owners_table.insert(owner_address);
|
||||
});
|
||||
footer
|
||||
.owners_block_format
|
||||
.write_owners_block(&file, &addresses)
|
||||
.write_owners_block(&file, &owners_table)
|
||||
.unwrap();
|
||||
|
||||
// while the test only focuses on account metas, writing a footer
|
||||
|
@ -893,9 +897,13 @@ pub mod tests {
|
|||
// the owners_block_offset set to the end of the accounts blocks.
|
||||
footer.owners_block_offset = footer.index_block_offset;
|
||||
|
||||
let mut owners_table = OwnersTable::default();
|
||||
owner_addresses.iter().for_each(|owner_address| {
|
||||
owners_table.insert(owner_address);
|
||||
});
|
||||
footer
|
||||
.owners_block_format
|
||||
.write_owners_block(&file, &owner_addresses)
|
||||
.write_owners_block(&file, &owners_table)
|
||||
.unwrap();
|
||||
|
||||
// while the test only focuses on account metas, writing a footer
|
||||
|
@ -1029,9 +1037,13 @@ pub mod tests {
|
|||
|
||||
// write owners block
|
||||
footer.owners_block_offset = current_offset as u64;
|
||||
let mut owners_table = OwnersTable::default();
|
||||
owners.iter().for_each(|owner_address| {
|
||||
owners_table.insert(owner_address);
|
||||
});
|
||||
footer
|
||||
.owners_block_format
|
||||
.write_owners_block(&file, &owners)
|
||||
.write_owners_block(&file, &owners_table)
|
||||
.unwrap();
|
||||
|
||||
footer.write_footer_block(&file).unwrap();
|
||||
|
|
|
@ -3,6 +3,7 @@ use {
|
|||
file::TieredStorageFile, footer::TieredStorageFooter, mmap_utils::get_pod,
|
||||
TieredStorageResult,
|
||||
},
|
||||
indexmap::set::IndexSet,
|
||||
memmap2::Mmap,
|
||||
solana_sdk::pubkey::Pubkey,
|
||||
};
|
||||
|
@ -43,13 +44,13 @@ impl OwnersBlockFormat {
|
|||
pub fn write_owners_block(
|
||||
&self,
|
||||
file: &TieredStorageFile,
|
||||
addresses: &[Pubkey],
|
||||
owners_table: &OwnersTable,
|
||||
) -> TieredStorageResult<usize> {
|
||||
match self {
|
||||
Self::AddressesOnly => {
|
||||
let mut bytes_written = 0;
|
||||
for address in addresses {
|
||||
bytes_written += file.write_pod(address)?;
|
||||
for address in &owners_table.owners_set {
|
||||
bytes_written += file.write_pod(*address)?;
|
||||
}
|
||||
|
||||
Ok(bytes_written)
|
||||
|
@ -77,6 +78,27 @@ impl OwnersBlockFormat {
|
|||
}
|
||||
}
|
||||
|
||||
/// The in-memory representation of owners block for write.
|
||||
/// It manages a set of unique addresses of account owners.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct OwnersTable<'a> {
|
||||
owners_set: IndexSet<&'a Pubkey>,
|
||||
}
|
||||
|
||||
/// 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<'a> OwnersTable<'a> {
|
||||
/// Add the specified pubkey as the owner into the OwnersWriterTable
|
||||
/// if the specified pubkey has not existed in the OwnersWriterTable
|
||||
/// yet. In any case, the function returns its OwnerOffset.
|
||||
pub fn insert(&mut self, pubkey: &'a Pubkey) -> OwnerOffset {
|
||||
let (offset, _existed) = self.owners_set.insert_full(pubkey);
|
||||
|
||||
OwnerOffset(offset as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {
|
||||
|
@ -105,9 +127,13 @@ mod tests {
|
|||
{
|
||||
let file = TieredStorageFile::new_writable(&path).unwrap();
|
||||
|
||||
let mut owners_table = OwnersTable::default();
|
||||
addresses.iter().for_each(|owner_address| {
|
||||
owners_table.insert(owner_address);
|
||||
});
|
||||
footer
|
||||
.owners_block_format
|
||||
.write_owners_block(&file, &addresses)
|
||||
.write_owners_block(&file, &owners_table)
|
||||
.unwrap();
|
||||
|
||||
// while the test only focuses on account metas, writing a footer
|
||||
|
@ -128,4 +154,31 @@ mod tests {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_owners_table() {
|
||||
let mut owners_table = OwnersTable::default();
|
||||
const NUM_OWNERS: usize = 99;
|
||||
|
||||
let addresses: Vec<_> = std::iter::repeat_with(Pubkey::new_unique)
|
||||
.take(NUM_OWNERS)
|
||||
.collect();
|
||||
|
||||
// as we insert sequentially, we expect each entry has same OwnerOffset
|
||||
// as its index inside the Vector.
|
||||
for (i, address) in addresses.iter().enumerate() {
|
||||
assert_eq!(owners_table.insert(address), OwnerOffset(i as u32));
|
||||
}
|
||||
|
||||
let cloned_addresses = addresses.clone();
|
||||
|
||||
// insert again and expect the same OwnerOffset
|
||||
for (i, address) in cloned_addresses.iter().enumerate() {
|
||||
assert_eq!(owners_table.insert(address), OwnerOffset(i as u32));
|
||||
}
|
||||
|
||||
// make sure the size of the resulting owner table is the same
|
||||
// as the input
|
||||
assert_eq!(owners_table.owners_set.len(), addresses.len());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4672,6 +4672,7 @@ dependencies = [
|
|||
"fnv",
|
||||
"im",
|
||||
"index_list",
|
||||
"indexmap 2.1.0",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"log",
|
||||
|
|
Loading…
Reference in New Issue