introduce UpsertReclaim (#26462)
This commit is contained in:
parent
5bffee248c
commit
b582e4ce0f
|
@ -7,7 +7,8 @@ use {
|
|||
solana_runtime::{
|
||||
account_info::AccountInfo,
|
||||
accounts_index::{
|
||||
AccountSecondaryIndexes, AccountsIndex, ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS,
|
||||
AccountSecondaryIndexes, AccountsIndex, UpsertReclaim,
|
||||
ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS,
|
||||
},
|
||||
},
|
||||
solana_sdk::{account::AccountSharedData, pubkey},
|
||||
|
@ -33,7 +34,7 @@ fn bench_accounts_index(bencher: &mut Bencher) {
|
|||
&AccountSecondaryIndexes::default(),
|
||||
AccountInfo::default(),
|
||||
&mut reclaims,
|
||||
false,
|
||||
UpsertReclaim::PopulateReclaims,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +52,7 @@ fn bench_accounts_index(bencher: &mut Bencher) {
|
|||
&AccountSecondaryIndexes::default(),
|
||||
AccountInfo::default(),
|
||||
&mut reclaims,
|
||||
false,
|
||||
UpsertReclaim::PopulateReclaims,
|
||||
);
|
||||
reclaims.clear();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ use {
|
|||
accounts_index::{
|
||||
AccountIndexGetResult, AccountSecondaryIndexes, AccountsIndex, AccountsIndexConfig,
|
||||
AccountsIndexRootsStats, AccountsIndexScanResult, IndexKey, IndexValue, IsCached,
|
||||
RefCount, ScanConfig, ScanResult, SlotList, SlotSlice, ZeroLamport,
|
||||
RefCount, ScanConfig, ScanResult, SlotList, SlotSlice, UpsertReclaim, ZeroLamport,
|
||||
ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS, ACCOUNTS_INDEX_CONFIG_FOR_TESTING,
|
||||
},
|
||||
accounts_index_storage::Startup,
|
||||
|
@ -7107,7 +7107,7 @@ impl AccountsDb {
|
|||
&self,
|
||||
infos: Vec<AccountInfo>,
|
||||
accounts: impl StorableAccounts<'a, T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) -> SlotList<AccountInfo> {
|
||||
let target_slot = accounts.target_slot();
|
||||
// using a thread pool here results in deadlock panics from bank_hashes.write()
|
||||
|
@ -7130,7 +7130,7 @@ impl AccountsDb {
|
|||
&self.account_indexes,
|
||||
info,
|
||||
&mut reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
});
|
||||
reclaims
|
||||
|
@ -7716,7 +7716,11 @@ impl AccountsDb {
|
|||
.fetch_add(store_accounts_time.as_us(), Ordering::Relaxed);
|
||||
let mut update_index_time = Measure::start("update_index");
|
||||
|
||||
let previous_slot_entry_was_cached = self.caching_enabled && is_cached_store;
|
||||
let reclaim = if self.caching_enabled && is_cached_store {
|
||||
UpsertReclaim::PreviousSlotEntryWasCached
|
||||
} else {
|
||||
UpsertReclaim::PopulateReclaims
|
||||
};
|
||||
|
||||
// if we are squashing a single slot, then we can expect a single dead slot
|
||||
let expected_single_dead_slot =
|
||||
|
@ -7726,7 +7730,7 @@ impl AccountsDb {
|
|||
// after the account are stored by the above `store_accounts_to`
|
||||
// call and all the accounts are stored, all reads after this point
|
||||
// will know to not check the cache anymore
|
||||
let mut reclaims = self.update_index(infos, accounts, previous_slot_entry_was_cached);
|
||||
let mut reclaims = self.update_index(infos, accounts, reclaim);
|
||||
|
||||
// For each updated account, `reclaims` should only have at most one
|
||||
// item (if the account was previously updated in this slot).
|
||||
|
@ -12690,7 +12694,8 @@ pub mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE: bool = false;
|
||||
const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE: UpsertReclaim =
|
||||
UpsertReclaim::PopulateReclaims;
|
||||
|
||||
#[test]
|
||||
fn test_delete_dependencies() {
|
||||
|
|
|
@ -70,6 +70,16 @@ pub type SlotSlice<'s, T> = &'s [(Slot, T)];
|
|||
pub type RefCount = u64;
|
||||
pub type AccountMap<V> = Arc<InMemAccountsIndex<V>>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// how accounts index 'upsert' should handle reclaims
|
||||
pub enum UpsertReclaim {
|
||||
/// previous entry for this slot in the index is expected to be cached, so irrelevant to reclaims
|
||||
PreviousSlotEntryWasCached,
|
||||
/// previous entry for this slot in the index may need to be reclaimed, so return it.
|
||||
/// reclaims is the only output of upsert, requiring a synchronous execution
|
||||
PopulateReclaims,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ScanConfig {
|
||||
/// checked by the scan. When true, abort scan.
|
||||
|
@ -1605,7 +1615,7 @@ impl<T: IndexValue> AccountsIndex<T> {
|
|||
account_indexes: &AccountSecondaryIndexes,
|
||||
account_info: T,
|
||||
reclaims: &mut SlotList<T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) {
|
||||
// vast majority of updates are to item already in accounts index, so store as raw to avoid unnecessary allocations
|
||||
let store_raw = true;
|
||||
|
@ -1631,13 +1641,7 @@ impl<T: IndexValue> AccountsIndex<T> {
|
|||
|
||||
{
|
||||
let r_account_maps = map.read().unwrap();
|
||||
r_account_maps.upsert(
|
||||
pubkey,
|
||||
new_item,
|
||||
Some(old_slot),
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
);
|
||||
r_account_maps.upsert(pubkey, new_item, Some(old_slot), reclaims, reclaim);
|
||||
}
|
||||
self.update_secondary_indexes(pubkey, account, account_indexes);
|
||||
}
|
||||
|
@ -2301,7 +2305,8 @@ pub mod tests {
|
|||
assert!(index.include_key(&pk2));
|
||||
}
|
||||
|
||||
const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE: bool = false;
|
||||
const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE: UpsertReclaim =
|
||||
UpsertReclaim::PopulateReclaims;
|
||||
|
||||
#[test]
|
||||
fn test_insert_no_ancestors() {
|
||||
|
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
accounts_index::{
|
||||
AccountMapEntry, AccountMapEntryInner, AccountMapEntryMeta, IndexValue,
|
||||
PreAllocatedAccountMapEntry, RefCount, SlotList, SlotSlice, ZeroLamport,
|
||||
PreAllocatedAccountMapEntry, RefCount, SlotList, SlotSlice, UpsertReclaim, ZeroLamport,
|
||||
},
|
||||
bucket_map_holder::{Age, BucketMapHolder},
|
||||
bucket_map_holder_stats::BucketMapHolderStats,
|
||||
|
@ -364,7 +364,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_value: PreAllocatedAccountMapEntry<T>,
|
||||
other_slot: Option<Slot>,
|
||||
reclaims: &mut SlotList<T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) {
|
||||
let mut updated_in_mem = true;
|
||||
// try to get it just from memory first using only a read lock
|
||||
|
@ -375,7 +375,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_value.into(),
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
// age is incremented by caller
|
||||
} else {
|
||||
|
@ -392,7 +392,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_value.into(),
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
current.set_age(self.storage.future_age_to_flush());
|
||||
}
|
||||
|
@ -407,13 +407,8 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
// We may like this to always run, but it is unclear.
|
||||
// If disk bucket needs to resize, then this call can stall for a long time.
|
||||
// Right now, we know it is safe during startup.
|
||||
let already_existed = self.upsert_on_disk(
|
||||
vacant,
|
||||
new_value,
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
);
|
||||
let already_existed = self
|
||||
.upsert_on_disk(vacant, new_value, other_slot, reclaims, reclaim);
|
||||
if !already_existed {
|
||||
self.stats().inc_insert();
|
||||
}
|
||||
|
@ -427,7 +422,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_value.into(),
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
disk_entry
|
||||
} else {
|
||||
|
@ -471,7 +466,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_value: (Slot, T),
|
||||
other_slot: Option<Slot>,
|
||||
reclaims: &mut SlotList<T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) {
|
||||
let mut slot_list = current.slot_list.write().unwrap();
|
||||
let (slot, new_entry) = new_value;
|
||||
|
@ -481,7 +476,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_entry,
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
if addref {
|
||||
current.add_un_ref(true);
|
||||
|
@ -504,7 +499,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
account_info: T,
|
||||
mut other_slot: Option<Slot>,
|
||||
reclaims: &mut SlotList<T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) -> bool {
|
||||
let mut addref = !account_info.is_cached();
|
||||
|
||||
|
@ -546,10 +541,13 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
// already replaced one entry, so this one has to be removed
|
||||
slot_list.remove(slot_list_index)
|
||||
};
|
||||
if previous_slot_entry_was_cached {
|
||||
assert!(is_cur_account_cached);
|
||||
} else {
|
||||
reclaims.push(reclaim_item);
|
||||
match reclaim {
|
||||
UpsertReclaim::PopulateReclaims => {
|
||||
reclaims.push(reclaim_item);
|
||||
}
|
||||
UpsertReclaim::PreviousSlotEntryWasCached => {
|
||||
assert!(is_cur_account_cached);
|
||||
}
|
||||
}
|
||||
|
||||
if matched_slot {
|
||||
|
@ -618,7 +616,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
(slot, account_info),
|
||||
None, // should be None because we don't expect a different slot # during index generation
|
||||
&mut Vec::default(),
|
||||
false,
|
||||
UpsertReclaim::PopulateReclaims, // this should be ignore?
|
||||
);
|
||||
(
|
||||
true, /* found in mem */
|
||||
|
@ -637,7 +635,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_entry,
|
||||
None, // not changing slots here since it doesn't exist in the index at all
|
||||
&mut Vec::default(),
|
||||
false,
|
||||
UpsertReclaim::PopulateReclaims,
|
||||
);
|
||||
(false, already_existed)
|
||||
} else {
|
||||
|
@ -652,7 +650,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
// There can be no 'other' slot in the list.
|
||||
None,
|
||||
&mut Vec::default(),
|
||||
false,
|
||||
UpsertReclaim::PopulateReclaims,
|
||||
);
|
||||
vacant.insert(disk_entry);
|
||||
(
|
||||
|
@ -694,7 +692,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
new_entry: PreAllocatedAccountMapEntry<T>,
|
||||
other_slot: Option<Slot>,
|
||||
reclaims: &mut SlotList<T>,
|
||||
previous_slot_entry_was_cached: bool,
|
||||
reclaim: UpsertReclaim,
|
||||
) -> bool {
|
||||
if let Some(disk) = self.bucket.as_ref() {
|
||||
let mut existed = false;
|
||||
|
@ -709,7 +707,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
account_info,
|
||||
other_slot,
|
||||
reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
if addref {
|
||||
ref_count += 1
|
||||
|
@ -1672,7 +1670,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_update_slot_list_other() {
|
||||
solana_logger::setup();
|
||||
let previous_slot_entry_was_cached = false;
|
||||
let reclaim = UpsertReclaim::PopulateReclaims;
|
||||
let new_slot = 0;
|
||||
let info = 1;
|
||||
let other_value = info + 1;
|
||||
|
@ -1689,7 +1687,7 @@ mod tests {
|
|||
info,
|
||||
other_slot,
|
||||
&mut reclaims,
|
||||
previous_slot_entry_was_cached
|
||||
reclaim
|
||||
),
|
||||
"other_slot: {:?}",
|
||||
other_slot
|
||||
|
@ -1711,7 +1709,7 @@ mod tests {
|
|||
info,
|
||||
other_slot,
|
||||
&mut reclaims,
|
||||
previous_slot_entry_was_cached
|
||||
reclaim
|
||||
),
|
||||
"other_slot: {:?}",
|
||||
other_slot
|
||||
|
@ -1732,7 +1730,7 @@ mod tests {
|
|||
info,
|
||||
other_slot,
|
||||
&mut reclaims,
|
||||
previous_slot_entry_was_cached
|
||||
reclaim
|
||||
),
|
||||
"other_slot: {:?}",
|
||||
other_slot
|
||||
|
@ -1805,7 +1803,7 @@ mod tests {
|
|||
info,
|
||||
other_slot,
|
||||
&mut reclaims,
|
||||
previous_slot_entry_was_cached,
|
||||
reclaim,
|
||||
);
|
||||
|
||||
// calculate expected results
|
||||
|
|
Loading…
Reference in New Issue