@@ -237,6 +237,51 @@ impl<T: IndexValue> ReadAccountMapEntry<T> {
237
237
}
238
238
}
239
239
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
+
240
285
#[ self_referencing]
241
286
pub struct WriteAccountMapEntry < T : IndexValue > {
242
287
owned_entry : AccountMapEntry < T > ,
@@ -266,23 +311,6 @@ impl<T: IndexValue> WriteAccountMapEntry<T> {
266
311
self . borrow_owned_entry ( ) . set_dirty ( true ) ;
267
312
result
268
313
}
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
- }
286
314
}
287
315
288
316
#[ derive( Debug , Default , AbiExample , Clone ) ]
@@ -1539,11 +1567,8 @@ impl<T: IndexValue> AccountsIndex<T> {
1539
1567
let is_zero_lamport = account_info. is_zero_lamport ( ) ;
1540
1568
let result = if is_zero_lamport { Some ( pubkey) } else { None } ;
1541
1569
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 ) ;
1547
1572
binned[ bin] . 1 . push ( ( pubkey, info) ) ;
1548
1573
result
1549
1574
} )
@@ -1609,20 +1634,25 @@ impl<T: IndexValue> AccountsIndex<T> {
1609
1634
// - The secondary index is never consulted as primary source of truth for gets/stores.
1610
1635
// So, what the accounts_index sees alone is sufficient as a source of truth for other non-scan
1611
1636
// 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 ) ;
1614
1638
let map = & self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey) ] ;
1615
1639
1616
1640
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 (
1618
1642
pubkey,
1619
- & new_item,
1643
+ new_item,
1620
1644
reclaims,
1621
1645
previous_slot_entry_was_cached,
1622
- ) {
1646
+ ) ;
1647
+ if !updated {
1623
1648
drop ( r_account_maps) ;
1624
1649
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
+ ) ;
1626
1656
}
1627
1657
self . update_secondary_indexes ( pubkey, account_owner, account_data, account_indexes) ;
1628
1658
}
@@ -1967,6 +1997,18 @@ pub mod tests {
1967
1997
)
1968
1998
}
1969
1999
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
+
1970
2012
#[ test]
1971
2013
fn test_bitfield_delete_non_excess ( ) {
1972
2014
solana_logger:: setup ( ) ;
@@ -2790,11 +2832,8 @@ pub mod tests {
2790
2832
let account_info = AccountInfoTest :: default ( ) ;
2791
2833
let index = AccountsIndex :: default_for_tests ( ) ;
2792
2834
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 ( ) ;
2798
2837
assert_eq ! ( new_entry. ref_count. load( Ordering :: Relaxed ) , 0 ) ;
2799
2838
assert_eq ! ( new_entry. slot_list. read( ) . unwrap( ) . capacity( ) , 1 ) ;
2800
2839
assert_eq ! (
@@ -2806,11 +2845,8 @@ pub mod tests {
2806
2845
let account_info = true ;
2807
2846
let index = AccountsIndex :: default_for_tests ( ) ;
2808
2847
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 ( ) ;
2814
2850
assert_eq ! ( new_entry. ref_count. load( Ordering :: Relaxed ) , 1 ) ;
2815
2851
assert_eq ! ( new_entry. slot_list. read( ) . unwrap( ) . capacity( ) , 1 ) ;
2816
2852
assert_eq ! (
@@ -2874,11 +2910,9 @@ pub mod tests {
2874
2910
assert_eq ! ( entry. ref_count( ) , if is_cached { 0 } else { 1 } ) ;
2875
2911
let expected = vec ! [ ( slot0, account_infos[ 0 ] ) ] ;
2876
2912
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 ( ) ;
2882
2916
assert_eq ! (
2883
2917
entry. slot_list( ) . to_vec( ) ,
2884
2918
new_entry. slot_list. read( ) . unwrap( ) . to_vec( ) ,
@@ -2924,12 +2958,9 @@ pub mod tests {
2924
2958
vec![ ( slot0, account_infos[ 0 ] ) , ( slot1, account_infos[ 1 ] ) ]
2925
2959
) ;
2926
2960
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( ) ) ;
2933
2964
}
2934
2965
}
2935
2966
@@ -2951,26 +2982,24 @@ pub mod tests {
2951
2982
let slot = 0 ;
2952
2983
let account_info = true ;
2953
2984
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 ) ;
2959
2987
assert_eq ! ( 0 , account_maps_len_expensive( & index) ) ;
2960
2988
2961
2989
// will fail because key doesn't exist
2962
2990
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
2973
3000
) ;
3001
+ drop ( r_account_maps) ;
3002
+ assert_eq ! ( ( slot, account_info) , new_entry. clone( ) . into( ) ) ;
2974
3003
2975
3004
assert_eq ! ( 0 , account_maps_len_expensive( & index) ) ;
2976
3005
let w_account_maps = index. get_account_maps_write_lock ( & key. pubkey ( ) ) ;
0 commit comments