-
Notifications
You must be signed in to change notification settings - Fork 757
Implement serialize/deserialize for obsolete accounts #8414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
9997967
c4bcf2f
27fd90b
1d8843e
db5e1c7
e1ecfbc
516d9df
053ca4d
9bb7a1e
391fe73
d24ef21
8634ddd
7592bb5
a08ef30
94d0722
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,7 +47,7 @@ pub mod waitable_condvar; | |
|
||
pub use { | ||
buffered_reader::large_file_buf_reader, file_io::validate_memlock_limit_for_disk_io, | ||
obsolete_accounts::ObsoleteAccounts, | ||
obsolete_accounts::{ObsoleteAccounts, ObsoleteAccountItem}, | ||
|
||
}; | ||
|
||
#[macro_use] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
use {crate::account_info::Offset, solana_clock::Slot}; | ||
|
||
#[derive(Debug, Clone, PartialEq)] | ||
struct ObsoleteAccountItem { | ||
pub struct ObsoleteAccountItem { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same, public for access in storage.rs |
||
/// Offset of the account in the account storage entry | ||
offset: Offset, | ||
pub offset: Offset, | ||
/// Length of the account data | ||
data_len: usize, | ||
pub data_len: usize, | ||
/// Slot when the account was marked obsolete | ||
slot: Slot, | ||
pub slot: Slot, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Default)] | ||
pub struct ObsoleteAccounts { | ||
accounts: Vec<ObsoleteAccountItem>, | ||
pub accounts: Vec<ObsoleteAccountItem>, | ||
} | ||
|
||
impl ObsoleteAccounts { | ||
|
@@ -45,6 +45,22 @@ impl ObsoleteAccounts { | |
.filter(move |obsolete_account| slot.is_none_or(|s| obsolete_account.slot <= s)) | ||
.map(|obsolete_account| (obsolete_account.offset, obsolete_account.data_len)) | ||
} | ||
|
||
/// Returns the accounts that were marked obsolete as of the passed in slot | ||
/// or earlier. Returned data includes the slots that the accounts were marked | ||
/// obsolete at | ||
pub fn obsolete_accounts_for_snapshots(&self, slot: Slot) -> ObsoleteAccounts { | ||
let filtered_accounts = self | ||
.accounts | ||
.iter() | ||
.filter(|account| account.slot <= slot) | ||
.cloned() | ||
.collect(); | ||
|
||
ObsoleteAccounts { | ||
accounts: filtered_accounts, | ||
} | ||
} | ||
} | ||
#[cfg(test)] | ||
mod tests { | ||
|
@@ -99,4 +115,39 @@ mod tests { | |
|
||
assert_eq!(filtered_accounts, vec![(10, 100), (20, 200), (30, 300)]); | ||
} | ||
|
||
#[test] | ||
fn test_obsolete_accounts_for_snapshots() { | ||
let mut obsolete_accounts = ObsoleteAccounts::default(); | ||
let new_accounts = vec![(10, 100, 40), (20, 200, 42), (30, 300, 44)] | ||
.into_iter() | ||
.map(|(offset, data_len, slot)| ObsoleteAccountItem { | ||
offset, | ||
data_len, | ||
slot, | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
// Mark accounts obsolete with different slots | ||
new_accounts.iter().for_each(|item| { | ||
obsolete_accounts | ||
.mark_accounts_obsolete([(item.offset, item.data_len)].into_iter(), item.slot) | ||
}); | ||
|
||
// Filter accounts obsolete as of slot 42 | ||
let obsolete_accounts_for_snapshots = obsolete_accounts.obsolete_accounts_for_snapshots(42); | ||
|
||
let expected_accounts: Vec<_> = new_accounts | ||
.iter() | ||
.filter(|account| account.slot <= 42) | ||
.cloned() | ||
.collect(); | ||
|
||
assert_eq!(obsolete_accounts_for_snapshots.accounts, expected_accounts); | ||
|
||
// Filter accounts obsolete passing in no slot (i.e., all obsolete accounts) | ||
let obsolete_accounts_for_snapshots = obsolete_accounts.obsolete_accounts_for_snapshots(100); | ||
|
||
assert_eq!(obsolete_accounts_for_snapshots.accounts, new_accounts); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11,6 +11,7 @@ use { | |||||
stakes::{serialize_stake_accounts_to_delegation_format, Stakes}, | ||||||
}, | ||||||
bincode::{self, config::Options, Error}, | ||||||
dashmap::DashMap, | ||||||
log::*, | ||||||
serde::{de::DeserializeOwned, Deserialize, Serialize}, | ||||||
solana_accounts_db::{ | ||||||
|
@@ -24,7 +25,7 @@ use { | |||||
accounts_update_notifier_interface::AccountsUpdateNotifier, | ||||||
ancestors::AncestorsForSerialization, | ||||||
blockhash_queue::BlockhashQueue, | ||||||
ObsoleteAccounts, | ||||||
ObsoleteAccountItem, ObsoleteAccounts, | ||||||
}, | ||||||
solana_clock::{Epoch, Slot, UnixTimestamp}, | ||||||
solana_epoch_schedule::EpochSchedule, | ||||||
|
@@ -58,7 +59,7 @@ mod status_cache; | |||||
mod storage; | ||||||
mod tests; | ||||||
mod types; | ||||||
mod utils; | ||||||
pub mod utils; | ||||||
brooksprumo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
||||||
pub(crate) use { | ||||||
status_cache::{deserialize_status_cache, serialize_status_cache}, | ||||||
|
@@ -649,6 +650,34 @@ where | |||||
(serializable_bank, serializable_accounts_db, extra_fields).serialize(serializer) | ||||||
} | ||||||
|
||||||
pub(crate) fn serialize_obsolete_accounts<W>( | ||||||
|
||||||
stream: &mut BufWriter<W>, | ||||||
obsolete_accounts_map: &HashMap<Slot, SerdeObsoleteAccounts>, | ||||||
) -> Result<(), Error> | ||||||
where | ||||||
W: Write, | ||||||
{ | ||||||
let bincode = bincode::DefaultOptions::new().with_fixint_encoding(); | ||||||
bincode.serialize_into( | ||||||
stream, | ||||||
&utils::serialize_iter_as_tuple(obsolete_accounts_map.iter()), | ||||||
|
&utils::serialize_iter_as_tuple(obsolete_accounts_map.iter()), | |
obsolete_accounts_map, |
Minimally clippy is happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If clippy is happy, it probably works!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it out, it doesn't work:
It is because it is being serialized as a hashmap and deserialized as a dashmap.
I could use a dashmap on the serialization side, but dashmaps do not suppot serialize/deseralize, so it would need something like serialize_iter_as_tuple anyways in that situation.
Dashmap is definitely needed on the deserialize size as performance testing found. It could be deseralized as a hashmap and then converted to a dashmap, but that seems less efficient.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a serde
feature for DashMap. I haven't used it before. Maybe it'll work here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But otherwise, yeah I agree with you. Probably don't want to do extra allocations/conversions unnecessarily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passes testing. I will check performance in a bit
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this will swallow any real errors too?
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdyt
let accounts = ObsoleteAccounts { | |
let obsolete_accounts = ObsoleteAccounts { |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,8 +4,10 @@ mod serde_snapshot_tests { | |||||
crate::{ | ||||||
bank::BankHashStats, | ||||||
serde_snapshot::{ | ||||||
deserialize_accounts_db_fields, reconstruct_accountsdb_from_fields, | ||||||
remap_append_vec_file, SerializableAccountsDb, SnapshotAccountsDbFields, | ||||||
deserialize_accounts_db_fields, deserialize_obsolete_accounts, | ||||||
reconstruct_accountsdb_from_fields, remap_append_vec_file, | ||||||
serialize_obsolete_accounts, SerdeObsoleteAccounts, SerializableAccountsDb, | ||||||
SnapshotAccountsDbFields, | ||||||
}, | ||||||
snapshot_utils::{get_storages_to_serialize, StorageAndNextAccountsFileId}, | ||||||
}, | ||||||
|
@@ -30,8 +32,9 @@ mod serde_snapshot_tests { | |||||
solana_nohash_hasher::BuildNoHashHasher, | ||||||
solana_pubkey::Pubkey, | ||||||
std::{ | ||||||
collections::HashMap, | ||||||
fs::File, | ||||||
io::{self, BufReader, Cursor, Read, Write}, | ||||||
io::{self, BufReader, BufWriter, Cursor, Read, Write}, | ||||||
ops::RangeFull, | ||||||
path::{Path, PathBuf}, | ||||||
sync::{ | ||||||
|
@@ -937,4 +940,48 @@ mod serde_snapshot_tests { | |||||
) | ||||||
.unwrap(); | ||||||
} | ||||||
|
||||||
#[test_case(0, 0)] | ||||||
#[test_case(1, 0)] | ||||||
#[test_case(10, 15)] | ||||||
fn test_serialize_and_deserialize_obsolete_accounts( | ||||||
|
||||||
num_storages: u64, | ||||||
num_accounts_per_storage: usize, | ||||||
|
num_accounts_per_storage: usize, | |
num_obsolete_accounts_per_storage: usize, |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdyt
let deserialized_accounts = deserialize_obsolete_accounts(&mut reader).unwrap(); | |
let deserialized_obsolete_accounts = deserialize_obsolete_accounts(&mut reader).unwrap(); |
Uh oh!
There was an error while loading. Please reload this page.