Remove accounts when the fork is removed (#3384)
* Fix test * Cleanup accounts when the fork is removed * Update test to check for deleted accounts
This commit is contained in:
parent
dbb145c266
commit
06b0c98c75
|
@ -704,7 +704,8 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handle_new_root() {
|
fn test_handle_new_root() {
|
||||||
let bank0 = Bank::default();
|
let genesis_block = GenesisBlock::new(10_000).0;
|
||||||
|
let bank0 = Bank::new(&genesis_block);
|
||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank0)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank0)));
|
||||||
let mut progress = HashMap::new();
|
let mut progress = HashMap::new();
|
||||||
progress.insert(5, (Hash::default(), 0));
|
progress.insert(5, (Hash::default(), 0));
|
||||||
|
|
|
@ -395,10 +395,14 @@ impl AccountsDB {
|
||||||
|
|
||||||
fn load(&self, fork: Fork, pubkey: &Pubkey, walk_back: bool) -> Option<Account> {
|
fn load(&self, fork: Fork, pubkey: &Pubkey, walk_back: bool) -> Option<Account> {
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
let account_map = account_maps.get(&fork).unwrap().read().unwrap();
|
if let Some(account_map) = account_maps.get(&fork) {
|
||||||
|
let account_map = account_map.read().unwrap();
|
||||||
if let Some(account_info) = account_map.get(&pubkey) {
|
if let Some(account_info) = account_map.get(&pubkey) {
|
||||||
return Some(self.get_account(account_info.id, account_info.offset));
|
return Some(self.get_account(account_info.id, account_info.offset));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if !walk_back {
|
if !walk_back {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -546,6 +550,24 @@ impl AccountsDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_accounts(&self, fork: Fork) {
|
||||||
|
let mut account_maps = self.account_index.account_maps.write().unwrap();
|
||||||
|
{
|
||||||
|
let mut account_map = account_maps.get(&fork).unwrap().write().unwrap();
|
||||||
|
let stores = self.storage.read().unwrap();
|
||||||
|
for (_, account_info) in account_map.iter() {
|
||||||
|
stores[account_info.id].remove_account();
|
||||||
|
}
|
||||||
|
account_map.clear();
|
||||||
|
}
|
||||||
|
account_maps.remove(&fork);
|
||||||
|
let mut fork_infos = self.fork_infos.write().unwrap();
|
||||||
|
for (_, fork_info) in fork_infos.iter_mut() {
|
||||||
|
fork_info.parents.retain(|parent_fork| *parent_fork != fork);
|
||||||
|
}
|
||||||
|
fork_infos.remove(&fork);
|
||||||
|
}
|
||||||
|
|
||||||
/// Store the account update.
|
/// Store the account update.
|
||||||
pub fn store(&self, fork: Fork, pubkey: &Pubkey, account: &Account) {
|
pub fn store(&self, fork: Fork, pubkey: &Pubkey, account: &Account) {
|
||||||
if account.lamports == 0 && self.is_squashed(fork) {
|
if account.lamports == 0 && self.is_squashed(fork) {
|
||||||
|
@ -955,6 +977,10 @@ impl Accounts {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, acc)| acc.lamports != 0)
|
.filter(|(_, acc)| acc.lamports != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_accounts(&self, fork: Fork) {
|
||||||
|
self.accounts_db.remove_accounts(fork);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1458,7 +1484,7 @@ mod tests {
|
||||||
let db = AccountsDB::new(0, &paths.paths);
|
let db = AccountsDB::new(0, &paths.paths);
|
||||||
|
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
create_account(&db, &mut pubkeys, 100, 0);
|
create_account(&db, &mut pubkeys, 0, 100, 0);
|
||||||
for _ in 1..100 {
|
for _ in 1..100 {
|
||||||
let idx = thread_rng().gen_range(0, 99);
|
let idx = thread_rng().gen_range(0, 99);
|
||||||
let account = db.load(0, &pubkeys[idx], true).unwrap();
|
let account = db.load(0, &pubkeys[idx], true).unwrap();
|
||||||
|
@ -1527,6 +1553,7 @@ mod tests {
|
||||||
fn create_account(
|
fn create_account(
|
||||||
accounts: &AccountsDB,
|
accounts: &AccountsDB,
|
||||||
pubkeys: &mut Vec<Pubkey>,
|
pubkeys: &mut Vec<Pubkey>,
|
||||||
|
fork: Fork,
|
||||||
num: usize,
|
num: usize,
|
||||||
num_vote: usize,
|
num_vote: usize,
|
||||||
) {
|
) {
|
||||||
|
@ -1535,8 +1562,8 @@ mod tests {
|
||||||
let mut default_account = Account::default();
|
let mut default_account = Account::default();
|
||||||
pubkeys.push(pubkey.clone());
|
pubkeys.push(pubkey.clone());
|
||||||
default_account.lamports = (t + 1) as u64;
|
default_account.lamports = (t + 1) as u64;
|
||||||
assert!(accounts.load(0, &pubkey, true).is_none());
|
assert!(accounts.load(fork, &pubkey, true).is_none());
|
||||||
accounts.store(0, &pubkey, &default_account);
|
accounts.store(fork, &pubkey, &default_account);
|
||||||
}
|
}
|
||||||
for t in 0..num_vote {
|
for t in 0..num_vote {
|
||||||
let pubkey = Keypair::new().pubkey();
|
let pubkey = Keypair::new().pubkey();
|
||||||
|
@ -1544,19 +1571,19 @@ mod tests {
|
||||||
pubkeys.push(pubkey.clone());
|
pubkeys.push(pubkey.clone());
|
||||||
default_account.owner = solana_vote_api::id();
|
default_account.owner = solana_vote_api::id();
|
||||||
default_account.lamports = (num + t + 1) as u64;
|
default_account.lamports = (num + t + 1) as u64;
|
||||||
assert!(accounts.load(0, &pubkey, true).is_none());
|
assert!(accounts.load(fork, &pubkey, true).is_none());
|
||||||
accounts.store(0, &pubkey, &default_account);
|
accounts.store(fork, &pubkey, &default_account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_accounts(accounts: &AccountsDB, pubkeys: Vec<Pubkey>, range: usize) {
|
fn update_accounts(accounts: &AccountsDB, pubkeys: &Vec<Pubkey>, fork: Fork, range: usize) {
|
||||||
for _ in 1..1000 {
|
for _ in 1..1000 {
|
||||||
let idx = thread_rng().gen_range(0, range);
|
let idx = thread_rng().gen_range(0, range);
|
||||||
if let Some(mut account) = accounts.load(0, &pubkeys[idx], true) {
|
if let Some(mut account) = accounts.load(fork, &pubkeys[idx], true) {
|
||||||
account.lamports = account.lamports + 1;
|
account.lamports = account.lamports + 1;
|
||||||
accounts.store(0, &pubkeys[idx], &account);
|
accounts.store(fork, &pubkeys[idx], &account);
|
||||||
if account.lamports == 0 {
|
if account.lamports == 0 {
|
||||||
assert!(accounts.load(0, &pubkeys[idx], true).is_none());
|
assert!(accounts.load(fork, &pubkeys[idx], true).is_none());
|
||||||
} else {
|
} else {
|
||||||
let mut default_account = Account::default();
|
let mut default_account = Account::default();
|
||||||
default_account.lamports = account.lamports;
|
default_account.lamports = account.lamports;
|
||||||
|
@ -1577,12 +1604,39 @@ mod tests {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_storage(accounts: &AccountsDB, count: usize) -> bool {
|
||||||
|
let stores = accounts.storage.read().unwrap();
|
||||||
|
assert_eq!(stores.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
stores[0].get_status(),
|
||||||
|
AccountStorageStatus::StorageAvailable
|
||||||
|
);
|
||||||
|
stores[0].count.load(Ordering::Relaxed) == count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_accounts(accounts: &AccountsDB, pubkeys: &Vec<Pubkey>, fork: Fork) {
|
||||||
|
for _ in 1..100 {
|
||||||
|
let idx = thread_rng().gen_range(0, 99);
|
||||||
|
let account = accounts.load(fork, &pubkeys[idx], true).unwrap();
|
||||||
|
let mut default_account = Account::default();
|
||||||
|
default_account.lamports = (idx + 1) as u64;
|
||||||
|
assert_eq!(compare_account(&default_account, &account), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_removed_accounts(accounts: &AccountsDB, pubkeys: &Vec<Pubkey>, fork: Fork) {
|
||||||
|
for _ in 1..100 {
|
||||||
|
let idx = thread_rng().gen_range(0, 99);
|
||||||
|
assert!(accounts.load(fork, &pubkeys[idx], true).is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_account_one() {
|
fn test_account_one() {
|
||||||
let paths = get_tmp_accounts_path!();
|
let paths = get_tmp_accounts_path!();
|
||||||
let accounts = AccountsDB::new(0, &paths.paths);
|
let accounts = AccountsDB::new(0, &paths.paths);
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
create_account(&accounts, &mut pubkeys, 1, 0);
|
create_account(&accounts, &mut pubkeys, 0, 1, 0);
|
||||||
let account = accounts.load(0, &pubkeys[0], true).unwrap();
|
let account = accounts.load(0, &pubkeys[0], true).unwrap();
|
||||||
let mut default_account = Account::default();
|
let mut default_account = Account::default();
|
||||||
default_account.lamports = 1;
|
default_account.lamports = 1;
|
||||||
|
@ -1594,14 +1648,8 @@ mod tests {
|
||||||
let paths = get_tmp_accounts_path("many0,many1");
|
let paths = get_tmp_accounts_path("many0,many1");
|
||||||
let accounts = AccountsDB::new(0, &paths.paths);
|
let accounts = AccountsDB::new(0, &paths.paths);
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
create_account(&accounts, &mut pubkeys, 100, 0);
|
create_account(&accounts, &mut pubkeys, 0, 100, 0);
|
||||||
for _ in 1..100 {
|
check_accounts(&accounts, &pubkeys, 0);
|
||||||
let idx = thread_rng().gen_range(0, 99);
|
|
||||||
let account = accounts.load(0, &pubkeys[idx], true).unwrap();
|
|
||||||
let mut default_account = Account::default();
|
|
||||||
default_account.lamports = (idx + 1) as u64;
|
|
||||||
assert_eq!(compare_account(&default_account, &account), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1609,17 +1657,9 @@ mod tests {
|
||||||
let paths = get_tmp_accounts_path!();
|
let paths = get_tmp_accounts_path!();
|
||||||
let accounts = AccountsDB::new(0, &paths.paths);
|
let accounts = AccountsDB::new(0, &paths.paths);
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
create_account(&accounts, &mut pubkeys, 100, 0);
|
create_account(&accounts, &mut pubkeys, 0, 100, 0);
|
||||||
update_accounts(&accounts, pubkeys, 99);
|
update_accounts(&accounts, &pubkeys, 0, 99);
|
||||||
{
|
assert_eq!(check_storage(&accounts, 100), true);
|
||||||
let stores = accounts.storage.read().unwrap();
|
|
||||||
assert_eq!(stores.len(), 1);
|
|
||||||
assert_eq!(stores[0].count.load(Ordering::Relaxed), 100);
|
|
||||||
assert_eq!(
|
|
||||||
stores[0].get_status(),
|
|
||||||
AccountStorageStatus::StorageAvailable
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1703,6 +1743,32 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_accounts_remove() {
|
||||||
|
let paths = get_tmp_accounts_path!();
|
||||||
|
let accounts = AccountsDB::new(0, &paths.paths);
|
||||||
|
let mut pubkeys0: Vec<Pubkey> = vec![];
|
||||||
|
create_account(&accounts, &mut pubkeys0, 0, 100, 0);
|
||||||
|
assert_eq!(check_storage(&accounts, 100), true);
|
||||||
|
accounts.add_fork(1, Some(0));
|
||||||
|
let mut pubkeys1: Vec<Pubkey> = vec![];
|
||||||
|
create_account(&accounts, &mut pubkeys1, 1, 100, 0);
|
||||||
|
assert_eq!(check_storage(&accounts, 200), true);
|
||||||
|
accounts.remove_accounts(0);
|
||||||
|
check_accounts(&accounts, &pubkeys1, 1);
|
||||||
|
check_removed_accounts(&accounts, &pubkeys0, 0);
|
||||||
|
assert_eq!(check_storage(&accounts, 100), true);
|
||||||
|
accounts.add_fork(2, Some(1));
|
||||||
|
let mut pubkeys2: Vec<Pubkey> = vec![];
|
||||||
|
create_account(&accounts, &mut pubkeys2, 2, 100, 0);
|
||||||
|
assert_eq!(check_storage(&accounts, 200), true);
|
||||||
|
accounts.remove_accounts(1);
|
||||||
|
check_accounts(&accounts, &pubkeys2, 2);
|
||||||
|
assert_eq!(check_storage(&accounts, 100), true);
|
||||||
|
accounts.remove_accounts(2);
|
||||||
|
assert_eq!(check_storage(&accounts, 0), true);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_accounts_vote_filter() {
|
fn test_accounts_vote_filter() {
|
||||||
let accounts = Accounts::new(0, None);
|
let accounts = Accounts::new(0, None);
|
||||||
|
@ -1744,7 +1810,7 @@ mod tests {
|
||||||
let paths = get_tmp_accounts_path!();
|
let paths = get_tmp_accounts_path!();
|
||||||
let accounts_db = AccountsDB::new(0, &paths.paths);
|
let accounts_db = AccountsDB::new(0, &paths.paths);
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
create_account(&accounts_db, &mut pubkeys, 0, 1);
|
create_account(&accounts_db, &mut pubkeys, 0, 0, 1);
|
||||||
let accounts = accounts_db.get_vote_accounts(0);
|
let accounts = accounts_db.get_vote_accounts(0);
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
accounts.iter().for_each(|(_, account)| {
|
accounts.iter().for_each(|(_, account)| {
|
||||||
|
|
|
@ -912,6 +912,12 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Bank {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.accounts.remove_accounts(self.accounts_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue