Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 4d3e328

Browse files
AcctIdx: PreAllocatedAccountMapEntry (#20117)
1 parent 61a3df6 commit 4d3e328

File tree

2 files changed

+109
-78
lines changed

2 files changed

+109
-78
lines changed

runtime/src/accounts_index.rs

Lines changed: 93 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,51 @@ impl<T: IndexValue> ReadAccountMapEntry<T> {
237237
}
238238
}
239239

240+
pub struct PreAllocatedAccountMapEntry<T: IndexValue> {
241+
entry: AccountMapEntry<T>,
242+
}
243+
244+
impl<T: IndexValue> From<PreAllocatedAccountMapEntry<T>> for AccountMapEntry<T> {
245+
fn from(source: PreAllocatedAccountMapEntry<T>) -> AccountMapEntry<T> {
246+
source.entry
247+
}
248+
}
249+
250+
impl<T: IndexValue> From<PreAllocatedAccountMapEntry<T>> for (Slot, T) {
251+
fn from(source: PreAllocatedAccountMapEntry<T>) -> (Slot, T) {
252+
source.entry.slot_list.write().unwrap().remove(0)
253+
}
254+
}
255+
256+
impl<T: IndexValue> PreAllocatedAccountMapEntry<T> {
257+
/// create an entry that is equivalent to this process:
258+
/// 1. new empty (refcount=0, slot_list={})
259+
/// 2. update(slot, account_info)
260+
/// This code is called when the first entry [ie. (slot,account_info)] for a pubkey is inserted into the index.
261+
pub fn new(
262+
slot: Slot,
263+
account_info: T,
264+
storage: &Arc<BucketMapHolder<T>>,
265+
) -> PreAllocatedAccountMapEntry<T> {
266+
Self::new_internal(slot, account_info, AccountMapEntryMeta::new_dirty(storage))
267+
}
268+
269+
fn new_internal(
270+
slot: Slot,
271+
account_info: T,
272+
meta: AccountMapEntryMeta,
273+
) -> PreAllocatedAccountMapEntry<T> {
274+
let ref_count = if account_info.is_cached() { 0 } else { 1 };
275+
PreAllocatedAccountMapEntry {
276+
entry: Arc::new(AccountMapEntryInner::new(
277+
vec![(slot, account_info)],
278+
ref_count,
279+
meta,
280+
)),
281+
}
282+
}
283+
}
284+
240285
#[self_referencing]
241286
pub struct WriteAccountMapEntry<T: IndexValue> {
242287
owned_entry: AccountMapEntry<T>,
@@ -266,23 +311,6 @@ impl<T: IndexValue> WriteAccountMapEntry<T> {
266311
self.borrow_owned_entry().set_dirty(true);
267312
result
268313
}
269-
270-
// create an entry that is equivalent to this process:
271-
// 1. new empty (refcount=0, slot_list={})
272-
// 2. update(slot, account_info)
273-
// This code is called when the first entry [ie. (slot,account_info)] for a pubkey is inserted into the index.
274-
pub fn new_entry_after_update(
275-
slot: Slot,
276-
account_info: T,
277-
storage: &Arc<BucketMapHolder<T>>,
278-
) -> AccountMapEntry<T> {
279-
let ref_count = if account_info.is_cached() { 0 } else { 1 };
280-
Arc::new(AccountMapEntryInner::new(
281-
vec![(slot, account_info)],
282-
ref_count,
283-
AccountMapEntryMeta::new_dirty(storage),
284-
))
285-
}
286314
}
287315

288316
#[derive(Debug, Default, AbiExample, Clone)]
@@ -1539,11 +1567,8 @@ impl<T: IndexValue> AccountsIndex<T> {
15391567
let is_zero_lamport = account_info.is_zero_lamport();
15401568
let result = if is_zero_lamport { Some(pubkey) } else { None };
15411569

1542-
let info = WriteAccountMapEntry::new_entry_after_update(
1543-
slot,
1544-
account_info,
1545-
&self.storage.storage,
1546-
);
1570+
let info =
1571+
PreAllocatedAccountMapEntry::new(slot, account_info, &self.storage.storage);
15471572
binned[bin].1.push((pubkey, info));
15481573
result
15491574
})
@@ -1609,20 +1634,25 @@ impl<T: IndexValue> AccountsIndex<T> {
16091634
// - The secondary index is never consulted as primary source of truth for gets/stores.
16101635
// So, what the accounts_index sees alone is sufficient as a source of truth for other non-scan
16111636
// account operations.
1612-
let new_item =
1613-
WriteAccountMapEntry::new_entry_after_update(slot, account_info, &self.storage.storage);
1637+
let new_item = PreAllocatedAccountMapEntry::new(slot, account_info, &self.storage.storage);
16141638
let map = &self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)];
16151639

