Check for deleting key, make sure list is empty again (#11007)
This commit is contained in:
parent
12d188da09
commit
edf2b1ee85
|
@ -39,6 +39,7 @@ use solana_sdk::{
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
io::{Error as IOError, Result as IOResult},
|
io::{Error as IOError, Result as IOResult},
|
||||||
|
iter::FromIterator,
|
||||||
ops::RangeBounds,
|
ops::RangeBounds,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
|
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
|
// Purge zero lamport accounts and older rooted account states as garbage
|
||||||
// collection
|
// collection
|
||||||
// Only remove those accounts where the entire rooted history of the account
|
// 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
|
// can be purged because there are no live append vecs in the ancestors
|
||||||
pub fn clean_accounts(&self) {
|
pub fn clean_accounts(&self) {
|
||||||
use std::iter::FromIterator;
|
|
||||||
self.report_store_stats();
|
self.report_store_stats();
|
||||||
|
|
||||||
let mut accounts_scan = Measure::start("accounts_scan");
|
let mut accounts_scan = Measure::start("accounts_scan");
|
||||||
|
@ -730,27 +749,13 @@ impl AccountsDB {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.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() {
|
self.handle_dead_keys(dead_keys);
|
||||||
let mut accounts_index = self.accounts_index.write().unwrap();
|
|
||||||
for key in &dead_keys {
|
|
||||||
accounts_index.account_maps.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.handle_reclaims_maybe_cleanup(&reclaims);
|
self.handle_reclaims_maybe_cleanup(&reclaims);
|
||||||
|
|
||||||
reclaims_time.stop();
|
reclaims_time.stop();
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"clean_accounts",
|
"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>) {
|
fn handle_reclaims_maybe_cleanup(&self, reclaims: SlotSlice<AccountInfo>) {
|
||||||
let mut dead_accounts = Measure::start("reclaims::remove_dead_accounts");
|
let mut dead_accounts = Measure::start("reclaims::remove_dead_accounts");
|
||||||
let dead_slots = self.remove_dead_accounts(reclaims);
|
let dead_slots = self.remove_dead_accounts(reclaims);
|
||||||
|
@ -3235,6 +3253,37 @@ pub mod tests {
|
||||||
assert_eq!(accounts.len(), 2);
|
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]
|
#[test]
|
||||||
fn test_store_large_account() {
|
fn test_store_large_account() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
Loading…
Reference in New Issue