acctidx: unref returns whether refcount went negative (#27773)
This commit is contained in:
parent
17007fdda8
commit
cd44a0ab7b
|
@ -278,12 +278,15 @@ impl<T: IndexValue> AccountMapEntryInner<T> {
|
|||
self.set_dirty(true);
|
||||
}
|
||||
|
||||
pub fn unref(&self) {
|
||||
/// decrement the ref count
|
||||
/// return true if the old refcount was already 0. This indicates an under refcounting error in the system.
|
||||
pub fn unref(&self) -> bool {
|
||||
let previous = self.ref_count.fetch_sub(1, Ordering::Release);
|
||||
self.set_dirty(true);
|
||||
if previous == 0 {
|
||||
inc_new_counter_info!("accounts_index-deref_from_0", 1);
|
||||
}
|
||||
self.set_dirty(true);
|
||||
previous == 0
|
||||
}
|
||||
|
||||
pub fn dirty(&self) -> bool {
|
||||
|
@ -1378,7 +1381,9 @@ impl<T: IndexValue> AccountsIndex<T> {
|
|||
};
|
||||
cache = match result {
|
||||
AccountsIndexScanResult::Unref => {
|
||||
locked_entry.unref();
|
||||
if locked_entry.unref() {
|
||||
info!("scan: refcount of item already at 0: {pubkey}");
|
||||
}
|
||||
true
|
||||
}
|
||||
AccountsIndexScanResult::KeepInMemory => true,
|
||||
|
@ -4045,6 +4050,37 @@ pub mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unref() {
|
||||
let value = true;
|
||||
let key = solana_sdk::pubkey::new_rand();
|
||||
let index = AccountsIndex::<bool>::default_for_tests();
|
||||
let slot1 = 1;
|
||||
|
||||
index.upsert_simple_test(&key, slot1, value);
|
||||
|
||||
let map = index.get_bin(&key);
|
||||
for expected in [false, true] {
|
||||
assert!(map.get_internal(&key, |entry| {
|
||||
// check refcount BEFORE the unref
|
||||
assert_eq!(if expected { 0 } else { 1 }, entry.unwrap().ref_count());
|
||||
// first time, ref count was at 1, we can unref once. Unref should return false.
|
||||
// second time, ref count was at 0, it is an error to unref. Unref should return true
|
||||
assert_eq!(expected, entry.unwrap().unref());
|
||||
// check refcount AFTER the unref
|
||||
assert_eq!(
|
||||
if expected {
|
||||
(0 as RefCount).wrapping_sub(1)
|
||||
} else {
|
||||
0
|
||||
},
|
||||
entry.unwrap().ref_count()
|
||||
);
|
||||
(false, true)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean_rooted_entries_return() {
|
||||
solana_logger::setup();
|
||||
|
|
|
@ -8,6 +8,7 @@ use {
|
|||
bucket_map_holder_stats::BucketMapHolderStats,
|
||||
waitable_condvar::WaitableCondvar,
|
||||
},
|
||||
log::*,
|
||||
rand::{thread_rng, Rng},
|
||||
solana_bucket_map::bucket_api::BucketApi,
|
||||
solana_measure::measure::Measure,
|
||||
|
@ -439,7 +440,9 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||
pub fn unref(&self, pubkey: &Pubkey) {
|
||||
self.get_internal(pubkey, |entry| {
|
||||
if let Some(entry) = entry {
|
||||
entry.unref();
|
||||
if entry.unref() {
|
||||
info!("refcount of item already at 0: {pubkey}");
|
||||
}
|
||||
}
|
||||
(true, ())
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue