@@ -200,6 +200,29 @@ impl AccountStorage {
200200 pub ( crate ) fn len ( & self ) -> usize {
201201 self . map . len ( )
202202 }
203+
204+ /// Returns the (slot, storage) tuples where `predicate` returns `true`
205+ ///
206+ /// This function is useful when not all storages are desired,
207+ /// as storages are only Arc::cloned if they pass the predicate.
208+ ///
209+ /// # Panics
210+ ///
211+ /// Panics if `shrink` is in progress.
212+ pub fn get_if (
213+ & self ,
214+ predicate : impl Fn ( & Slot , & AccountStorageEntry ) -> bool ,
215+ ) -> Box < [ ( Slot , Arc < AccountStorageEntry > ) ] > {
216+ assert ! ( self . no_shrink_in_progress( ) ) ;
217+ self . map
218+ . iter ( )
219+ . filter_map ( |entry| {
220+ let slot = entry. key ( ) ;
221+ let storage = & entry. value ( ) . storage ;
222+ predicate ( slot, storage) . then ( || ( * slot, Arc :: clone ( storage) ) )
223+ } )
224+ . collect ( )
225+ }
203226}
204227
205228/// iterate contents of AccountStorage without exposing internals
@@ -291,7 +314,11 @@ impl Default for AccountStorageStatus {
291314
292315#[ cfg( test) ]
293316pub ( crate ) mod tests {
294- use { super :: * , crate :: accounts_file:: AccountsFileProvider , std:: path:: Path } ;
317+ use {
318+ super :: * ,
319+ crate :: accounts_file:: AccountsFileProvider ,
320+ std:: { iter, path:: Path } ,
321+ } ;
295322
296323 #[ test]
297324 fn test_shrink_in_progress ( ) {
@@ -568,4 +595,52 @@ pub(crate) mod tests {
568595 . is_none( ) ) ;
569596 assert ! ( storage. get_account_storage_entry( slot, id) . is_some( ) ) ;
570597 }
598+
599+ #[ test]
600+ fn test_get_if ( ) {
601+ let storage = AccountStorage :: default ( ) ;
602+ assert ! ( storage. get_if( |_, _| true ) . is_empty( ) ) ;
603+
604+ // add some entries
605+ let ids = [ 123 , 456 , 789 ] ;
606+ for id in ids {
607+ let slot = id as Slot ;
608+ let entry = AccountStorageEntry :: new (
609+ Path :: new ( "" ) ,
610+ slot,
611+ id,
612+ 5000 ,
613+ AccountsFileProvider :: AppendVec ,
614+ ) ;
615+ storage. map . insert (
616+ slot,
617+ AccountStorageReference {
618+ id,
619+ storage : entry. into ( ) ,
620+ } ,
621+ ) ;
622+ }
623+
624+ // look 'em up
625+ for id in ids {
626+ let found = storage. get_if ( |slot, _| * slot == id as Slot ) ;
627+ assert ! ( found
628+ . iter( )
629+ . map( |( slot, _) | * slot)
630+ . eq( iter:: once( id as Slot ) ) ) ;
631+ }
632+
633+ assert ! ( storage. get_if( |_, _| false ) . is_empty( ) ) ;
634+ assert_eq ! ( storage. get_if( |_, _| true ) . len( ) , ids. len( ) ) ;
635+ }
636+
637+ #[ test]
638+ #[ should_panic( expected = "self.no_shrink_in_progress()" ) ]
639+ fn test_get_if_fail ( ) {
640+ let storage = AccountStorage :: default ( ) ;
641+ storage
642+ . shrink_in_progress_map
643+ . insert ( 0 , storage. get_test_storage ( ) ) ;
644+ storage. get_if ( |_, _| true ) ;
645+ }
571646}
0 commit comments