Check for deleting key, make sure list is empty again (#11007)

This commit is contained in:
sakridge 2020-07-11 20:38:34 -07:00 committed by GitHub
parent 12d188da09
commit edf2b1ee85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 18 deletions

View File

@ -39,6 +39,7 @@ use solana_sdk::{
use std::{
collections::{HashMap, HashSet},
io::{Error as IOError, Result as IOResult},
iter::FromIterator,
ops::RangeBounds,
path::{Path, PathBuf},
sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
@ -630,12 +631,30 @@ impl AccountsDB {
}
}
fn purge_keys_exact(
&self,
pubkey_to_slot_set: Vec<(Pubkey, HashSet<Slot>)>,
) -> (Vec<(u64, AccountInfo)>, Vec<Pubkey>) {
let mut reclaims = Vec::new();
let mut dead_keys = Vec::new();
let accounts_index = self.accounts_index.read().unwrap();
for (pubkey, slots_set) in pubkey_to_slot_set {
let (new_reclaims, is_empty) = accounts_index.purge_exact(&pubkey, slots_set);
if is_empty {
dead_keys.push(pubkey);
}
reclaims.extend(new_reclaims);
}
(reclaims, dead_keys)
}
// Purge zero lamport accounts and older rooted account states as garbage
// collection
// Only remove those accounts where the entire rooted history of the account
// can be purged because there are no live append vecs in the ancestors
pub fn clean_accounts(&self) {
use std::iter::FromIterator;
self.report_store_stats();
let mut accounts_scan = Measure::start("accounts_scan");
@ -730,27 +749,13 @@ impl AccountsDB {
)
})
.collect();
let accounts_index = self.accounts_index.read().unwrap();
let mut reclaims = Vec::new();
let mut dead_keys = Vec::new();
for (pubkey, slots_set) in pubkey_to_slot_set {
let (new_reclaims, is_empty) = accounts_index.purge_exact(&pubkey, slots_set);
if is_empty {
dead_keys.push(pubkey);
}
reclaims.extend(new_reclaims);
}
drop(accounts_index);
let (reclaims, dead_keys) = self.purge_keys_exact(pubkey_to_slot_set);
if !dead_keys.is_empty() {
let mut accounts_index = self.accounts_index.write().unwrap();
for key in &dead_keys {
accounts_index.account_maps.remove(key);
}
}
self.handle_dead_keys(dead_keys);
self.handle_reclaims_maybe_cleanup(&reclaims);
reclaims_time.stop();
datapoint_info!(
"clean_accounts",
@ -762,6 +767,19 @@ impl AccountsDB {
);
}
fn handle_dead_keys(&self, dead_keys: Vec<Pubkey>) {
if !dead_keys.is_empty() {
let mut accounts_index = self.accounts_index.write().unwrap();
for key in &dead_keys {
if let Some((_ref_count, list)) = accounts_index.account_maps.get(key) {
if list.read().unwrap().is_empty() {
accounts_index.account_maps.remove(key);
}
}
}
}
}
fn handle_reclaims_maybe_cleanup(&self, reclaims: SlotSlice<AccountInfo>) {
let mut dead_accounts = Measure::start("reclaims::remove_dead_accounts");
let dead_slots = self.remove_dead_accounts(reclaims);
@ -3235,6 +3253,37 @@ pub mod tests {
assert_eq!(accounts.len(), 2);
}
#[test]
fn test_cleanup_key_not_removed() {
solana_logger::setup();
let db = AccountsDB::new_single();
let key = Pubkey::default();
let key0 = Pubkey::new_rand();
let account0 = Account::new(1, 0, &key);
db.store(0, &[(&key0, &account0)]);
let key1 = Pubkey::new_rand();
let account1 = Account::new(2, 0, &key);
db.store(1, &[(&key1, &account1)]);
db.print_accounts_stats("pre");
let slots: HashSet<Slot> = HashSet::from_iter(vec![1].into_iter());
let purge_keys = vec![(key1, slots)];
let (_reclaims, dead_keys) = db.purge_keys_exact(purge_keys);
let account2 = Account::new(3, 0, &key);
db.store(2, &[(&key1, &account2)]);
db.handle_dead_keys(dead_keys);
db.print_accounts_stats("post");
let ancestors = vec![(2, 0)].into_iter().collect();
assert_eq!(db.load_slow(&ancestors, &key1).unwrap().0.lamports, 3);
}
#[test]
fn test_store_large_account() {
solana_logger::setup();