move vote_accounts up (#3647)
This commit is contained in:
@@ -13,7 +13,6 @@ use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::transaction::Result;
|
||||
use solana_sdk::transaction::{Transaction, TransactionError};
|
||||
use solana_vote_api;
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::fs::{create_dir_all, remove_dir_all};
|
||||
@@ -181,15 +180,6 @@ impl AccountStorageEntry {
|
||||
|
||||
type AccountStorage = Vec<AccountStorageEntry>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct ForkInfo {
|
||||
/// List of all parents of this fork
|
||||
parents: Vec<Fork>,
|
||||
|
||||
/// Cached vote accounts
|
||||
vote_accounts: RwLock<HashMap<Pubkey, Account>>,
|
||||
}
|
||||
|
||||
// This structure handles the load/store of the accounts
|
||||
#[derive(Default)]
|
||||
pub struct AccountsDB {
|
||||
@@ -203,7 +193,7 @@ pub struct AccountsDB {
|
||||
next_id: AtomicUsize,
|
||||
|
||||
/// Information related to the fork
|
||||
fork_infos: RwLock<HashMap<Fork, ForkInfo>>,
|
||||
parents_map: RwLock<HashMap<Fork, Vec<Fork>>>,
|
||||
|
||||
/// Set of storage paths to pick from
|
||||
paths: Vec<String>,
|
||||
@@ -260,7 +250,7 @@ impl AccountsDB {
|
||||
account_index,
|
||||
storage: RwLock::new(vec![]),
|
||||
next_id: AtomicUsize::new(0),
|
||||
fork_infos: RwLock::new(HashMap::new()),
|
||||
parents_map: RwLock::new(HashMap::new()),
|
||||
paths,
|
||||
file_size,
|
||||
inc_size,
|
||||
@@ -276,18 +266,16 @@ impl AccountsDB {
|
||||
|
||||
pub fn add_fork(&self, fork: Fork, parent: Option<Fork>) {
|
||||
{
|
||||
let mut fork_infos = self.fork_infos.write().unwrap();
|
||||
let mut fork_info = ForkInfo::default();
|
||||
let mut parents_map = self.parents_map.write().unwrap();
|
||||
let mut parents = Vec::new();
|
||||
if let Some(parent) = parent {
|
||||
fork_info.parents.push(parent);
|
||||
if let Some(parent_fork_info) = fork_infos.get(&parent) {
|
||||
fork_info
|
||||
.parents
|
||||
.extend_from_slice(&parent_fork_info.parents);
|
||||
parents.push(parent);
|
||||
if let Some(grandparents) = parents_map.get(&parent) {
|
||||
parents.extend_from_slice(&grandparents);
|
||||
}
|
||||
}
|
||||
if let Some(old_fork_info) = fork_infos.insert(fork, fork_info) {
|
||||
panic!("duplicate forks! {} {:?}", fork, old_fork_info);
|
||||
if let Some(old_parents) = parents_map.insert(fork, parents) {
|
||||
panic!("duplicate forks! {} {:?}", fork, old_parents);
|
||||
}
|
||||
}
|
||||
let mut account_maps = self.account_index.account_maps.write().unwrap();
|
||||
@@ -309,45 +297,6 @@ impl AccountsDB {
|
||||
storage.append(&mut stores);
|
||||
}
|
||||
|
||||
fn get_vote_accounts_by_fork(
|
||||
&self,
|
||||
fork: Fork,
|
||||
fork_infos: &HashMap<Fork, ForkInfo>,
|
||||
vote_accounts: &HashMap<Pubkey, Account>,
|
||||
) -> HashMap<Pubkey, Account> {
|
||||
fork_infos
|
||||
.get(&fork)
|
||||
.unwrap()
|
||||
.vote_accounts
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter_map(|(pubkey, account)| {
|
||||
if !vote_accounts.contains_key(pubkey) {
|
||||
Some((*pubkey, account.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_vote_accounts(&self, fork: Fork) -> HashMap<Pubkey, Account> {
|
||||
let mut vote_accounts = HashMap::new();
|
||||
let fork_infos = self.fork_infos.read().unwrap();
|
||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||
vote_accounts = fork_info.vote_accounts.read().unwrap().clone();
|
||||
for parent_fork in fork_info.parents.iter() {
|
||||
let parent_vote_accounts =
|
||||
self.get_vote_accounts_by_fork(*parent_fork, &fork_infos, &vote_accounts);
|
||||
for (pubkey, account) in parent_vote_accounts.iter() {
|
||||
vote_accounts.insert(*pubkey, account.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
vote_accounts
|
||||
}
|
||||
|
||||
pub fn has_accounts(&self, fork: Fork) -> bool {
|
||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||
if let Some(account_map) = account_maps.get(&fork) {
|
||||
@@ -400,10 +349,10 @@ impl AccountsDB {
|
||||
return None;
|
||||
}
|
||||
// find most recent fork that is an ancestor of current_fork
|
||||
let fork_infos = self.fork_infos.read().unwrap();
|
||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||
for parent_fork in fork_info.parents.iter() {
|
||||
if let Some(account_map) = account_maps.get(&parent_fork) {
|
||||
let parents_map = self.parents_map.read().unwrap();
|
||||
if let Some(parents) = parents_map.get(&fork) {
|
||||
for parent in parents.iter() {
|
||||
if let Some(account_map) = account_maps.get(&parent) {
|
||||
let account_map = account_map.read().unwrap();
|
||||
if let Some(account_info) = account_map.get(&pubkey) {
|
||||
return Some(self.get_account(account_info.id, account_info.offset));
|
||||
@@ -443,9 +392,9 @@ impl AccountsDB {
|
||||
if !walk_back {
|
||||
return program_accounts;
|
||||
}
|
||||
let fork_infos = self.fork_infos.read().unwrap();
|
||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||
for parent_fork in fork_info.parents.iter() {
|
||||
let parents_map = self.parents_map.read().unwrap();
|
||||
if let Some(parents) = parents_map.get(&fork) {
|
||||
for parent_fork in parents.iter() {
|
||||
let mut parent_accounts = self.load_program_accounts(*parent_fork, &program_id);
|
||||
program_accounts.append(&mut parent_accounts);
|
||||
}
|
||||
@@ -554,11 +503,11 @@ impl AccountsDB {
|
||||
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);
|
||||
let mut parents_map = self.parents_map.write().unwrap();
|
||||
for (_, parents) in parents_map.iter_mut() {
|
||||
parents.retain(|parent_fork| *parent_fork != fork);
|
||||
}
|
||||
fork_infos.remove(&fork);
|
||||
parents_map.remove(&fork);
|
||||
}
|
||||
|
||||
/// Store the account update.
|
||||
@@ -566,13 +515,6 @@ impl AccountsDB {
|
||||
if account.lamports == 0 && self.is_squashed(fork) {
|
||||
// purge if balance is 0 and no checkpoints
|
||||
self.remove_account_entries(fork, &pubkey);
|
||||
if solana_vote_api::check_id(&account.owner) {
|
||||
let fork_infos = self.fork_infos.read().unwrap();
|
||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||
let mut vote_accounts = fork_info.vote_accounts.write().unwrap();
|
||||
vote_accounts.remove(pubkey);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (id, offset) = self.append_account(account);
|
||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||
@@ -583,13 +525,6 @@ impl AccountsDB {
|
||||
lamports: account.lamports,
|
||||
};
|
||||
self.insert_account_entry(&pubkey, &account_info, &mut account_map);
|
||||
if solana_vote_api::check_id(&account.owner) {
|
||||
let fork_infos = self.fork_infos.read().unwrap();
|
||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||
let mut vote_accounts = fork_info.vote_accounts.write().unwrap();
|
||||
vote_accounts.insert(*pubkey, account.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,22 +671,17 @@ impl AccountsDB {
|
||||
}
|
||||
|
||||
fn remove_parents(&self, fork: Fork) -> Vec<Fork> {
|
||||
let mut squashed_vote_accounts = self.get_vote_accounts(fork);
|
||||
squashed_vote_accounts.retain(|_, account| account.lamports != 0);
|
||||
let mut info = self.fork_infos.write().unwrap();
|
||||
let fork_info = info.get_mut(&fork).unwrap();
|
||||
let mut vote_accounts = fork_info.vote_accounts.write().unwrap();
|
||||
*vote_accounts = squashed_vote_accounts;
|
||||
fork_info.parents.split_off(0)
|
||||
let mut parents_map = self.parents_map.write().unwrap();
|
||||
let parents = parents_map.get_mut(&fork).unwrap();
|
||||
parents.split_off(0)
|
||||
}
|
||||
|
||||
fn is_squashed(&self, fork: Fork) -> bool {
|
||||
self.fork_infos
|
||||
self.parents_map
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&fork)
|
||||
.unwrap()
|
||||
.parents
|
||||
.is_empty()
|
||||
}
|
||||
|
||||
@@ -764,16 +694,16 @@ impl AccountsDB {
|
||||
{
|
||||
let stores = self.storage.read().unwrap();
|
||||
for parent_fork in parents.iter() {
|
||||
let parent_map = account_maps.get(&parent_fork).unwrap().read().unwrap();
|
||||
if account_map.len() > parent_map.len() {
|
||||
for (pubkey, account_info) in parent_map.iter() {
|
||||
let parents_map = account_maps.get(&parent_fork).unwrap().read().unwrap();
|
||||
if account_map.len() > parents_map.len() {
|
||||
for (pubkey, account_info) in parents_map.iter() {
|
||||
if !account_map.contains_key(pubkey) {
|
||||
stores[account_info.id].add_account();
|
||||
account_map.insert(*pubkey, account_info.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut maps = parent_map.clone();
|
||||
let mut maps = parents_map.clone();
|
||||
for (_, account_info) in maps.iter() {
|
||||
stores[account_info.id].add_account();
|
||||
}
|
||||
@@ -984,13 +914,6 @@ impl Accounts {
|
||||
self.accounts_db.squash(fork);
|
||||
}
|
||||
|
||||
pub fn get_vote_accounts(&self, fork: Fork) -> impl Iterator<Item = (Pubkey, Account)> {
|
||||
self.accounts_db
|
||||
.get_vote_accounts(fork)
|
||||
.into_iter()
|
||||
.filter(|(_, acc)| acc.lamports != 0)
|
||||
}
|
||||
|
||||
pub fn remove_accounts(&self, fork: Fork) {
|
||||
self.accounts_db.remove_accounts(fork);
|
||||
}
|
||||
@@ -1774,93 +1697,6 @@ mod tests {
|
||||
assert_eq!(check_storage(&accounts, 0), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accounts_vote_filter() {
|
||||
let accounts = Accounts::new(0, None);
|
||||
let mut vote_account = Account::new(1, 0, &solana_vote_api::id());
|
||||
let key = Pubkey::new_rand();
|
||||
accounts.store_slow(0, &key, &vote_account);
|
||||
|
||||
accounts.new_from_parent(1, 0);
|
||||
|
||||
let mut vote_accounts: Vec<_> = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 1);
|
||||
|
||||
vote_account.lamports = 0;
|
||||
accounts.store_slow(1, &key, &vote_account);
|
||||
|
||||
vote_accounts = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 0);
|
||||
|
||||
let mut vote_account1 = Account::new(2, 0, &solana_vote_api::id());
|
||||
let key1 = Pubkey::new_rand();
|
||||
accounts.store_slow(1, &key1, &vote_account1);
|
||||
|
||||
accounts.squash(1);
|
||||
vote_accounts = accounts.get_vote_accounts(0).collect();
|
||||
assert_eq!(vote_accounts.len(), 1);
|
||||
vote_accounts = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 1);
|
||||
|
||||
vote_account1.lamports = 0;
|
||||
accounts.store_slow(1, &key1, &vote_account1);
|
||||
accounts.store_slow(0, &key, &vote_account);
|
||||
|
||||
vote_accounts = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_account_vote() {
|
||||
let paths = get_tmp_accounts_path!();
|
||||
let accounts_db = AccountsDB::new(0, &paths.paths);
|
||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||
create_account(&accounts_db, &mut pubkeys, 0, 0, 1);
|
||||
let accounts = accounts_db.get_vote_accounts(0);
|
||||
assert_eq!(accounts.len(), 1);
|
||||
accounts.iter().for_each(|(_, account)| {
|
||||
assert_eq!(account.owner, solana_vote_api::id());
|
||||
});
|
||||
let lastkey = Pubkey::new_rand();
|
||||
let mut lastaccount = Account::new(1, 0, &solana_vote_api::id());
|
||||
accounts_db.store(0, &lastkey, &lastaccount);
|
||||
assert_eq!(accounts_db.get_vote_accounts(0).len(), 2);
|
||||
|
||||
accounts_db.add_fork(1, Some(0));
|
||||
|
||||
assert_eq!(
|
||||
accounts_db.get_vote_accounts(1),
|
||||
accounts_db.get_vote_accounts(0)
|
||||
);
|
||||
|
||||
info!("storing lamports=0 to fork 1");
|
||||
// should store a lamports=0 account in 1
|
||||
lastaccount.lamports = 0;
|
||||
accounts_db.store(1, &lastkey, &lastaccount);
|
||||
// len == 2 because lamports=0 accounts are filtered at the Accounts interface.
|
||||
assert_eq!(accounts_db.get_vote_accounts(1).len(), 2);
|
||||
|
||||
accounts_db.squash(1);
|
||||
|
||||
// should still be in 0
|
||||
assert_eq!(accounts_db.get_vote_accounts(0).len(), 2);
|
||||
|
||||
// delete it from 0
|
||||
accounts_db.store(0, &lastkey, &lastaccount);
|
||||
assert_eq!(accounts_db.get_vote_accounts(0).len(), 1);
|
||||
assert_eq!(accounts_db.get_vote_accounts(1).len(), 1);
|
||||
|
||||
// Add fork 2 and squash
|
||||
accounts_db.add_fork(2, Some(1));
|
||||
accounts_db.store(2, &lastkey, &lastaccount);
|
||||
|
||||
accounts_db.squash(1);
|
||||
accounts_db.squash(2);
|
||||
|
||||
assert_eq!(accounts_db.get_vote_accounts(1).len(), 1);
|
||||
assert_eq!(accounts_db.get_vote_accounts(2).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accounts_empty_hash_internal_state() {
|
||||
let paths = get_tmp_accounts_path!();
|
||||
|
Reference in New Issue
Block a user