Organize accounts on a per fork basis (#3336)
* Organize accounts by fork * Keep track of vote accounts in account info * update comments
This commit is contained in:
@ -94,24 +94,37 @@ impl From<usize> for AccountStorageStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// in a given a Fork, which AppendVecId and offset
|
#[derive(Default, Clone)]
|
||||||
type AccountMap = RwLock<HashMap<Fork, (AppendVecId, u64)>>;
|
struct AccountInfo {
|
||||||
|
/// index identifying the append storage
|
||||||
|
id: AppendVecId,
|
||||||
|
|
||||||
/// information about where Accounts are stored and which vote accounts are present
|
/// offset into the storage
|
||||||
|
offset: u64,
|
||||||
|
|
||||||
|
/// lamports in the account used when squashing kept for optimization
|
||||||
|
/// purposes to remove accounts with zero balance.
|
||||||
|
lamports: u64,
|
||||||
|
|
||||||
|
/// keep track if this is a vote account for performance reasons to avoid
|
||||||
|
/// having to read the accounts from the storage
|
||||||
|
is_vote_account: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// in a given a Fork, which AppendVecId and offset
|
||||||
|
type AccountMap = RwLock<HashMap<Pubkey, AccountInfo>>;
|
||||||
|
|
||||||
|
/// information about where Accounts are stored
|
||||||
/// keying hierarchy is:
|
/// keying hierarchy is:
|
||||||
///
|
///
|
||||||
/// pubkey->fork->append_vec->offset
|
/// fork->pubkey->append_vec->offset
|
||||||
///
|
///
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct AccountIndex {
|
struct AccountIndex {
|
||||||
/// For each Pubkey, the Account for a specific Fork is in a specific
|
/// For each Fork, the Account for a specific Pubkey is in a specific
|
||||||
/// AppendVec at a specific index. There may be an Account for Pubkey
|
/// AppendVec at a specific index. There may be an Account for Pubkey
|
||||||
/// in any number of Forks.
|
/// in any number of Forks.
|
||||||
account_maps: RwLock<HashMap<Pubkey, AccountMap>>,
|
account_maps: RwLock<HashMap<Fork, AccountMap>>,
|
||||||
|
|
||||||
/// Cached index to vote accounts for performance reasons to avoid having
|
|
||||||
/// to iterate through the entire accounts each time
|
|
||||||
vote_accounts: RwLock<HashSet<Pubkey>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Persistent storage structure holding the accounts
|
/// Persistent storage structure holding the accounts
|
||||||
@ -243,7 +256,6 @@ impl AccountsDB {
|
|||||||
pub fn new_with_file_size(fork: Fork, paths: &str, file_size: u64, inc_size: u64) -> Self {
|
pub fn new_with_file_size(fork: Fork, paths: &str, file_size: u64, inc_size: u64) -> Self {
|
||||||
let account_index = AccountIndex {
|
let account_index = AccountIndex {
|
||||||
account_maps: RwLock::new(HashMap::new()),
|
account_maps: RwLock::new(HashMap::new()),
|
||||||
vote_accounts: RwLock::new(HashSet::new()),
|
|
||||||
};
|
};
|
||||||
let paths = get_paths_vec(&paths);
|
let paths = get_paths_vec(&paths);
|
||||||
let accounts_db = AccountsDB {
|
let accounts_db = AccountsDB {
|
||||||
@ -265,20 +277,24 @@ impl AccountsDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_fork(&self, fork: Fork, parent: Option<Fork>) {
|
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 fork_infos = self.fork_infos.write().unwrap();
|
||||||
if let Some(parent) = parent {
|
let mut fork_info = ForkInfo::default();
|
||||||
fork_info.parents.push(parent);
|
if let Some(parent) = parent {
|
||||||
if let Some(parent_fork_info) = fork_infos.get(&parent) {
|
fork_info.parents.push(parent);
|
||||||
fork_info.transaction_count = parent_fork_info.transaction_count;
|
if let Some(parent_fork_info) = fork_infos.get(&parent) {
|
||||||
fork_info
|
fork_info.transaction_count = parent_fork_info.transaction_count;
|
||||||
.parents
|
fork_info
|
||||||
.extend_from_slice(&parent_fork_info.parents);
|
.parents
|
||||||
|
.extend_from_slice(&parent_fork_info.parents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(old_fork_info) = fork_infos.insert(fork, fork_info) {
|
||||||
|
panic!("duplicate forks! {} {:?}", fork, old_fork_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(old_fork_info) = fork_infos.insert(fork, fork_info) {
|
let mut account_maps = self.account_index.account_maps.write().unwrap();
|
||||||
panic!("duplicate forks! {} {:?}", fork, old_fork_info);
|
account_maps.insert(fork, RwLock::new(HashMap::new()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_storage_entry(&self, path: &str) -> AccountStorageEntry {
|
fn new_storage_entry(&self, path: &str) -> AccountStorageEntry {
|
||||||
@ -296,15 +312,24 @@ impl AccountsDB {
|
|||||||
storage.append(&mut stores);
|
storage.append(&mut stores);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_vote_accounts(&self, fork: Fork) -> HashMap<Pubkey, Account> {
|
fn get_vote_accounts_by_fork(
|
||||||
self.account_index
|
&self,
|
||||||
.vote_accounts
|
fork: Fork,
|
||||||
|
account_maps: &HashMap<Fork, AccountMap>,
|
||||||
|
vote_accounts: &HashMap<Pubkey, Account>,
|
||||||
|
) -> HashMap<Pubkey, Account> {
|
||||||
|
account_maps
|
||||||
|
.get(&fork)
|
||||||
|
.unwrap()
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|pubkey| {
|
.filter_map(|(pubkey, account_info)| {
|
||||||
if let Some(account) = self.load(fork, pubkey, true) {
|
if account_info.is_vote_account && !vote_accounts.contains_key(pubkey) {
|
||||||
Some((*pubkey, account))
|
Some((
|
||||||
|
*pubkey,
|
||||||
|
self.get_account(account_info.id, account_info.offset),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -312,11 +337,27 @@ impl AccountsDB {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_vote_accounts(&self, fork: Fork) -> HashMap<Pubkey, Account> {
|
||||||
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
|
let mut vote_accounts = HashMap::new();
|
||||||
|
vote_accounts = self.get_vote_accounts_by_fork(fork, &account_maps, &vote_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() {
|
||||||
|
for (pubkey, account_info) in
|
||||||
|
self.get_vote_accounts_by_fork(*parent_fork, &account_maps, &vote_accounts)
|
||||||
|
{
|
||||||
|
vote_accounts.insert(pubkey, account_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vote_accounts
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_accounts(&self, fork: Fork) -> bool {
|
pub fn has_accounts(&self, fork: Fork) -> bool {
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
|
if let Some(account_map) = account_maps.get(&fork) {
|
||||||
for account_map in account_maps.values() {
|
if account_map.read().unwrap().len() > 0 {
|
||||||
if account_map.read().unwrap().contains_key(&fork) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,33 +365,24 @@ impl AccountsDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_internal_state(&self, fork: Fork) -> Option<Hash> {
|
pub fn hash_internal_state(&self, fork: Fork) -> Option<Hash> {
|
||||||
let ordered_accounts: BTreeMap<_, _> = self
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
.account_index
|
let account_map = account_maps.get(&fork).unwrap();
|
||||||
.account_maps
|
let ordered_accounts: BTreeMap<_, _> = account_map
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pubkey, account_map)| {
|
.map(|(pubkey, account_info)| {
|
||||||
let account_map = account_map.read().unwrap();
|
(
|
||||||
if let Some((vec_id, offset)) = account_map.get(&fork) {
|
*pubkey,
|
||||||
Some((
|
self.get_account(account_info.id, account_info.offset),
|
||||||
*pubkey,
|
)
|
||||||
self.storage.read().unwrap()[*vec_id]
|
|
||||||
.accounts
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get_account(*offset)
|
|
||||||
.unwrap(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if ordered_accounts.is_empty() {
|
if ordered_accounts.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(hash(&serialize(&ordered_accounts).unwrap()))
|
Some(hash(&serialize(&ordered_accounts).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,21 +394,21 @@ 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();
|
||||||
if let Some(account_map) = account_maps.get(pubkey) {
|
let account_map = account_maps.get(&fork).unwrap().read().unwrap();
|
||||||
let account_map = account_map.read().unwrap();
|
if let Some(account_info) = account_map.get(&pubkey) {
|
||||||
// find most recent fork that is an ancestor of current_fork
|
return Some(self.get_account(account_info.id, account_info.offset));
|
||||||
if let Some((id, offset)) = account_map.get(&fork) {
|
}
|
||||||
return Some(self.get_account(*id, *offset));
|
if !walk_back {
|
||||||
} else {
|
return None;
|
||||||
if !walk_back {
|
}
|
||||||
return None;
|
// find most recent fork that is an ancestor of current_fork
|
||||||
}
|
let fork_infos = self.fork_infos.read().unwrap();
|
||||||
let fork_infos = self.fork_infos.read().unwrap();
|
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||||
if let Some(fork_info) = fork_infos.get(&fork) {
|
for parent_fork in fork_info.parents.iter() {
|
||||||
for parent_fork in fork_info.parents.iter() {
|
if let Some(account_map) = account_maps.get(&parent_fork) {
|
||||||
if let Some((id, offset)) = account_map.get(&parent_fork) {
|
let account_map = account_map.read().unwrap();
|
||||||
return Some(self.get_account(*id, *offset));
|
if let Some(account_info) = account_map.get(&pubkey) {
|
||||||
}
|
return Some(self.get_account(account_info.id, account_info.offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,23 +416,43 @@ impl AccountsDB {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_program_accounts(&self, fork: Fork, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
|
||||||
|
self.account_index
|
||||||
|
.account_maps
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(&fork)
|
||||||
|
.unwrap()
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(pubkey, account_info)| {
|
||||||
|
let account = Some(self.get_account(account_info.id, account_info.offset));
|
||||||
|
account
|
||||||
|
.filter(|account| account.owner == *program_id)
|
||||||
|
.map(|account| (*pubkey, account))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn load_by_program(
|
fn load_by_program(
|
||||||
&self,
|
&self,
|
||||||
fork: Fork,
|
fork: Fork,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
walk_back: bool,
|
walk_back: bool,
|
||||||
) -> Vec<(Pubkey, Account)> {
|
) -> Vec<(Pubkey, Account)> {
|
||||||
self.account_index
|
let mut program_accounts = self.load_program_accounts(fork, &program_id);
|
||||||
.account_maps
|
if !walk_back {
|
||||||
.read()
|
return program_accounts;
|
||||||
.unwrap()
|
}
|
||||||
.iter()
|
let fork_infos = self.fork_infos.read().unwrap();
|
||||||
.filter_map(|(pubkey, _)| {
|
if let Some(fork_info) = fork_infos.get(&fork) {
|
||||||
self.load(fork, pubkey, walk_back)
|
for parent_fork in fork_info.parents.iter() {
|
||||||
.filter(|account| account.owner == *program_id)
|
let mut parent_accounts = self.load_program_accounts(*parent_fork, &program_id);
|
||||||
.map(|account| (*pubkey, account))
|
program_accounts.append(&mut parent_accounts);
|
||||||
})
|
}
|
||||||
.collect()
|
}
|
||||||
|
program_accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_id(&self, start: usize, current: usize) -> usize {
|
fn get_storage_id(&self, start: usize, current: usize) -> usize {
|
||||||
@ -470,95 +522,48 @@ impl AccountsDB {
|
|||||||
(id, offset)
|
(id, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_account_entries(&self, entries: &[Fork], map: &AccountMap) -> bool {
|
fn remove_account_entries(&self, fork: Fork, pubkey: &Pubkey) -> bool {
|
||||||
let mut forks = map.write().unwrap();
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
for fork in entries.iter() {
|
let mut account_map = account_maps.get(&fork).unwrap().write().unwrap();
|
||||||
if let Some((id, _)) = forks.remove(&fork) {
|
if let Some(account_info) = account_map.remove(&pubkey) {
|
||||||
let stores = self.storage.read().unwrap();
|
let stores = self.storage.read().unwrap();
|
||||||
stores[id].remove_account();
|
stores[account_info.id].remove_account();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
forks.is_empty()
|
account_map.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn account_map_is_empty(pubkey: &Pubkey, account_maps: &HashMap<Pubkey, AccountMap>) -> bool {
|
fn insert_account_entry(
|
||||||
if let Some(account_map) = account_maps.get(pubkey) {
|
|
||||||
if account_map.read().unwrap().len() == 0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_vote_cache(
|
|
||||||
&self,
|
&self,
|
||||||
account: &Account,
|
|
||||||
account_maps: &HashMap<Pubkey, AccountMap>,
|
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
|
account_info: &AccountInfo,
|
||||||
|
account_map: &mut HashMap<Pubkey, AccountInfo>,
|
||||||
) {
|
) {
|
||||||
if solana_vote_api::check_id(&account.owner) {
|
|
||||||
if Self::account_map_is_empty(pubkey, account_maps) {
|
|
||||||
self.account_index
|
|
||||||
.vote_accounts
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.remove(pubkey);
|
|
||||||
} else {
|
|
||||||
self.account_index
|
|
||||||
.vote_accounts
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(*pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_account_entry(&self, fork: Fork, id: AppendVecId, offset: u64, map: &AccountMap) {
|
|
||||||
let mut forks = map.write().unwrap();
|
|
||||||
let stores = self.storage.read().unwrap();
|
let stores = self.storage.read().unwrap();
|
||||||
stores[id].add_account();
|
stores[account_info.id].add_account();
|
||||||
if let Some((old_id, _)) = forks.insert(fork, (id, offset)) {
|
if let Some(old_account_info) = account_map.insert(*pubkey, account_info.clone()) {
|
||||||
stores[old_id].remove_account();
|
stores[old_account_info.id].remove_account();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store the account update.
|
/// Store the account update.
|
||||||
fn store_account(&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) {
|
||||||
// purge if balance is 0 and no checkpoints
|
// purge if balance is 0 and no checkpoints
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
self.remove_account_entries(fork, &pubkey);
|
||||||
let map = account_maps.get(&pubkey).unwrap();
|
|
||||||
self.remove_account_entries(&[fork], &map);
|
|
||||||
self.update_vote_cache(account, &account_maps, pubkey);
|
|
||||||
} else {
|
} else {
|
||||||
let (id, offset) = self.append_account(account);
|
let (id, offset) = self.append_account(account);
|
||||||
|
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
|
let mut account_map = account_maps.get(&fork).unwrap().write().unwrap();
|
||||||
let map = account_maps.get(&pubkey).unwrap();
|
let account_info = AccountInfo {
|
||||||
self.insert_account_entry(fork, id, offset, &map);
|
id,
|
||||||
self.update_vote_cache(account, &account_maps, pubkey);
|
offset,
|
||||||
|
lamports: account.lamports,
|
||||||
|
is_vote_account: solana_vote_api::check_id(&account.owner),
|
||||||
|
};
|
||||||
|
self.insert_account_entry(&pubkey, &account_info, &mut account_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(&self, fork: Fork, pubkey: &Pubkey, account: &Account) {
|
|
||||||
{
|
|
||||||
if !self
|
|
||||||
.account_index
|
|
||||||
.account_maps
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.contains_key(&pubkey)
|
|
||||||
{
|
|
||||||
let mut waccount_maps = self.account_index.account_maps.write().unwrap();
|
|
||||||
if !waccount_maps.contains_key(&pubkey) {
|
|
||||||
waccount_maps.insert(*pubkey, RwLock::new(HashMap::new()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.store_account(fork, pubkey, account);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_accounts(
|
pub fn store_accounts(
|
||||||
&self,
|
&self,
|
||||||
fork: Fork,
|
fork: Fork,
|
||||||
@ -566,27 +571,6 @@ impl AccountsDB {
|
|||||||
res: &[Result<()>],
|
res: &[Result<()>],
|
||||||
loaded: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
loaded: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
||||||
) {
|
) {
|
||||||
let mut keys = vec![];
|
|
||||||
{
|
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
|
||||||
for (i, raccs) in loaded.iter().enumerate() {
|
|
||||||
if res[i].is_err() || raccs.is_err() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let tx = &txs[i];
|
|
||||||
for key in tx.account_keys.iter() {
|
|
||||||
if !account_maps.contains_key(&key) {
|
|
||||||
keys.push(*key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !keys.is_empty() {
|
|
||||||
let mut account_maps = self.account_index.account_maps.write().unwrap();
|
|
||||||
for key in keys.iter() {
|
|
||||||
account_maps.insert(*key, RwLock::new(HashMap::new()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i, raccs) in loaded.iter().enumerate() {
|
for (i, raccs) in loaded.iter().enumerate() {
|
||||||
if res[i].is_err() || raccs.is_err() {
|
if res[i].is_err() || raccs.is_err() {
|
||||||
continue;
|
continue;
|
||||||
@ -746,58 +730,23 @@ impl AccountsDB {
|
|||||||
.is_empty()
|
.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_merged_account_map(
|
|
||||||
&self,
|
|
||||||
fork: Fork,
|
|
||||||
parents: &[Fork],
|
|
||||||
map: &AccountMap,
|
|
||||||
) -> Option<(Fork, AppendVecId, u64)> {
|
|
||||||
let forks = map.read().unwrap();
|
|
||||||
if let Some((id, offset)) = forks.get(&fork) {
|
|
||||||
return Some((fork, *id, *offset));
|
|
||||||
} else {
|
|
||||||
for parent_fork in parents.iter() {
|
|
||||||
if let Some((id, offset)) = forks.get(parent_fork) {
|
|
||||||
return Some((*parent_fork, *id, *offset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// make fork a root, i.e. forget its heritage
|
/// make fork a root, i.e. forget its heritage
|
||||||
fn squash(&self, fork: Fork) {
|
fn squash(&self, fork: Fork) {
|
||||||
let parents = self.remove_parents(fork);
|
let parents = self.remove_parents(fork);
|
||||||
|
|
||||||
// for every account in all the parents, load latest and update self if
|
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||||
// absent
|
let mut account_map = account_maps.get(&fork).unwrap().write().unwrap();
|
||||||
let mut keys = vec![];
|
for parent_fork in parents.iter() {
|
||||||
{
|
let parent_map = account_maps.get(&parent_fork).unwrap().read().unwrap();
|
||||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
for (pubkey, account_info) in parent_map.iter() {
|
||||||
account_maps.iter().for_each(|(pubkey, map)| {
|
if account_map.get(pubkey).is_none() {
|
||||||
if let Some((parent_fork, id, offset)) =
|
self.insert_account_entry(&pubkey, &account_info, &mut account_map);
|
||||||
self.get_merged_account_map(fork, &parents, &map)
|
|
||||||
{
|
|
||||||
if parent_fork != fork {
|
|
||||||
self.insert_account_entry(fork, id, offset, &map);
|
|
||||||
} else {
|
|
||||||
let account = self.get_account(id, offset);
|
|
||||||
if account.lamports == 0 {
|
|
||||||
if self.remove_account_entries(&[fork], &map) {
|
|
||||||
keys.push(pubkey.clone());
|
|
||||||
}
|
|
||||||
self.update_vote_cache(&account, &account_maps, pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
if !keys.is_empty() {
|
|
||||||
let mut account_maps = self.account_index.account_maps.write().unwrap();
|
|
||||||
for key in keys.iter() {
|
|
||||||
account_maps.remove(&key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toss any zero-balance accounts, since self is root now
|
||||||
|
account_map.retain(|_, account_info| account_info.lamports != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1693,10 +1642,9 @@ mod tests {
|
|||||||
|
|
||||||
let mut append_vec_histogram = HashMap::new();
|
let mut append_vec_histogram = HashMap::new();
|
||||||
let account_maps = accounts.account_index.account_maps.read().unwrap();
|
let account_maps = accounts.account_index.account_maps.read().unwrap();
|
||||||
for map in account_maps.values() {
|
let account_map = account_maps.get(&0).unwrap().read().unwrap();
|
||||||
*append_vec_histogram
|
for map in account_map.values() {
|
||||||
.entry(map.read().unwrap().get(&0).unwrap().0)
|
*append_vec_histogram.entry(map.id).or_insert(0) += 1;
|
||||||
.or_insert(0) += 1;
|
|
||||||
}
|
}
|
||||||
for count in append_vec_histogram.values() {
|
for count in append_vec_histogram.values() {
|
||||||
assert!(*count >= 2);
|
assert!(*count >= 2);
|
||||||
@ -1837,15 +1785,6 @@ mod tests {
|
|||||||
accounts_db.squash(1);
|
accounts_db.squash(1);
|
||||||
accounts_db.squash(2);
|
accounts_db.squash(2);
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
accounts_db
|
|
||||||
.account_index
|
|
||||||
.vote_accounts
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.len(),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
assert_eq!(accounts_db.get_vote_accounts(1).len(), 1);
|
assert_eq!(accounts_db.get_vote_accounts(1).len(), 1);
|
||||||
assert_eq!(accounts_db.get_vote_accounts(2).len(), 1);
|
assert_eq!(accounts_db.get_vote_accounts(2).len(), 1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user