Splits up AccountsDb::bank_hashes (#30024)
This commit is contained in:
parent
b29a50a55e
commit
d048a1903f
|
@ -281,7 +281,7 @@ fn run_bank_forks_snapshot_n<F>(
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let accounts_hash = last_bank.get_accounts_hash();
|
let accounts_hash = last_bank.get_accounts_hash().unwrap();
|
||||||
solana_runtime::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
solana_runtime::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
||||||
accounts_package.snapshot_links_dir(),
|
accounts_package.snapshot_links_dir(),
|
||||||
accounts_package.slot,
|
accounts_package.slot,
|
||||||
|
|
|
@ -1349,7 +1349,9 @@ pub struct AccountsDb {
|
||||||
|
|
||||||
pub thread_pool_clean: ThreadPool,
|
pub thread_pool_clean: ThreadPool,
|
||||||
|
|
||||||
bank_hashes: RwLock<HashMap<Slot, BankHashInfo>>,
|
accounts_delta_hashes: Mutex<HashMap<Slot, AccountsDeltaHash>>,
|
||||||
|
accounts_hashes: Mutex<HashMap<Slot, AccountsHash>>,
|
||||||
|
bank_hash_stats: Mutex<HashMap<Slot, BankHashStats>>,
|
||||||
|
|
||||||
pub stats: AccountsStats,
|
pub stats: AccountsStats,
|
||||||
|
|
||||||
|
@ -2315,8 +2317,12 @@ impl AccountsDb {
|
||||||
.to_path_buf()
|
.to_path_buf()
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut bank_hashes = HashMap::new();
|
let mut accounts_delta_hashes = HashMap::new();
|
||||||
bank_hashes.insert(0, BankHashInfo::default());
|
accounts_delta_hashes.insert(0, AccountsDeltaHash::default());
|
||||||
|
let mut accounts_hashes = HashMap::new();
|
||||||
|
accounts_hashes.insert(0, AccountsHash::default());
|
||||||
|
let mut bank_hash_stats = HashMap::new();
|
||||||
|
bank_hash_stats.insert(0, BankHashStats::default());
|
||||||
|
|
||||||
// Increase the stack for accounts threads
|
// Increase the stack for accounts threads
|
||||||
// rayon needs a lot of stack
|
// rayon needs a lot of stack
|
||||||
|
@ -2357,7 +2363,9 @@ impl AccountsDb {
|
||||||
.build()
|
.build()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
thread_pool_clean: make_min_priority_thread_pool(),
|
thread_pool_clean: make_min_priority_thread_pool(),
|
||||||
bank_hashes: RwLock::new(bank_hashes),
|
accounts_delta_hashes: Mutex::new(accounts_delta_hashes),
|
||||||
|
accounts_hashes: Mutex::new(accounts_hashes),
|
||||||
|
bank_hash_stats: Mutex::new(bank_hash_stats),
|
||||||
external_purge_slots_stats: PurgeStats::default(),
|
external_purge_slots_stats: PurgeStats::default(),
|
||||||
clean_accounts_stats: CleanAccountsStats::default(),
|
clean_accounts_stats: CleanAccountsStats::default(),
|
||||||
shrink_stats: ShrinkStats::default(),
|
shrink_stats: ShrinkStats::default(),
|
||||||
|
@ -4559,7 +4567,7 @@ impl AccountsDb {
|
||||||
dropped_roots.iter().for_each(|slot| {
|
dropped_roots.iter().for_each(|slot| {
|
||||||
self.accounts_index
|
self.accounts_index
|
||||||
.clean_dead_slot(*slot, &mut AccountsIndexRootsStats::default());
|
.clean_dead_slot(*slot, &mut AccountsIndexRootsStats::default());
|
||||||
self.bank_hashes.write().unwrap().remove(slot);
|
self.remove_bank_hash_info(slot);
|
||||||
// the storage has been removed from this slot and recycled or dropped
|
// the storage has been removed from this slot and recycled or dropped
|
||||||
assert!(self.storage.remove(slot).is_none());
|
assert!(self.storage.remove(slot).is_none());
|
||||||
});
|
});
|
||||||
|
@ -4881,17 +4889,23 @@ impl AccountsDb {
|
||||||
/// The new bank hash is empty/default except for the slot. This fn is called when creating a
|
/// The new bank hash is empty/default except for the slot. This fn is called when creating a
|
||||||
/// new bank from parent. The bank hash for this slot is updated with real values later.
|
/// new bank from parent. The bank hash for this slot is updated with real values later.
|
||||||
pub fn insert_default_bank_hash(&self, slot: Slot, parent_slot: Slot) {
|
pub fn insert_default_bank_hash(&self, slot: Slot, parent_slot: Slot) {
|
||||||
let mut bank_hashes = self.bank_hashes.write().unwrap();
|
let mut bank_hash_stats = self.bank_hash_stats.lock().unwrap();
|
||||||
if bank_hashes.get(&slot).is_some() {
|
if bank_hash_stats.get(&slot).is_some() {
|
||||||
error!(
|
error!(
|
||||||
"set_hash: already exists; multiple forks with shared slot {} as child (parent: {})!?",
|
"set_hash: already exists; multiple forks with shared slot {} as child (parent: {})!?",
|
||||||
slot, parent_slot,
|
slot, parent_slot,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bank_hash_stats.insert(slot, BankHashStats::default());
|
||||||
|
drop(bank_hash_stats);
|
||||||
|
|
||||||
let new_hash_info = BankHashInfo::default();
|
let old_accounts_delta_hash =
|
||||||
bank_hashes.insert(slot, new_hash_info);
|
self.set_accounts_delta_hash(slot, AccountsDeltaHash::default());
|
||||||
|
assert!(old_accounts_delta_hash.is_none());
|
||||||
|
|
||||||
|
let old_accounts_hash = self.set_accounts_hash(slot, AccountsHash::default());
|
||||||
|
assert!(old_accounts_hash.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(
|
pub fn load(
|
||||||
|
@ -6850,12 +6864,6 @@ impl AccountsDb {
|
||||||
Ok((accounts_hash, total_lamports))
|
Ok((accounts_hash, total_lamports))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_accounts_hash(&self, slot: Slot) -> AccountsHash {
|
|
||||||
let bank_hashes = self.bank_hashes.read().unwrap();
|
|
||||||
let bank_hash_info = bank_hashes.get(&slot).unwrap();
|
|
||||||
bank_hash_info.accounts_hash
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_accounts_hash_for_tests(
|
pub fn update_accounts_hash_for_tests(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
@ -7223,11 +7231,19 @@ impl AccountsDb {
|
||||||
(accounts_hash, total_lamports)
|
(accounts_hash, total_lamports)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// update hash for this slot in the 'bank_hashes' map
|
/// Set the accounts hash for `slot` in the `accounts_hashes` map
|
||||||
pub(crate) fn set_accounts_hash(&self, slot: Slot, accounts_hash: AccountsHash) {
|
///
|
||||||
let mut bank_hashes = self.bank_hashes.write().unwrap();
|
/// returns the previous accounts hash for `slot`
|
||||||
let mut bank_hash_info = bank_hashes.get_mut(&slot).unwrap();
|
fn set_accounts_hash(&self, slot: Slot, accounts_hash: AccountsHash) -> Option<AccountsHash> {
|
||||||
bank_hash_info.accounts_hash = accounts_hash;
|
self.accounts_hashes
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(slot, accounts_hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the accounts hash for `slot` in the `accounts_hashes` map
|
||||||
|
pub fn get_accounts_hash(&self, slot: Slot) -> Option<AccountsHash> {
|
||||||
|
self.accounts_hashes.lock().unwrap().get(&slot).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// scan 'storages', return a vec of 'CacheHashDataFile', one per pass
|
/// scan 'storages', return a vec of 'CacheHashDataFile', one per pass
|
||||||
|
@ -7532,21 +7548,18 @@ impl AccountsDb {
|
||||||
|
|
||||||
if ignore_mismatch {
|
if ignore_mismatch {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else if let Some(found_accounts_hash) = self.get_accounts_hash(slot) {
|
||||||
let bank_hashes = self.bank_hashes.read().unwrap();
|
if calculated_accounts_hash == found_accounts_hash {
|
||||||
if let Some(found_hash_info) = bank_hashes.get(&slot) {
|
Ok(())
|
||||||
if calculated_accounts_hash == found_hash_info.accounts_hash {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"mismatched bank hash for slot {}: {:?} (calculated) != {:?} (expected)",
|
|
||||||
slot, calculated_accounts_hash, found_hash_info.accounts_hash,
|
|
||||||
);
|
|
||||||
Err(MismatchedBankHash)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(MissingBankHash)
|
warn!(
|
||||||
|
"mismatched bank hash for slot {}: {:?} (calculated) != {:?} (expected)",
|
||||||
|
slot, calculated_accounts_hash, found_accounts_hash,
|
||||||
|
);
|
||||||
|
Err(MismatchedBankHash)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Err(MissingBankHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7601,10 +7614,12 @@ impl AccountsDb {
|
||||||
let mut uncleaned_time = Measure::start("uncleaned_index");
|
let mut uncleaned_time = Measure::start("uncleaned_index");
|
||||||
self.uncleaned_pubkeys.insert(slot, dirty_keys);
|
self.uncleaned_pubkeys.insert(slot, dirty_keys);
|
||||||
uncleaned_time.stop();
|
uncleaned_time.stop();
|
||||||
|
|
||||||
|
self.set_accounts_delta_hash(slot, accounts_delta_hash);
|
||||||
|
|
||||||
self.stats
|
self.stats
|
||||||
.store_uncleaned_update
|
.store_uncleaned_update
|
||||||
.fetch_add(uncleaned_time.as_us(), Ordering::Relaxed);
|
.fetch_add(uncleaned_time.as_us(), Ordering::Relaxed);
|
||||||
|
|
||||||
self.stats
|
self.stats
|
||||||
.delta_hash_scan_time_total_us
|
.delta_hash_scan_time_total_us
|
||||||
.fetch_add(scan_us, Ordering::Relaxed);
|
.fetch_add(scan_us, Ordering::Relaxed);
|
||||||
|
@ -7615,13 +7630,76 @@ impl AccountsDb {
|
||||||
accounts_delta_hash
|
accounts_delta_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the bank hash info for `slot`
|
/// Set the accounts delta hash for `slot` in the `accounts_delta_hashes` map
|
||||||
pub fn get_bank_hash_info(&self, slot: Slot) -> Option<BankHashInfo> {
|
///
|
||||||
self.bank_hashes.read().unwrap().get(&slot).cloned()
|
/// returns the previous accounts delta hash for `slot`
|
||||||
|
fn set_accounts_delta_hash(
|
||||||
|
&self,
|
||||||
|
slot: Slot,
|
||||||
|
accounts_delta_hash: AccountsDeltaHash,
|
||||||
|
) -> Option<AccountsDeltaHash> {
|
||||||
|
self.accounts_delta_hashes
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(slot, accounts_delta_hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the accounts delta hash for `slot` in the `accounts_delta_hashes` map
|
||||||
|
pub fn get_accounts_delta_hash(&self, slot: Slot) -> Option<AccountsDeltaHash> {
|
||||||
|
self.accounts_delta_hashes
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&slot)
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the bank hash stats for `slot` in the `bank_hash_stats` map
|
||||||
|
///
|
||||||
|
/// returns the previous bank hash stats for `slot`
|
||||||
|
fn set_bank_hash_stats(
|
||||||
|
&self,
|
||||||
|
slot: Slot,
|
||||||
|
bank_hash_stats: BankHashStats,
|
||||||
|
) -> Option<BankHashStats> {
|
||||||
|
self.bank_hash_stats
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(slot, bank_hash_stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the bank hash stats for `slot` in the `bank_hash_stats` map
|
||||||
|
pub fn get_bank_hash_stats(&self, slot: Slot) -> Option<BankHashStats> {
|
||||||
|
self.bank_hash_stats.lock().unwrap().get(&slot).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the "bank hash info" for `slot`
|
||||||
|
///
|
||||||
|
/// Internally this sets the accounts delta hash, the accounts hash, and the bank hash stats
|
||||||
|
/// from `bank_hash_info` for `slot` in their respective maps.
|
||||||
|
///
|
||||||
|
/// returns the previous accounts delta hash, accounts hash, and bank hash stats for `slot`
|
||||||
|
fn set_bank_hash_info(
|
||||||
|
&self,
|
||||||
|
slot: Slot,
|
||||||
|
bank_hash_info: BankHashInfo,
|
||||||
|
) -> (
|
||||||
|
Option<AccountsDeltaHash>,
|
||||||
|
Option<AccountsHash>,
|
||||||
|
Option<BankHashStats>,
|
||||||
|
) {
|
||||||
|
let BankHashInfo {
|
||||||
|
accounts_delta_hash,
|
||||||
|
accounts_hash,
|
||||||
|
stats,
|
||||||
|
} = bank_hash_info;
|
||||||
|
let old_accounts_delta_hash = self.set_accounts_delta_hash(slot, accounts_delta_hash);
|
||||||
|
let old_accounts_hash = self.set_accounts_hash(slot, accounts_hash);
|
||||||
|
let old_stats = self.set_bank_hash_stats(slot, stats);
|
||||||
|
(old_accounts_delta_hash, old_accounts_hash, old_stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When reconstructing AccountsDb from a snapshot, insert the `bank_hash_info` into the
|
/// When reconstructing AccountsDb from a snapshot, insert the `bank_hash_info` into the
|
||||||
/// internal bank hashses map.
|
/// internal bank hash info maps.
|
||||||
///
|
///
|
||||||
/// This fn is only called when loading from a snapshot, which means AccountsDb is new and its
|
/// This fn is only called when loading from a snapshot, which means AccountsDb is new and its
|
||||||
/// bank hashes is unpopulated. Therefore, a bank hash must not already exist at `slot` [^1].
|
/// bank hashes is unpopulated. Therefore, a bank hash must not already exist at `slot` [^1].
|
||||||
|
@ -7630,16 +7708,74 @@ impl AccountsDb {
|
||||||
/// loading from a snapshot--the bank hashes map is populated with a default entry at slot 0.
|
/// loading from a snapshot--the bank hashes map is populated with a default entry at slot 0.
|
||||||
/// It is valid to have a snapshot at slot 0, so it must be handled accordingly.
|
/// It is valid to have a snapshot at slot 0, so it must be handled accordingly.
|
||||||
pub fn set_bank_hash_info_from_snapshot(&self, slot: Slot, bank_hash_info: BankHashInfo) {
|
pub fn set_bank_hash_info_from_snapshot(&self, slot: Slot, bank_hash_info: BankHashInfo) {
|
||||||
let old_bank_hash_info = self
|
let (old_accounts_delta_hash, old_accounts_hash, old_stats) =
|
||||||
.bank_hashes
|
self.set_bank_hash_info(slot, bank_hash_info);
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(slot, bank_hash_info);
|
|
||||||
assert!(
|
assert!(
|
||||||
old_bank_hash_info.is_none()
|
old_accounts_delta_hash.is_none()
|
||||||
|| (slot == 0 && old_bank_hash_info == Some(BankHashInfo::default())),
|
|| (slot == 0 && old_accounts_delta_hash == Some(AccountsDeltaHash(Hash::default()))),
|
||||||
"There should not already be a BankHashInfo at slot {slot}: {old_bank_hash_info:?}",
|
"There should not already be an AccountsDeltaHash at slot {slot}: {old_accounts_delta_hash:?}",
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
old_accounts_hash.is_none()
|
||||||
|
|| (slot == 0 && old_accounts_hash == Some(AccountsHash(Hash::default()))),
|
||||||
|
"There should not already be an AccountsHash at slot {slot}: {old_accounts_hash:?}",
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
old_stats.is_none() || (slot == 0 && old_stats == Some(BankHashStats::default())),
|
||||||
|
"There should not already be a BankHashStats at slot {slot}: {old_stats:?}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove "bank hash info" for `slot`
|
||||||
|
///
|
||||||
|
/// This fn removes the accounts delta hash, accounts hash, and bank hash stats for `slot` from
|
||||||
|
/// their respective maps.
|
||||||
|
fn remove_bank_hash_info(&self, slot: &Slot) {
|
||||||
|
self.remove_bank_hash_infos(std::iter::once(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove "bank hash info" for `slots`
|
||||||
|
///
|
||||||
|
/// This fn removes the accounts delta hash, accounts hash, and bank hash stats for `slots` from
|
||||||
|
/// their respective maps.
|
||||||
|
fn remove_bank_hash_infos<'s>(&self, slots: impl IntoIterator<Item = &'s Slot>) {
|
||||||
|
let mut accounts_delta_hashes = self.accounts_delta_hashes.lock().unwrap();
|
||||||
|
let mut accounts_hashes = self.accounts_hashes.lock().unwrap();
|
||||||
|
let mut bank_hash_stats = self.bank_hash_stats.lock().unwrap();
|
||||||
|
|
||||||
|
for slot in slots.into_iter() {
|
||||||
|
accounts_delta_hashes.remove(slot);
|
||||||
|
accounts_hashes.remove(slot);
|
||||||
|
bank_hash_stats.remove(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the "bank hash info" for `slot`
|
||||||
|
///
|
||||||
|
/// Internally this gets the accounts delta hash, the accounts hash, and the bank hash stats
|
||||||
|
/// for `slot` from their respective maps.
|
||||||
|
///
|
||||||
|
/// Only called by tests or serde_snapshot when serializing accounts db fields
|
||||||
|
pub fn get_bank_hash_info(&self, slot: Slot) -> Option<BankHashInfo> {
|
||||||
|
let Some(stats) = self.get_bank_hash_stats(slot) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If there is a bank hash stats at this slot, then we'll return a `Some` regardless. Use
|
||||||
|
// default values for accounts hash and accounts delta hash if not found.
|
||||||
|
let accounts_hash = self
|
||||||
|
.get_accounts_hash(slot)
|
||||||
|
.unwrap_or_else(|| AccountsHash(Hash::default()));
|
||||||
|
let accounts_delta_hash = self
|
||||||
|
.get_accounts_delta_hash(slot)
|
||||||
|
.unwrap_or_else(|| AccountsDeltaHash(Hash::default()));
|
||||||
|
|
||||||
|
Some(BankHashInfo {
|
||||||
|
accounts_hash,
|
||||||
|
accounts_delta_hash,
|
||||||
|
stats,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_index<'a, T: ReadableAccount + Sync>(
|
fn update_index<'a, T: ReadableAccount + Sync>(
|
||||||
|
@ -7859,12 +7995,7 @@ impl AccountsDb {
|
||||||
purged_stored_account_slots,
|
purged_stored_account_slots,
|
||||||
pubkeys_removed_from_accounts_index,
|
pubkeys_removed_from_accounts_index,
|
||||||
);
|
);
|
||||||
{
|
self.remove_bank_hash_infos(dead_slots_iter);
|
||||||
let mut bank_hashes = self.bank_hashes.write().unwrap();
|
|
||||||
for slot in dead_slots_iter {
|
|
||||||
bank_hashes.remove(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
measure.stop();
|
measure.stop();
|
||||||
inc_new_counter_info!("remove_dead_slots_metadata-ms", measure.as_ms() as usize);
|
inc_new_counter_info!("remove_dead_slots_metadata-ms", measure.as_ms() as usize);
|
||||||
}
|
}
|
||||||
|
@ -8072,12 +8203,13 @@ impl AccountsDb {
|
||||||
.fetch_add(total_data as u64, Ordering::Relaxed);
|
.fetch_add(total_data as u64, Ordering::Relaxed);
|
||||||
|
|
||||||
{
|
{
|
||||||
// we need to drop bank_hashes to prevent deadlocks
|
// we need to drop the bank_hash_stats lock to prevent deadlocks
|
||||||
let mut bank_hashes = self.bank_hashes.write().unwrap();
|
self.bank_hash_stats
|
||||||
let slot_info = bank_hashes
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.entry(accounts.target_slot())
|
.entry(accounts.target_slot())
|
||||||
.or_insert_with(BankHashInfo::default);
|
.or_insert_with(BankHashStats::default)
|
||||||
slot_info.stats.accumulate(&stats);
|
.accumulate(&stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use default hashes for now since the same account may be stored to the cache multiple times
|
// we use default hashes for now since the same account may be stored to the cache multiple times
|
||||||
|
@ -9364,6 +9496,11 @@ pub mod tests {
|
||||||
fn get_storage_for_slot(&self, slot: Slot) -> Option<Arc<AccountStorageEntry>> {
|
fn get_storage_for_slot(&self, slot: Slot) -> Option<Arc<AccountStorageEntry>> {
|
||||||
self.storage.get_slot_storage_entry(slot)
|
self.storage.get_slot_storage_entry(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used by serde_snapshot tests
|
||||||
|
pub fn set_accounts_hash_for_tests(&self, slot: Slot, accounts_hash: AccountsHash) {
|
||||||
|
self.set_accounts_hash(slot, accounts_hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This impl exists until this feature is activated:
|
/// This impl exists until this feature is activated:
|
||||||
|
@ -10683,10 +10820,7 @@ pub mod tests {
|
||||||
} else {
|
} else {
|
||||||
db.store_for_tests(unrooted_slot, &[(&key, &account0)]);
|
db.store_for_tests(unrooted_slot, &[(&key, &account0)]);
|
||||||
}
|
}
|
||||||
db.bank_hashes
|
db.set_bank_hash_info(unrooted_slot, BankHashInfo::default());
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(unrooted_slot, BankHashInfo::default());
|
|
||||||
assert!(db
|
assert!(db
|
||||||
.accounts_index
|
.accounts_index
|
||||||
.get(&key, Some(&ancestors), None)
|
.get(&key, Some(&ancestors), None)
|
||||||
|
@ -10696,7 +10830,9 @@ pub mod tests {
|
||||||
// Purge the slot
|
// Purge the slot
|
||||||
db.remove_unrooted_slots(&[(unrooted_slot, unrooted_bank_id)]);
|
db.remove_unrooted_slots(&[(unrooted_slot, unrooted_bank_id)]);
|
||||||
assert!(db.load_without_fixed_root(&ancestors, &key).is_none());
|
assert!(db.load_without_fixed_root(&ancestors, &key).is_none());
|
||||||
assert!(db.bank_hashes.read().unwrap().get(&unrooted_slot).is_none());
|
assert!(db.get_accounts_hash(unrooted_slot).is_none());
|
||||||
|
assert!(db.get_accounts_delta_hash(unrooted_slot).is_none());
|
||||||
|
assert!(db.get_bank_hash_stats(unrooted_slot).is_none());
|
||||||
assert!(db.accounts_cache.slot_cache(unrooted_slot).is_none());
|
assert!(db.accounts_cache.slot_cache(unrooted_slot).is_none());
|
||||||
assert!(db.storage.get_slot_storage_entry(unrooted_slot).is_none());
|
assert!(db.storage.get_slot_storage_entry(unrooted_slot).is_none());
|
||||||
assert!(db.accounts_index.get_account_read_entry(&key).is_none());
|
assert!(db.accounts_index.get_account_read_entry(&key).is_none());
|
||||||
|
@ -11591,6 +11727,9 @@ pub mod tests {
|
||||||
accounts.add_root_and_flush_write_cache(latest_slot);
|
accounts.add_root_and_flush_write_cache(latest_slot);
|
||||||
check_storage(&accounts, 2, 31);
|
check_storage(&accounts, 2, 31);
|
||||||
|
|
||||||
|
let ancestors = linear_ancestors(latest_slot);
|
||||||
|
accounts.update_accounts_hash_for_tests(latest_slot, &ancestors, false, false);
|
||||||
|
|
||||||
accounts.clean_accounts_for_tests();
|
accounts.clean_accounts_for_tests();
|
||||||
// The first 20 accounts of slot 0 have been updated in slot 2, as well as
|
// The first 20 accounts of slot 0 have been updated in slot 2, as well as
|
||||||
// accounts 30 and 31 (overwritten with zero-lamport accounts in slot 1 and
|
// accounts 30 and 31 (overwritten with zero-lamport accounts in slot 1 and
|
||||||
|
@ -11608,12 +11747,17 @@ pub mod tests {
|
||||||
accounts.write_version.load(Ordering::Acquire)
|
accounts.write_version.load(Ordering::Acquire)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the hash for the latest slot, which should be the only hash in the
|
// Get the hashes for the latest slot, which should be the only hashes in the
|
||||||
// bank_hashes map on the deserialized AccountsDb
|
// map on the deserialized AccountsDb (other than slot 0)
|
||||||
assert_eq!(daccounts.bank_hashes.read().unwrap().len(), 2);
|
assert_eq!(daccounts.accounts_delta_hashes.lock().unwrap().len(), 2);
|
||||||
|
assert_eq!(daccounts.accounts_hashes.lock().unwrap().len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
daccounts.bank_hashes.read().unwrap().get(&latest_slot),
|
daccounts.get_accounts_delta_hash(latest_slot).unwrap(),
|
||||||
accounts.bank_hashes.read().unwrap().get(&latest_slot)
|
accounts.get_accounts_delta_hash(latest_slot).unwrap(),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
daccounts.get_accounts_hash(latest_slot).unwrap(),
|
||||||
|
accounts.get_accounts_hash(latest_slot).unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
daccounts.print_count_and_status("daccounts");
|
daccounts.print_count_and_status("daccounts");
|
||||||
|
@ -11625,7 +11769,6 @@ pub mod tests {
|
||||||
check_storage(&daccounts, 1, 21);
|
check_storage(&daccounts, 1, 21);
|
||||||
check_storage(&daccounts, 2, 31);
|
check_storage(&daccounts, 2, 31);
|
||||||
|
|
||||||
let ancestors = linear_ancestors(latest_slot);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
daccounts.update_accounts_hash_for_tests(latest_slot, &ancestors, false, false,),
|
daccounts.update_accounts_hash_for_tests(latest_slot, &ancestors, false, false,),
|
||||||
accounts.update_accounts_hash_for_tests(latest_slot, &ancestors, false, false,)
|
accounts.update_accounts_hash_for_tests(latest_slot, &ancestors, false, false,)
|
||||||
|
@ -12208,13 +12351,12 @@ pub mod tests {
|
||||||
db.store_for_tests(some_slot, &[(&key, &account)]);
|
db.store_for_tests(some_slot, &[(&key, &account)]);
|
||||||
db.add_root(some_slot);
|
db.add_root(some_slot);
|
||||||
|
|
||||||
let bank_hashes = db.bank_hashes.read().unwrap();
|
let stats = db.get_bank_hash_stats(some_slot).unwrap();
|
||||||
let bank_hash = bank_hashes.get(&some_slot).unwrap();
|
assert_eq!(stats.num_updated_accounts, 1);
|
||||||
assert_eq!(bank_hash.stats.num_updated_accounts, 1);
|
assert_eq!(stats.num_removed_accounts, 1);
|
||||||
assert_eq!(bank_hash.stats.num_removed_accounts, 1);
|
assert_eq!(stats.num_lamports_stored, 1);
|
||||||
assert_eq!(bank_hash.stats.num_lamports_stored, 1);
|
assert_eq!(stats.total_data_len, 2 * some_data_len as u64);
|
||||||
assert_eq!(bank_hash.stats.total_data_len, 2 * some_data_len as u64);
|
assert_eq!(stats.num_executable_accounts, 1);
|
||||||
assert_eq!(bank_hash.stats.num_executable_accounts, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this test tests check_hash=true, which is unsupported behavior at the moment. It cannot be enabled by anything but these tests.
|
// this test tests check_hash=true, which is unsupported behavior at the moment. It cannot be enabled by anything but these tests.
|
||||||
|
@ -12352,7 +12494,7 @@ pub mod tests {
|
||||||
Ok(_)
|
Ok(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
db.bank_hashes.write().unwrap().remove(&some_slot).unwrap();
|
db.remove_bank_hash_info(&some_slot);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
db.verify_bank_hash_and_lamports(
|
db.verify_bank_hash_and_lamports(
|
||||||
some_slot,
|
some_slot,
|
||||||
|
@ -12373,10 +12515,7 @@ pub mod tests {
|
||||||
accounts_hash: AccountsHash(Hash::new(&[0xca; HASH_BYTES])),
|
accounts_hash: AccountsHash(Hash::new(&[0xca; HASH_BYTES])),
|
||||||
stats: BankHashStats::default(),
|
stats: BankHashStats::default(),
|
||||||
};
|
};
|
||||||
db.bank_hashes
|
db.set_bank_hash_info(some_slot, bank_hash_info);
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(some_slot, bank_hash_info);
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
db.verify_bank_hash_and_lamports(
|
db.verify_bank_hash_and_lamports(
|
||||||
some_slot,
|
some_slot,
|
||||||
|
@ -12467,10 +12606,7 @@ pub mod tests {
|
||||||
let some_slot: Slot = 0;
|
let some_slot: Slot = 0;
|
||||||
let ancestors = vec![(some_slot, 0)].into_iter().collect();
|
let ancestors = vec![(some_slot, 0)].into_iter().collect();
|
||||||
|
|
||||||
db.bank_hashes
|
db.set_bank_hash_info(some_slot, BankHashInfo::default());
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(some_slot, BankHashInfo::default());
|
|
||||||
db.add_root(some_slot);
|
db.add_root(some_slot);
|
||||||
db.update_accounts_hash_for_tests(some_slot, &ancestors, true, true);
|
db.update_accounts_hash_for_tests(some_slot, &ancestors, true, true);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
|
@ -12502,13 +12638,8 @@ pub mod tests {
|
||||||
let ancestors = vec![(some_slot, 0)].into_iter().collect();
|
let ancestors = vec![(some_slot, 0)].into_iter().collect();
|
||||||
|
|
||||||
let accounts = &[(&key, &account)][..];
|
let accounts = &[(&key, &account)][..];
|
||||||
// update AccountsDb's bank hash
|
db.update_accounts_hash_for_tests(some_slot, &ancestors, false, false);
|
||||||
{
|
|
||||||
let mut bank_hashes = db.bank_hashes.write().unwrap();
|
|
||||||
bank_hashes
|
|
||||||
.entry(some_slot)
|
|
||||||
.or_insert_with(BankHashInfo::default);
|
|
||||||
}
|
|
||||||
// provide bogus account hashes
|
// provide bogus account hashes
|
||||||
let some_hash = Hash::new(&[0xca; HASH_BYTES]);
|
let some_hash = Hash::new(&[0xca; HASH_BYTES]);
|
||||||
db.store_accounts_unfrozen(
|
db.store_accounts_unfrozen(
|
||||||
|
@ -17427,17 +17558,14 @@ pub mod tests {
|
||||||
db.handle_dropped_roots_for_ancient(Vec::default());
|
db.handle_dropped_roots_for_ancient(Vec::default());
|
||||||
let slot0 = 0;
|
let slot0 = 0;
|
||||||
let dropped_roots = vec![slot0];
|
let dropped_roots = vec![slot0];
|
||||||
db.bank_hashes
|
db.set_bank_hash_info(slot0, BankHashInfo::default());
|
||||||
.write()
|
assert!(db.get_bank_hash_info(slot0).is_some());
|
||||||
.unwrap()
|
|
||||||
.insert(slot0, BankHashInfo::default());
|
|
||||||
assert!(!db.bank_hashes.read().unwrap().is_empty());
|
|
||||||
db.accounts_index.add_root(slot0);
|
db.accounts_index.add_root(slot0);
|
||||||
db.accounts_index.add_uncleaned_roots([slot0].into_iter());
|
db.accounts_index.add_uncleaned_roots([slot0].into_iter());
|
||||||
assert!(db.accounts_index.is_uncleaned_root(slot0));
|
assert!(db.accounts_index.is_uncleaned_root(slot0));
|
||||||
assert!(db.accounts_index.is_alive_root(slot0));
|
assert!(db.accounts_index.is_alive_root(slot0));
|
||||||
db.handle_dropped_roots_for_ancient(dropped_roots);
|
db.handle_dropped_roots_for_ancient(dropped_roots);
|
||||||
assert!(db.bank_hashes.read().unwrap().is_empty());
|
assert!(db.get_bank_hash_info(slot0).is_none());
|
||||||
assert!(!db.accounts_index.is_uncleaned_root(slot0));
|
assert!(!db.accounts_index.is_uncleaned_root(slot0));
|
||||||
assert!(!db.accounts_index.is_alive_root(slot0));
|
assert!(!db.accounts_index.is_alive_root(slot0));
|
||||||
}
|
}
|
||||||
|
@ -17461,10 +17589,7 @@ pub mod tests {
|
||||||
let db = AccountsDb::new_single_for_tests();
|
let db = AccountsDb::new_single_for_tests();
|
||||||
let slot0 = 0;
|
let slot0 = 0;
|
||||||
let dropped_roots = vec![slot0];
|
let dropped_roots = vec![slot0];
|
||||||
db.bank_hashes
|
db.set_bank_hash_info(slot0, BankHashInfo::default());
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(slot0, BankHashInfo::default());
|
|
||||||
insert_store(&db, entry);
|
insert_store(&db, entry);
|
||||||
db.handle_dropped_roots_for_ancient(dropped_roots);
|
db.handle_dropped_roots_for_ancient(dropped_roots);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6638,9 +6638,8 @@ impl Bank {
|
||||||
.rc
|
.rc
|
||||||
.accounts
|
.accounts
|
||||||
.accounts_db
|
.accounts_db
|
||||||
.get_bank_hash_info(slot)
|
.get_bank_hash_stats(slot)
|
||||||
.expect("No bank hash was found for this bank, that should not be possible")
|
.expect("No bank hash stats were found for this bank, that should not be possible");
|
||||||
.stats;
|
|
||||||
info!(
|
info!(
|
||||||
"bank frozen: {slot} hash: {hash} accounts_delta: {} signature_count: {} last_blockhash: {} capitalization: {}{}, stats: {bank_hash_stats:?}",
|
"bank frozen: {slot} hash: {hash} accounts_delta: {} signature_count: {} last_blockhash: {} capitalization: {}{}, stats: {bank_hash_stats:?}",
|
||||||
accounts_delta_hash.0,
|
accounts_delta_hash.0,
|
||||||
|
@ -6933,12 +6932,14 @@ impl Bank {
|
||||||
old
|
old
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_accounts_hash(&self) -> AccountsHash {
|
pub fn get_accounts_hash(&self) -> Option<AccountsHash> {
|
||||||
self.rc.accounts.accounts_db.get_accounts_hash(self.slot)
|
self.rc.accounts.accounts_db.get_accounts_hash(self.slot())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_snapshot_hash(&self) -> SnapshotHash {
|
pub fn get_snapshot_hash(&self) -> SnapshotHash {
|
||||||
let accounts_hash = self.get_accounts_hash();
|
let accounts_hash = self
|
||||||
|
.get_accounts_hash()
|
||||||
|
.expect("accounts hash is required to get snapshot hash");
|
||||||
let epoch_accounts_hash = self.get_epoch_accounts_hash_to_serialize();
|
let epoch_accounts_hash = self.get_epoch_accounts_hash_to_serialize();
|
||||||
SnapshotHash::new(&accounts_hash, epoch_accounts_hash.as_ref())
|
SnapshotHash::new(&accounts_hash, epoch_accounts_hash.as_ref())
|
||||||
}
|
}
|
||||||
|
@ -12903,12 +12904,12 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
// Re-adding builtin programs should be no-op
|
// Re-adding builtin programs should be no-op
|
||||||
bank.update_accounts_hash_for_tests();
|
bank.update_accounts_hash_for_tests();
|
||||||
let old_hash = bank.get_accounts_hash();
|
let old_hash = bank.get_accounts_hash().unwrap();
|
||||||
bank.add_builtin("mock_program1", &vote_id, mock_ix_processor);
|
bank.add_builtin("mock_program1", &vote_id, mock_ix_processor);
|
||||||
bank.add_builtin("mock_program2", &stake_id, mock_ix_processor);
|
bank.add_builtin("mock_program2", &stake_id, mock_ix_processor);
|
||||||
add_root_and_flush_write_cache(&bank);
|
add_root_and_flush_write_cache(&bank);
|
||||||
bank.update_accounts_hash_for_tests();
|
bank.update_accounts_hash_for_tests();
|
||||||
let new_hash = bank.get_accounts_hash();
|
let new_hash = bank.get_accounts_hash().unwrap();
|
||||||
assert_eq!(old_hash, new_hash);
|
assert_eq!(old_hash, new_hash);
|
||||||
{
|
{
|
||||||
let stakes = bank.stakes_cache.stakes();
|
let stakes = bank.stakes_cache.stakes();
|
||||||
|
|
|
@ -257,6 +257,10 @@ fn test_bank_serialize_style(
|
||||||
bank2.freeze();
|
bank2.freeze();
|
||||||
bank2.squash();
|
bank2.squash();
|
||||||
bank2.force_flush_accounts_cache();
|
bank2.force_flush_accounts_cache();
|
||||||
|
bank2
|
||||||
|
.accounts()
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[0; 32])));
|
||||||
|
|
||||||
let snapshot_storages = bank2.get_snapshot_storages(None);
|
let snapshot_storages = bank2.get_snapshot_storages(None);
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
@ -285,16 +289,13 @@ fn test_bank_serialize_style(
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let accounts_hash = if update_accounts_hash {
|
if update_accounts_hash {
|
||||||
let accounts_hash = AccountsHash(Hash::new(&[1; 32]));
|
|
||||||
bank2
|
bank2
|
||||||
.accounts()
|
.accounts()
|
||||||
.accounts_db
|
.accounts_db
|
||||||
.set_accounts_hash(bank2.slot(), accounts_hash);
|
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[1; 32])));
|
||||||
accounts_hash
|
}
|
||||||
} else {
|
let accounts_hash = bank2.get_accounts_hash().unwrap();
|
||||||
bank2.get_accounts_hash()
|
|
||||||
};
|
|
||||||
|
|
||||||
let slot = bank2.slot();
|
let slot = bank2.slot();
|
||||||
let incremental =
|
let incremental =
|
||||||
|
@ -406,7 +407,7 @@ fn test_bank_serialize_style(
|
||||||
assert_eq!(dbank.get_balance(&key1.pubkey()), 0);
|
assert_eq!(dbank.get_balance(&key1.pubkey()), 0);
|
||||||
assert_eq!(dbank.get_balance(&key2.pubkey()), 10);
|
assert_eq!(dbank.get_balance(&key2.pubkey()), 10);
|
||||||
assert_eq!(dbank.get_balance(&key3.pubkey()), 0);
|
assert_eq!(dbank.get_balance(&key3.pubkey()), 0);
|
||||||
assert_eq!(dbank.get_accounts_hash(), accounts_hash);
|
assert_eq!(dbank.get_accounts_hash(), Some(accounts_hash));
|
||||||
assert!(bank2 == dbank);
|
assert!(bank2 == dbank);
|
||||||
assert_eq!(dbank.incremental_snapshot_persistence, incremental);
|
assert_eq!(dbank.incremental_snapshot_persistence, incremental);
|
||||||
assert_eq!(dbank.get_epoch_accounts_hash_to_serialize().map(|epoch_accounts_hash| *epoch_accounts_hash.as_ref()), expected_epoch_accounts_hash,
|
assert_eq!(dbank.get_epoch_accounts_hash_to_serialize().map(|epoch_accounts_hash| *epoch_accounts_hash.as_ref()), expected_epoch_accounts_hash,
|
||||||
|
|
|
@ -2347,7 +2347,9 @@ pub fn package_and_archive_full_snapshot(
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let accounts_hash = bank.get_accounts_hash();
|
let accounts_hash = bank
|
||||||
|
.get_accounts_hash()
|
||||||
|
.expect("accounts hash is required for snapshot");
|
||||||
crate::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
crate::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
||||||
accounts_package.snapshot_links_dir(),
|
accounts_package.snapshot_links_dir(),
|
||||||
accounts_package.slot,
|
accounts_package.slot,
|
||||||
|
@ -2401,7 +2403,9 @@ pub fn package_and_archive_incremental_snapshot(
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let accounts_hash = bank.get_accounts_hash();
|
let accounts_hash = bank
|
||||||
|
.get_accounts_hash()
|
||||||
|
.expect("accounts hash is required for snapshot");
|
||||||
crate::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
crate::serde_snapshot::reserialize_bank_with_new_accounts_hash(
|
||||||
accounts_package.snapshot_links_dir(),
|
accounts_package.snapshot_links_dir(),
|
||||||
accounts_package.slot,
|
accounts_package.slot,
|
||||||
|
|
Loading…
Reference in New Issue