From 185470c9c11d9c94d26b6d442a0092d73691a339 Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" Date: Mon, 2 Jan 2023 09:09:53 -0600 Subject: [PATCH] add test_shrink_ancient_overflow (#29363) --- runtime/src/accounts_db.rs | 85 ++++++++++++++++++++++++++++++++++++++ runtime/src/append_vec.rs | 4 ++ 2 files changed, 89 insertions(+) diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index b9197dd3bcd2eb..8d526982da87f0 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -17398,6 +17398,83 @@ pub mod tests { ); } + #[test] + fn test_shrink_ancient_overflow() { + solana_logger::setup(); + + let num_normal_slots = 2; + // build an ancient append vec at slot 'ancient_slot' + let (db, ancient_slot) = get_one_ancient_append_vec_and_others(true, num_normal_slots); + + let max_slot_inclusive = ancient_slot + (num_normal_slots as Slot); + let initial_accounts = get_all_accounts(&db, ancient_slot..(max_slot_inclusive + 1)); + + let ancient = db + .get_storages_for_slot(ancient_slot) + .unwrap() + .first() + .unwrap() + .clone(); + let initial_len = ancient.alive_bytes(); + // set size of ancient to be 'full' + adjust_append_vec_len_for_tests(&ancient, ancient.accounts.capacity() as usize); + + // combine 1 normal append vec into existing ancient append vec + // this will overflow the original ancient append vec because of the marking full above + db.combine_ancient_slots( + (ancient_slot..max_slot_inclusive).collect(), + CAN_RANDOMLY_SHRINK_FALSE, + ); + + // Restore size of ancient so we don't read garbage accounts when comparing. Now that we have created a second ancient append vec, + // This first one is happy to be quite empty. + adjust_append_vec_len_for_tests(&ancient, initial_len); + + compare_all_accounts( + &initial_accounts, + &get_all_accounts(&db, ancient_slot..max_slot_inclusive), + ); + + // the append vec at max_slot_inclusive-1 should NOT have been removed since we created an ancient append vec there + assert!(is_ancient( + &db.get_storages_for_slot(max_slot_inclusive - 1) + .unwrap() + .first() + .unwrap() + .accounts + )); + + // combine normal append vec(s) into existing ancient append vec + // this will overflow the original ancient append vec because of the marking full above + db.combine_ancient_slots( + (ancient_slot..=max_slot_inclusive).collect(), + CAN_RANDOMLY_SHRINK_FALSE, + ); + + // now, combine the next slot into the one that was just overflow + compare_all_accounts( + &initial_accounts, + &get_all_accounts(&db, ancient_slot..(max_slot_inclusive + 1)), + ); + + // 2 ancients and then missing (because combined into 2nd ancient) + assert!(is_ancient( + &db.get_storages_for_slot(ancient_slot) + .unwrap() + .first() + .unwrap() + .accounts + )); + assert!(is_ancient( + &db.get_storages_for_slot(max_slot_inclusive - 1) + .unwrap() + .first() + .unwrap() + .accounts + )); + assert!(db.get_storages_for_slot(max_slot_inclusive).is_none()); + } + #[test] fn test_shrink_ancient() { solana_logger::setup(); @@ -17910,11 +17987,19 @@ pub mod tests { storage.alive_bytes.store(alive_bytes, Ordering::Release); } + /// cause 'ancient' to appear to contain 'len' bytes + fn adjust_append_vec_len_for_tests(ancient: &Arc, len: usize) { + assert!(is_ancient(&ancient.accounts)); + ancient.accounts.set_current_len_for_tests(len); + adjust_alive_bytes(ancient, len); + } + fn make_ancient_append_vec_full(ancient: &Arc) { let vecs = vec![vec![ancient.clone()]]; for _ in 0..100 { append_sample_data_to_storage(&vecs, &Pubkey::default(), 0); } + // since we're not adding to the index, this is how we specify that all these accounts are alive adjust_alive_bytes(ancient, ancient.total_bytes() as usize); } diff --git a/runtime/src/append_vec.rs b/runtime/src/append_vec.rs index a17f3766120300..9951b19b2edf1c 100644 --- a/runtime/src/append_vec.rs +++ b/runtime/src/append_vec.rs @@ -709,6 +709,10 @@ pub mod tests { }; impl AppendVec { + pub(crate) fn set_current_len_for_tests(&self, len: usize) { + self.current_len.store(len, Ordering::Release); + } + fn append_account_test(&self, data: &(StoredMeta, AccountSharedData)) -> Option { let slot_ignored = Slot::MAX; let accounts = [(&data.0.pubkey, &data.1)];