16161640
let r_account_maps = map.read().unwrap();
1617-
if !r_account_maps.update_key_if_exists(
1641+
let (updated, new_item) = r_account_maps.update_key_if_exists(
16181642
pubkey,
1619-
&new_item,
1643+
new_item,
16201644
reclaims,
16211645
previous_slot_entry_was_cached,
1622-
) {
1646+
);
1647+
if !updated {
16231648
drop(r_account_maps);
16241649
let w_account_maps = map.write().unwrap();
1625-
w_account_maps.upsert(pubkey, new_item, reclaims, previous_slot_entry_was_cached);
1650+
w_account_maps.upsert(
1651+
pubkey,
1652+
new_item.unwrap(),
1653+
reclaims,
1654+
previous_slot_entry_was_cached,
1655+
);
16261656
}
16271657
self.update_secondary_indexes(pubkey, account_owner, account_data, account_indexes);
16281658
}
@@ -1967,6 +1997,18 @@ pub mod tests {
19671997
)
19681998
}
19691999

2000+
impl<T: IndexValue> Clone for PreAllocatedAccountMapEntry<T> {
2001+
fn clone(&self) -> Self {
2002+
// clone the AccountMapEntryInner into a new Arc
2003+
let (slot, info) = self.entry.slot_list.read().unwrap()[0];
2004+
let meta = AccountMapEntryMeta {
2005+
dirty: AtomicBool::new(self.entry.dirty()),
2006+
age: AtomicU8::new(self.entry.age()),
2007+
};
2008+
PreAllocatedAccountMapEntry::new_internal(slot, info, meta)
2009+
}
2010+
}
2011+
19702012
#[test]
19712013
fn test_bitfield_delete_non_excess() {
19722014
solana_logger::setup();
@@ -2790,11 +2832,8 @@ pub mod tests {
27902832
let account_info = AccountInfoTest::default();
27912833
let index = AccountsIndex::default_for_tests();
27922834

2793-
let new_entry = WriteAccountMapEntry::new_entry_after_update(
2794-
slot,
2795-
account_info,
2796-
&index.storage.storage,
2797-
);
2835+
let new_entry: AccountMapEntry<_> =
2836+
PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage).into();
27982837
assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 0);
27992838
assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
28002839
assert_eq!(
@@ -2806,11 +2845,8 @@ pub mod tests {
28062845
let account_info = true;
28072846
let index = AccountsIndex::default_for_tests();
28082847

2809-
let new_entry = WriteAccountMapEntry::new_entry_after_update(
2810-
slot,
2811-
account_info,
2812-
&index.storage.storage,
2813-
);
2848+
let new_entry: AccountMapEntry<_> =
2849+
PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage).into();
28142850
assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 1);
28152851
assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
28162852
assert_eq!(
@@ -2874,11 +2910,9 @@ pub mod tests {
28742910
assert_eq!(entry.ref_count(), if is_cached { 0 } else { 1 });
28752911
let expected = vec![(slot0, account_infos[0])];
28762912
assert_eq!(entry.slot_list().to_vec(), expected);
2877-
let new_entry = WriteAccountMapEntry::new_entry_after_update(
2878-
slot0,
2879-
account_infos[0],
2880-
&index.storage.storage,
2881-
);
2913+
let new_entry: AccountMapEntry<_> =
2914+
PreAllocatedAccountMapEntry::new(slot0, account_infos[0], &index.storage.storage)
2915+
.into();
28822916
assert_eq!(
28832917
entry.slot_list().to_vec(),
28842918
new_entry.slot_list.read().unwrap().to_vec(),
@@ -2924,12 +2958,9 @@ pub mod tests {
29242958
vec![(slot0, account_infos[0]), (slot1, account_infos[1])]
29252959
);
29262960

2927-
let new_entry = WriteAccountMapEntry::new_entry_after_update(
2928-
slot1,
2929-
account_infos[1],
2930-
&index.storage.storage,
2931-
);
2932-
assert_eq!(entry.slot_list()[1], new_entry.slot_list.read().unwrap()[0],);
2961+
let new_entry =
2962+
PreAllocatedAccountMapEntry::new(slot1, account_infos[1], &index.storage.storage);
2963+
assert_eq!(entry.slot_list()[1], new_entry.into());
29332964
}
29342965
}
29352966

@@ -2951,26 +2982,24 @@ pub mod tests {
29512982
let slot = 0;
29522983
let account_info = true;
29532984

2954-
let new_entry = WriteAccountMapEntry::new_entry_after_update(
2955-
slot,
2956-
account_info,
2957-
&index.storage.storage,
2958-
);
2985+
let new_entry =
2986+
PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage);
29592987
assert_eq!(0, account_maps_len_expensive(&index));
29602988

29612989
// will fail because key doesn't exist
29622990
let r_account_maps = index.get_account_maps_read_lock(&key.pubkey());
2963-
assert!(!r_account_maps.update_key_if_exists(
2964-
&key.pubkey(),
2965-
&new_entry,
2966-
&mut SlotList::default(),
2967-
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2968-
));
2969-
drop(r_account_maps);
2970-
assert_eq!(
2971-
(slot, account_info),
2972-
new_entry.slot_list.read().as_ref().unwrap()[0]
2991+
assert!(
2992+
!r_account_maps
2993+
.update_key_if_exists(
2994+
&key.pubkey(),
2995+
new_entry.clone(),
2996+
&mut SlotList::default(),
2997+
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2998+
)
2999+
.0
29733000
);
3001+
drop(r_account_maps);
3002+
assert_eq!((slot, account_info), new_entry.clone().into());
29743003

29753004
assert_eq!(0, account_maps_len_expensive(&index));
29763005
let w_account_maps = index.get_account_maps_write_lock(&key.pubkey());

runtime/src/in_mem_accounts_index.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::accounts_index::{
2-
AccountMapEntry, AccountMapEntryInner, AccountMapEntryMeta, IndexValue, RefCount, SlotList,
3-
SlotSlice,
2+
AccountMapEntry, AccountMapEntryInner, AccountMapEntryMeta, IndexValue,
3+
PreAllocatedAccountMapEntry, RefCount, SlotList, SlotSlice,
44
};
55
use crate::bucket_map_holder::{Age, BucketMapHolder};
66
use crate::bucket_map_holder_stats::BucketMapHolderStats;
@@ -219,7 +219,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
219219
pub fn upsert(
220220
&self,
221221
pubkey: &Pubkey,
222-
new_value: AccountMapEntry<T>,
222+
new_value: PreAllocatedAccountMapEntry<T>,
223223
reclaims: &mut SlotList<T>,
224224
previous_slot_entry_was_cached: bool,
225225
) {
@@ -239,7 +239,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
239239
let current = occupied.get_mut();
240240
Self::lock_and_update_slot_list(
241241
current,
242-
new_value.slot_list.write().unwrap().remove(0),
242+
new_value.into(),
243243
reclaims,
244244
previous_slot_entry_was_cached,
245245
);
@@ -252,14 +252,14 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
252252
// on disk, so merge new_value with what was on disk
253253
Self::lock_and_update_slot_list(
254254
&disk_entry,
255-
new_value.slot_list.write().unwrap().remove(0),
255+
new_value.into(),
256256
reclaims,
257257
previous_slot_entry_was_cached,
258258
);
259259
disk_entry
260260
} else {
261261
// not on disk, so insert new thing
262-
new_value
262+
new_value.into()
263263
};
264264
assert!(new_value.dirty());
265265
vacant.insert(new_value);
@@ -347,20 +347,20 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
347347
pub fn update_key_if_exists(
348348
&self,
349349
pubkey: &Pubkey,
350-
new_value: &AccountMapEntry<T>,
350+
new_value: PreAllocatedAccountMapEntry<T>,
351351
reclaims: &mut SlotList<T>,
352352
previous_slot_entry_was_cached: bool,
353-
) -> bool {
353+
) -> (bool, Option<PreAllocatedAccountMapEntry<T>>) {
354354
if let Some(current) = self.map().read().unwrap().get(pubkey) {
355355
Self::lock_and_update_slot_list(
356356
current,
357-
new_value.slot_list.write().unwrap().remove(0),
357+
new_value.into(),
358358
reclaims,
359359
previous_slot_entry_was_cached,
360360
);
361-
true
361+
(true, None)
362362
} else {
363-
false
363+
(false, Some(new_value))
364364
}
365365
}
366366

@@ -375,12 +375,13 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
375375
fn insert_returner(
376376
existing: &AccountMapEntry<T>,
377377
pubkey: &Pubkey,
378-
new_entry: AccountMapEntry<T>,
378+
new_entry: PreAllocatedAccountMapEntry<T>,
379379
) -> (AccountMapEntry<T>, T, Pubkey) {
380+
let (_slot, info): (Slot, T) = new_entry.into();
380381
(
381382
Arc::clone(existing),
382383
// extract the new account_info from the unused 'new_entry'
383-
new_entry.slot_list.write().unwrap().remove(0).1,
384+
info,
384385
*pubkey,
385386
)
386387
}
@@ -390,7 +391,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
390391
pub fn insert_new_entry_if_missing_with_lock(
391392
&self,
392393
pubkey: Pubkey,
393-
new_entry: AccountMapEntry<T>,
394+
new_entry: PreAllocatedAccountMapEntry<T>,
394395
) -> Option<(AccountMapEntry<T>, T, Pubkey)> {
395396
let m = Measure::start("entry");
396397
let mut map = self.map().write().unwrap();
@@ -420,6 +421,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
420421
result
421422
} else {
422423
// not on disk, so insert new thing and we're done
424+
let new_entry: AccountMapEntry<T> = new_entry.into();
423425
assert!(new_entry.dirty());
424426
vacant.insert(new_entry);
425427
None // returns None if item was created new

0 commit comments

Comments
 (0)