LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 264 444 59.5 %
Date: 2025-07-01 05:00:49 Functions: 15 225 6.7 %

          Line data    Source code
       1             : #include "fd_bank.h"
       2             : #include "../../util/fd_util_base.h"
       3             : 
       4             : ulong
       5          24 : fd_bank_align( void ) {
       6          24 :   return alignof(fd_bank_t);
       7          24 : }
       8             : 
       9             : ulong
      10           6 : fd_bank_footprint( void ) {
      11           6 :   ulong l = FD_LAYOUT_INIT;
      12           6 :   l = FD_LAYOUT_APPEND( l, fd_bank_align(), sizeof(fd_bank_t) );
      13           6 :   return FD_LAYOUT_FINI( l, fd_bank_align() );
      14           6 : }
      15             : 
      16             : /* Bank accesssors */
      17             : 
      18             : #define HAS_COW_1(type, name, footprint, align, has_lock)                                                          \
      19             :   type const *                                                                                                     \
      20           0 :   fd_bank_##name##_locking_query( fd_bank_t * bank ) {                                                             \
      21           0 :     fd_rwlock_read( &bank->name##_lock );                                                                          \
      22           0 :     /* If the pool element hasn't been setup yet, then return NULL */                                              \
      23           0 :     fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank );                                          \
      24           0 :     if( FD_UNLIKELY( name##_pool==NULL ) ) {                                                                       \
      25           0 :       FD_LOG_CRIT(( "NULL " #name " pool" ));                                                                      \
      26           0 :     }                                                                                                              \
      27           0 :     if( bank->name##_pool_idx==fd_bank_##name##_pool_idx_null( name##_pool ) ) {                                   \
      28           0 :       return NULL;                                                                                                 \
      29           0 :     }                                                                                                              \
      30           0 :     fd_bank_##name##_t * bank_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx );            \
      31           0 :     return (type *)bank_##name->data;                                                                              \
      32           0 :   }                                                                                                                \
      33             :   void                                                                                                             \
      34           0 :   fd_bank_##name##_end_locking_query( fd_bank_t * bank ) {                                                         \
      35           0 :     fd_rwlock_unread( &bank->name##_lock );                                                                        \
      36           0 :   }                                                                                                                \
      37             :   type *                                                                                                           \
      38           0 :   fd_bank_##name##_locking_modify( fd_bank_t * bank ) {                                                            \
      39           0 :     fd_rwlock_write( &bank->name##_lock );                                                                         \
      40           0 :     /* If the dirty flag is set, then we already have a pool element */                                            \
      41           0 :     /* that was copied over for the current bank. We can simply just */                                            \
      42           0 :     /* query the pool element and return it. */                                                                    \
      43           0 :     fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank );                                          \
      44           0 :     if( FD_UNLIKELY( name##_pool==NULL ) ) {                                                                       \
      45           0 :       FD_LOG_CRIT(( "NULL " #name " pool" ));                                                                      \
      46           0 :     }                                                                                                              \
      47           0 :     if( bank->name##_dirty ) {                                                                                     \
      48           0 :       fd_bank_##name##_t * bank_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx );          \
      49           0 :       return (type *)bank_##name->data;                                                                            \
      50           0 :     }                                                                                                              \
      51           0 :     fd_bank_##name##_t * child_##name = fd_bank_##name##_pool_ele_acquire( name##_pool );                          \
      52           0 :     if( FD_UNLIKELY( !child_##name ) ) {                                                                           \
      53           0 :       FD_LOG_CRIT(( "Failed to acquire " #name " pool element" ));                                                 \
      54           0 :     }                                                                                                              \
      55           0 :     /* If the dirty flag has not been set yet, we need to allocated a */                                           \
      56           0 :     /* new pool element and copy over the data from the parent idx.   */                                           \
      57           0 :     /* We also need to mark the dirty flag. */                                                                     \
      58           0 :     ulong child_idx = fd_bank_##name##_pool_idx( name##_pool, child_##name );                                      \
      59           0 :     if( bank->name##_pool_idx!=fd_bank_##name##_pool_idx_null( name##_pool ) ) {                                   \
      60           0 :       fd_bank_##name##_t * parent_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx );        \
      61           0 :       fd_memcpy( child_##name->data, parent_##name->data, fd_bank_##name##_footprint );                            \
      62           0 :     }                                                                                                              \
      63           0 :     bank->name##_pool_idx = child_idx;                                                                             \
      64           0 :     bank->name##_dirty    = 1;                                                                                     \
      65           0 :     return (type *)child_##name->data;                                                                             \
      66           0 :   }                                                                                                                \
      67             :   void                                                                                                             \
      68           0 :   fd_bank_##name##_end_locking_modify( fd_bank_t * bank ) {                                                        \
      69           0 :     fd_rwlock_unwrite( &bank->name##_lock );                                                                       \
      70           0 :   }
      71             : 
      72             : 
      73             : #define HAS_LOCK_0(type, name) \
      74             :   type const *                                             \
      75          42 :   fd_bank_##name##_query( fd_bank_t * bank ) {             \
      76          42 :     return (type const *)fd_type_pun_const( bank->name );  \
      77          42 :   }                                                        \
      78             :   type *                                                   \
      79           0 :   fd_bank_##name##_modify( fd_bank_t * bank ) {            \
      80           0 :     return (type *)fd_type_pun( bank->name );              \
      81           0 :   }
      82             : 
      83             : #define HAS_LOCK_1(type, name)                              \
      84             :   type const *                                              \
      85             :   fd_bank_##name##_locking_query( fd_bank_t * bank ) {      \
      86             :     fd_rwlock_read( &bank->name##_lock );                   \
      87             :     return (type const *)fd_type_pun_const( bank->name );   \
      88             :   }                                                         \
      89             :   type *                                                    \
      90             :   fd_bank_##name##_locking_modify( fd_bank_t * bank ) {     \
      91             :     fd_rwlock_write( &bank->name##_lock );                  \
      92             :     ACQUIRE_WRITE_##has_lock( name );                       \
      93             :     return (type *)fd_type_pun( bank->name );               \
      94             :   }                                                         \
      95             :   void                                                      \
      96             :   fd_bank_##name##_end_locking_query( fd_bank_t * bank ) {  \
      97             :     fd_rwlock_unread( &bank->name##_lock );                 \
      98             :   }                                                         \
      99             :   void                                                      \
     100             :   fd_bank_##name##_end_locking_modify( fd_bank_t * bank ) { \
     101             :     fd_rwlock_unwrite( &bank->name##_lock );                \
     102             :   }
     103             : 
     104             : #define HAS_COW_0(type, name, footprint, align, has_lock)   \
     105             :   HAS_LOCK_##has_lock(type, name)                           \
     106             :   void                                                      \
     107          15 :   fd_bank_##name##_set( fd_bank_t * bank, type value ) {    \
     108          15 :     FD_STORE( type, bank->name, value );                    \
     109          15 :   }                                                         \
     110             :   type                                                      \
     111          42 :   fd_bank_##name##_get( fd_bank_t * bank ) {                \
     112          42 :     type val = FD_LOAD( type, bank->name );                 \
     113          42 :     return val;                                             \
     114          42 :   }
     115             : 
     116             : #define X(type, name, footprint, align, cow, has_lock) \
     117             :   HAS_COW_##cow(type, name, footprint, align, has_lock)
     118             : FD_BANKS_ITER(X)
     119             : #undef X
     120             : #undef HAS_COW_0
     121             : #undef HAS_COW_1
     122             : #undef HAS_LOCK_0
     123             : #undef HAS_LOCK_1
     124             : 
     125             : /**********************************************************************/
     126             : 
     127             : ulong
     128         114 : fd_banks_align( void ) {
     129             :   /* TODO: The magic number here can probably be removed. */
     130         114 :   return 128UL;
     131         114 : }
     132             : 
     133             : ulong
     134          12 : fd_banks_footprint( ulong max_banks ) {
     135             : 
     136          12 :   ulong l = FD_LAYOUT_INIT;
     137          12 :   l = FD_LAYOUT_APPEND( l, fd_banks_align(),      sizeof(fd_banks_t) );
     138          12 :   l = FD_LAYOUT_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_banks ) );
     139          12 :   l = FD_LAYOUT_APPEND( l, fd_banks_map_align(),  fd_banks_map_footprint( max_banks ) );
     140             : 
     141             :   /* Need to count the footprint for all of the CoW pools. */
     142          12 :   #define HAS_COW_1(name) \
     143          96 :     l = FD_LAYOUT_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( max_banks ) );
     144             : 
     145             :   /* Do nothing for these. */
     146          12 :   #define HAS_COW_0(name)
     147             : 
     148          12 :   #define X(type, name, footprint, align, cow, has_lock) \
     149          96 :     HAS_COW_##cow(name)
     150          96 :   FD_BANKS_ITER(X)
     151          12 :   #undef X
     152          12 :   #undef HAS_COW_0
     153          12 :   #undef HAS_COW_1
     154             : 
     155          12 :   return FD_LAYOUT_FINI( l, fd_banks_align() );
     156          12 : }
     157             : 
     158             : void *
     159           6 : fd_banks_new( void * shmem, ulong max_banks ) {
     160             : 
     161           6 :   fd_banks_t * banks = (fd_banks_t *)shmem;
     162             : 
     163           6 :   if( FD_UNLIKELY( !banks ) ) {
     164           0 :     FD_LOG_WARNING(( "NULL banks" ));
     165           0 :     return NULL;
     166           0 :   }
     167             : 
     168           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks, fd_banks_align() ) ) ) {
     169           0 :     FD_LOG_WARNING(( "misaligned banks" ));
     170           0 :     return NULL;
     171           0 :   }
     172             : 
     173             :   /* Set the rwlock to unlocked. */
     174           6 :   fd_rwlock_unwrite( &banks->rwlock );
     175             : 
     176             :   /* First, layout the banks and the pool/map used by fd_banks_t. */
     177           6 :   FD_SCRATCH_ALLOC_INIT( l, banks );
     178           6 :   banks           = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),      sizeof(fd_banks_t) );
     179           6 :   void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_banks ) );
     180           6 :   void * map_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_map_align(),  fd_banks_map_footprint( max_banks ) );
     181             : 
     182             :   /* Need to layout all of the CoW pools. */
     183           0 :   #define HAS_COW_1(name) \
     184          48 :     void * name##_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( max_banks ) ); \
     185          48 :     memset( name##_pool_mem, 0, fd_bank_##name##_pool_footprint( max_banks ) );
     186             : 
     187             :   /* Do nothing for these. */
     188           0 :   #define HAS_COW_0(name)
     189             : 
     190           0 :   #define X(type, name, footprint, align, cow, has_lock) \
     191          48 :     HAS_COW_##cow(name)
     192          48 :   FD_BANKS_ITER(X)
     193          48 :   #undef X
     194          48 :   #undef HAS_COW_0
     195          48 :   #undef HAS_COW_1
     196             : 
     197          48 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() ) != (ulong)banks + fd_banks_footprint( max_banks ) ) ) {
     198           0 :     FD_LOG_WARNING(( "fd_banks_new: bad layout" ));
     199           0 :     return NULL;
     200           0 :   }
     201             : 
     202           6 :   void * pool = fd_banks_pool_new( pool_mem, max_banks );
     203           6 :   if( FD_UNLIKELY( !pool ) ) {
     204           0 :     FD_LOG_WARNING(( "Failed to create bank pool" ));
     205           0 :     return NULL;
     206           0 :   }
     207             : 
     208           6 :   fd_bank_t * bank_pool = fd_banks_pool_join( pool );
     209           6 :   if( FD_UNLIKELY( !bank_pool ) ) {
     210           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     211           0 :     return NULL;
     212           0 :   }
     213             : 
     214           6 :   fd_banks_set_bank_pool( banks, bank_pool );
     215             : 
     216           6 :   void * map = fd_banks_map_new( map_mem, max_banks, 999UL );
     217           6 :   if( FD_UNLIKELY( !map ) ) {
     218           0 :     FD_LOG_WARNING(( "Failed to create bank map" ));
     219           0 :     return NULL;
     220           0 :   }
     221             : 
     222           6 :   fd_banks_map_t * bank_map = fd_banks_map_join( map_mem );
     223           6 :   if( FD_UNLIKELY( !bank_map ) ) {
     224           0 :     FD_LOG_WARNING(( "Failed to join bank map" ));
     225           0 :     return NULL;
     226           0 :   }
     227             : 
     228           6 :   fd_banks_set_bank_map( banks, bank_map );
     229             : 
     230             :   /* Now, call _new() and _join() for all of the CoW pools. */
     231           6 :   #define HAS_COW_1(name)                                                             \
     232          48 :     void * name##_mem = fd_bank_##name##_pool_new( name##_pool_mem, max_banks );      \
     233          48 :     if( FD_UNLIKELY( !name##_mem ) ) {                                                \
     234           0 :       FD_LOG_WARNING(( "Failed to create " #name " pool" ));                          \
     235           0 :       return NULL;                                                                    \
     236           0 :     }                                                                                 \
     237          48 :     fd_bank_##name##_t * name##_pool = fd_bank_##name##_pool_join( name##_pool_mem ); \
     238          48 :     if( FD_UNLIKELY( !name##_pool ) ) {                                               \
     239           0 :       FD_LOG_WARNING(( "Failed to join " #name " pool" ));                            \
     240           0 :       return NULL;                                                                    \
     241           0 :     }                                                                                 \
     242          48 :     fd_banks_set_##name##_pool( banks, name##_pool );
     243             : 
     244             :   /* Do nothing for these. */
     245           6 :   #define HAS_COW_0(name)
     246             : 
     247           6 :   #define X(type, name, footprint, align, cow, has_lock) \
     248          48 :     HAS_COW_##cow(name)
     249          48 :   FD_BANKS_ITER(X)
     250           6 :   #undef X
     251           6 :   #undef HAS_COW_0
     252           6 :   #undef HAS_COW_1
     253             : 
     254           6 :   banks->max_banks = max_banks;
     255           6 :   banks->magic     = FD_BANKS_MAGIC;
     256             : 
     257           6 :   return shmem;
     258          90 : }
     259             : 
     260             : fd_banks_t *
     261           6 : fd_banks_join( void * mem ) {
     262           6 :   fd_banks_t * banks = (fd_banks_t *)mem;
     263             : 
     264           6 :   if( FD_UNLIKELY( !banks ) ) {
     265           0 :     FD_LOG_WARNING(( "NULL banks" ));
     266           0 :     return NULL;
     267           0 :   }
     268             : 
     269           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks, fd_banks_align() ) ) ) {
     270           0 :     FD_LOG_WARNING(( "misaligned banks" ));
     271           0 :     return NULL;
     272           0 :   }
     273             : 
     274           6 :   if( FD_UNLIKELY( banks->magic!=FD_BANKS_MAGIC ) ) {
     275           0 :     FD_LOG_WARNING(( "Invalid banks magic" ));
     276           0 :     return NULL;
     277           0 :   }
     278             : 
     279           6 :   FD_SCRATCH_ALLOC_INIT( l, banks );
     280           6 :   banks           = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),      sizeof(fd_banks_t) );
     281           6 :   void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( banks->max_banks ) );
     282           6 :   void * map_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_map_align(),  fd_banks_map_footprint( banks->max_banks ) );
     283             : 
     284             :   /* Need to layout all of the CoW pools. */
     285           0 :   #define HAS_COW_1(name) \
     286          48 :     void * name##_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( banks->max_banks ) );
     287             : 
     288             :   /* Don't need to layout if not CoW. */
     289           0 :   #define HAS_COW_0(name)
     290             : 
     291           0 :   #define X(type, name, footprint, align, cow, has_lock) \
     292          48 :     HAS_COW_##cow(name)
     293          48 :   FD_BANKS_ITER(X)
     294           0 :   #undef X
     295           0 :   #undef HAS_COW_0
     296           0 :   #undef HAS_COW_1
     297             : 
     298           6 :   FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() );
     299             : 
     300          48 :   fd_bank_t * banks_pool = fd_banks_get_bank_pool( banks );
     301          48 :   if( FD_UNLIKELY( !banks_pool ) ) {
     302           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     303           0 :     return NULL;
     304           0 :   }
     305             : 
     306           6 :   if( FD_UNLIKELY( banks_pool!=fd_banks_pool_join( pool_mem ) ) ) {
     307           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     308           0 :     return NULL;
     309           0 :   }
     310             : 
     311           6 :   fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
     312           6 :   if( FD_UNLIKELY( !bank_map ) ) {
     313           0 :     FD_LOG_WARNING(( "Failed to join bank map" ));
     314           0 :     return NULL;
     315           0 :   }
     316             : 
     317           6 :   if( FD_UNLIKELY( bank_map!=fd_banks_map_join( map_mem ) ) ) {
     318           0 :     FD_LOG_WARNING(( "Failed to join bank map" ));
     319           0 :     return NULL;
     320           0 :   }
     321             : 
     322             :   /* Now, call _join() for all of the CoW pools. */
     323           6 :   #define HAS_COW_1(name)                                                             \
     324          48 :     fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks );           \
     325          48 :     if( FD_UNLIKELY( !name##_pool ) ) {                                               \
     326           0 :       FD_LOG_WARNING(( "Failed to join " #name " pool" ));                            \
     327           0 :       return NULL;                                                                    \
     328           0 :     }                                                                                 \
     329          48 :     if( FD_UNLIKELY( name##_pool!=fd_bank_##name##_pool_join( name##_pool_mem ) ) ) { \
     330           0 :       FD_LOG_WARNING(( "Failed to join " #name " pool" ));                            \
     331           0 :       return NULL;                                                                    \
     332           0 :     }
     333             : 
     334             :   /* Do nothing when the field is not CoW. */
     335           6 :   #define HAS_COW_0(name)
     336             : 
     337           6 :   #define X(type, name, footprint, align, cow, has_lock) \
     338          48 :     HAS_COW_##cow(name)
     339          96 :   FD_BANKS_ITER(X)
     340           6 :   #undef X
     341           6 :   #undef HAS_COW_0
     342           6 :   #undef HAS_COW_1
     343             : 
     344             : 
     345           6 :   return banks;
     346          96 : }
     347             : 
     348             : void *
     349           0 : fd_banks_leave( fd_banks_t * banks ) {
     350             : 
     351           0 :   if( FD_UNLIKELY( !banks ) ) {
     352           0 :     FD_LOG_WARNING(( "NULL banks" ));
     353           0 :     return NULL;
     354           0 :   }
     355             : 
     356           0 :   return (void *)banks;
     357           0 : }
     358             : 
     359             : void *
     360           0 : fd_banks_delete( void * shmem ) {
     361             : 
     362           0 :   if( FD_UNLIKELY( !shmem ) ) {
     363           0 :     FD_LOG_WARNING(( "NULL banks" ));
     364           0 :     return NULL;
     365           0 :   }
     366             : 
     367           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shmem, fd_banks_align() ) ) ) {
     368           0 :     FD_LOG_WARNING(( "misaligned banks" ));
     369           0 :     return NULL;
     370           0 :   }
     371             : 
     372           0 :   return shmem;
     373           0 : }
     374             : 
     375             : fd_bank_t *
     376           6 : fd_banks_init_bank( fd_banks_t * banks, ulong slot ) {
     377             : 
     378           6 :   if( FD_UNLIKELY( !banks ) ) {
     379           0 :     FD_LOG_WARNING(( "NULL banks" ));
     380           0 :     return NULL;
     381           0 :   }
     382             : 
     383           6 :   fd_bank_t *      bank_pool = fd_banks_get_bank_pool( banks );
     384           6 :   fd_banks_map_t * bank_map  = fd_banks_get_bank_map( banks );
     385             : 
     386           6 :   fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
     387           6 :   if( FD_UNLIKELY( bank==NULL ) ) {
     388           0 :     FD_LOG_WARNING(( "Failed to acquire bank" ));
     389           0 :     return NULL;
     390           0 :   }
     391             : 
     392           6 :   memset( bank, 0, fd_bank_footprint() );
     393             : 
     394           6 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
     395           6 :   bank->slot        = slot;
     396           6 :   bank->next        = null_idx;
     397           6 :   bank->parent_idx  = null_idx;
     398           6 :   bank->child_idx   = null_idx;
     399           6 :   bank->sibling_idx = null_idx;
     400             : 
     401             :   /* Set all CoW fields to null. */
     402           6 :   #define HAS_COW_1(name)                                                             \
     403          48 :     fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks );           \
     404          48 :     fd_bank_set_##name##_pool( bank, name##_pool );                                   \
     405          48 :     bank->name##_pool_idx            = fd_bank_##name##_pool_idx_null( name##_pool ); \
     406          48 :     bank->name##_dirty               = 0;
     407             : 
     408             :   /* Do nothing for these. */
     409           6 :   #define HAS_COW_0(name)
     410             : 
     411           6 :   #define HAS_LOCK_1(name) \
     412          48 :     fd_rwlock_unwrite(&bank->name##_lock);
     413           6 :   #define HAS_LOCK_0(name)
     414             : 
     415           6 :   #define X(type, name, footprint, align, cow, has_lock) \
     416         318 :     HAS_COW_##cow(name);                                 \
     417         318 :     HAS_LOCK_##has_lock(name)
     418         318 :   FD_BANKS_ITER(X)
     419           6 :   #undef X
     420           6 :   #undef HAS_COW_0
     421           6 :   #undef HAS_COW_1
     422           6 :   #undef HAS_LOCK_0
     423           6 :   #undef HAS_LOCK_1
     424             : 
     425           6 :   fd_banks_map_ele_insert( bank_map, bank, bank_pool );
     426             : 
     427             :   /* Now that the node is inserted, update the root */
     428             : 
     429           6 :   banks->root     = slot;
     430           6 :   banks->root_idx = fd_banks_pool_idx( bank_pool, bank );
     431             : 
     432           6 :   return bank;
     433           6 : }
     434             : 
     435             : fd_bank_t *
     436          15 : fd_banks_get_bank( fd_banks_t * banks, ulong slot ) {
     437             : 
     438          15 :   fd_bank_t * bank = NULL;
     439             : 
     440          15 :   fd_rwlock_read( &banks->rwlock );
     441             : 
     442          15 :   fd_bank_t *      bank_pool = fd_banks_get_bank_pool( banks );
     443          15 :   fd_banks_map_t * bank_map  = fd_banks_get_bank_map( banks );
     444             : 
     445          15 :   bank = fd_banks_map_ele_query( bank_map, &slot, NULL, bank_pool );
     446          15 :   if( FD_UNLIKELY( !bank ) ) {
     447           6 :     FD_LOG_WARNING(( "Failed to get bank" ));
     448           6 :     return NULL;
     449           6 :   }
     450             : 
     451           9 :   fd_rwlock_unread( &banks->rwlock );
     452             : 
     453           9 :   return bank;
     454          15 : }
     455             : 
     456             : 
     457             : fd_bank_t *
     458             : fd_banks_clone_from_parent( fd_banks_t * banks,
     459             :                             ulong        slot,
     460          30 :                             ulong        parent_slot ) {
     461             : 
     462          30 :   fd_rwlock_write( &banks->rwlock );
     463             : 
     464          30 :   fd_bank_t *      bank_pool = fd_banks_get_bank_pool( banks );
     465          30 :   fd_banks_map_t * bank_map  = fd_banks_get_bank_map( banks );
     466             : 
     467             :   /* First query for the parent bank */
     468             : 
     469          30 :   fd_bank_t * parent_bank = fd_banks_map_ele_query( bank_map, &parent_slot, NULL, bank_pool );
     470             : 
     471          30 :   if( FD_UNLIKELY( !parent_bank ) ) {
     472           0 :     FD_LOG_WARNING(( "Failed to get bank" ));
     473           0 :     fd_rwlock_unwrite( &banks->rwlock );
     474           0 :     return NULL;
     475           0 :   }
     476             : 
     477          30 :   if( FD_UNLIKELY( parent_bank->slot != parent_slot ) ) {
     478           0 :     FD_LOG_WARNING(( "Parent slot mismatch" ));
     479           0 :     fd_rwlock_unwrite( &banks->rwlock );
     480           0 :     return NULL;
     481           0 :   }
     482             : 
     483          30 :   ulong parent_idx = fd_banks_pool_idx( bank_pool, parent_bank );
     484             : 
     485             :   /* Now acquire a new bank */
     486             : 
     487          30 :   fd_bank_t * new_bank = fd_banks_pool_ele_acquire( bank_pool );
     488          30 :   if( FD_UNLIKELY( !new_bank ) ) {
     489           0 :     FD_LOG_WARNING(( "Failed to acquire bank" ));
     490           0 :     fd_rwlock_unwrite( &banks->rwlock );
     491           0 :     return NULL;
     492           0 :   }
     493             : 
     494          30 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
     495             : 
     496          30 :   new_bank->slot        = slot;
     497          30 :   new_bank->next        = null_idx;
     498          30 :   new_bank->parent_idx  = null_idx;
     499          30 :   new_bank->child_idx   = null_idx;
     500          30 :   new_bank->sibling_idx = null_idx;
     501             : 
     502          30 :   fd_banks_map_ele_insert( bank_map, new_bank, bank_pool );
     503             : 
     504          30 :   ulong child_idx = fd_banks_pool_idx( bank_pool, new_bank );
     505             : 
     506             :   /* Link node->parent */
     507             : 
     508          30 :   new_bank->parent_idx = parent_idx;
     509             : 
     510             :   /* Link parent->node and sibling->node */
     511             : 
     512          30 :   if( FD_LIKELY( parent_bank->child_idx == null_idx ) ) {
     513             : 
     514             :     /* This is the first child so set as left-most child */
     515             : 
     516          18 :     parent_bank->child_idx = child_idx;
     517             : 
     518          18 :   } else {
     519             : 
     520             :     /* Already have children so iterate to right-most sibling. */
     521             : 
     522          12 :     fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
     523          15 :     while( curr_bank->sibling_idx != null_idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
     524             : 
     525             :     /* Link to right-most sibling. */
     526             : 
     527          12 :     curr_bank->sibling_idx = child_idx;
     528             : 
     529          12 :   }
     530             : 
     531             :   /* We want to copy over the fields from the parent to the child,
     532             :      except for the fields which correspond to the header of the bank
     533             :      struct which is used for pool and map management. We can take
     534             :      advantage of the fact that those fields are laid out at the top
     535             :      of the bank struct. */
     536             : 
     537          30 :   memcpy( (uchar *)new_bank + FD_BANK_HEADER_SIZE, (uchar *)parent_bank + FD_BANK_HEADER_SIZE, sizeof(fd_bank_t) - FD_BANK_HEADER_SIZE );
     538             : 
     539             :   /* Setup all of the CoW fields. */
     540          30 :   #define HAS_COW_1(name)                                                   \
     541         240 :     new_bank->name##_pool_idx        = parent_bank->name##_pool_idx;        \
     542         240 :     new_bank->name##_dirty           = 0UL;                                 \
     543         240 :     fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
     544         240 :     fd_bank_set_##name##_pool( new_bank, name##_pool );
     545             : 
     546             :   /* Do nothing if not CoW. */
     547          30 :   #define HAS_COW_0(name)
     548             : 
     549             :   /* Setup locks for new bank as free. */
     550          30 :   #define HAS_LOCK_1(name) \
     551         240 :     fd_rwlock_unwrite(&new_bank->name##_lock);
     552          30 :   #define HAS_LOCK_0(name)
     553             : 
     554          30 :   #define X(type, name, footprint, align, cow, has_lock) \
     555        1590 :     HAS_COW_##cow(name);                                 \
     556        1590 :     HAS_LOCK_##has_lock(name)
     557        1590 :   FD_BANKS_ITER(X)
     558          30 :   #undef X
     559          30 :   #undef HAS_COW_0
     560          30 :   #undef HAS_COW_1
     561          30 :   #undef HAS_LOCK_0
     562          30 :   #undef HAS_LOCK_1
     563             : 
     564          30 :   fd_rwlock_unwrite( &banks->rwlock );
     565             : 
     566          30 :   return new_bank;
     567          30 : }
     568             : 
     569             : fd_bank_t const *
     570           3 : fd_banks_publish( fd_banks_t * banks, ulong slot ) {
     571             : 
     572           3 :   fd_rwlock_write( &banks->rwlock );
     573             : 
     574           3 :   fd_bank_t *      bank_pool = fd_banks_get_bank_pool( banks );
     575           3 :   fd_banks_map_t * bank_map  = fd_banks_get_bank_map( banks );
     576             : 
     577           3 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
     578             : 
     579             :   /* We want to replace the old root with the new root. This means we
     580             :      have to remove banks that aren't descendants of the new root. */
     581             : 
     582           3 :   fd_bank_t const * old_root = fd_banks_root( banks );
     583           3 :   if( FD_UNLIKELY( !old_root ) ) {
     584           0 :     FD_LOG_WARNING(( "Failed to get root bank" ));
     585           0 :     fd_rwlock_unwrite( &banks->rwlock );
     586           0 :     return NULL;
     587           0 :   }
     588             : 
     589           3 :   fd_bank_t * new_root = fd_banks_map_ele_query( bank_map, &slot, NULL, bank_pool );
     590           3 :   if( FD_UNLIKELY( !new_root ) ) {
     591           0 :     FD_LOG_WARNING(( "Failed to get new root bank" ));
     592           0 :     fd_rwlock_unwrite( &banks->rwlock );
     593           0 :     return NULL;
     594           0 :   }
     595             : 
     596           3 :   fd_bank_t * head = fd_banks_map_ele_remove( bank_map, &old_root->slot, NULL, bank_pool );
     597           3 :   head->next       = fd_banks_pool_idx_null( bank_pool );
     598           3 :   fd_bank_t * tail = head;
     599             : 
     600          21 :   while( head ) {
     601          18 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, head->child_idx );
     602             : 
     603          36 :     while( FD_LIKELY( child ) ) {
     604             : 
     605          18 :       if( FD_LIKELY( child!=new_root ) ) {
     606             : 
     607             :         /* Remove the child from the map first and push onto the
     608             :            frontier list that needs to be iterated through */
     609          15 :         tail->next = fd_banks_map_idx_remove( bank_map,
     610          15 :                                               &child->slot,
     611          15 :                                               fd_banks_pool_idx_null( bank_pool ),
     612          15 :                                               bank_pool );
     613             : 
     614          15 :         tail       = fd_banks_pool_ele( bank_pool, tail->next );
     615          15 :         tail->next = fd_banks_pool_idx_null( bank_pool );
     616             : 
     617          15 :       }
     618             : 
     619          18 :       child = fd_banks_pool_ele( bank_pool, child->sibling_idx );
     620          18 :     }
     621             : 
     622          18 :     fd_bank_t * next = fd_banks_pool_ele( bank_pool, head->next );
     623             : 
     624             :     /* Decide if we need to free any CoW fields. We free a CoW member
     625             :        from its pool if the dirty flag is set unless it is the same
     626             :        pool that the new root uses. */
     627          18 :     #define HAS_COW_1(name)                                                             \
     628         144 :       if( head->name##_dirty && head->name##_pool_idx!=new_root->name##_pool_idx ) {    \
     629           0 :         fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks );        \
     630           0 :         fd_bank_##name##_pool_idx_release( name##_pool, head->name##_pool_idx );       \
     631           0 :       }
     632             :     /* Do nothing for these. */
     633          18 :     #define HAS_COW_0(name)
     634             : 
     635          18 :     #define X(type, name, footprint, align, cow, has_lock) \
     636         144 :       HAS_COW_##cow(name)
     637         144 :     FD_BANKS_ITER(X)
     638          18 :     #undef X
     639          18 :     #undef HAS_COW_0
     640          18 :     #undef HAS_COW_1
     641             : 
     642             : 
     643          18 :     fd_banks_pool_ele_release( bank_pool, head );
     644          18 :     head = next;
     645          18 :   }
     646             : 
     647             :   /* If the new root did not have the dirty bit set, that means the node
     648             :      didn't own the pool index. Change the ownership to the new root. */
     649           3 :   #define HAS_COW_1(name)                                                            \
     650          24 :     fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks );          \
     651          24 :     if( new_root->name##_pool_idx!=fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
     652           0 :       new_root->name##_dirty = 1;                                                    \
     653           0 :     }
     654             :   /* Do nothing if not CoW. */
     655           3 :   #define HAS_COW_0(name)
     656             : 
     657           3 :   #define X(type, name, footprint, align, cow, has_lock) \
     658          24 :     HAS_COW_##cow(name)
     659          24 :   FD_BANKS_ITER(X)
     660           3 :   #undef X
     661           3 :   #undef HAS_COW_0
     662           3 :   #undef HAS_COW_1
     663             : 
     664           3 :   new_root->parent_idx = null_idx;
     665           3 :   banks->root_idx      = fd_banks_map_idx_query( bank_map, &slot, null_idx, bank_pool );
     666           3 :   banks->root          = slot;
     667             : 
     668           3 :   fd_rwlock_unwrite( &banks->rwlock );
     669             : 
     670           3 :   return new_root;
     671           3 : }
     672             : 
     673             : void
     674           0 : fd_bank_clear_bank( fd_bank_t * bank ) {
     675             : 
     676           0 :   #define HAS_COW_1(type, name, footprint) \
     677           0 :     fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank ); \
     678           0 :     if( bank->name##_pool_idx==fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
     679           0 :       return; \
     680           0 :     } \
     681           0 :     fd_bank_##name##_t * name##_ele = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx ); \
     682           0 :     fd_memset( name##_ele->data, 0, footprint );
     683             : 
     684           0 :   #define HAS_COW_0(type, name, footprint) \
     685           0 :     fd_memset( bank->name, 0, footprint );
     686             : 
     687           0 :   #define X(type, name, footprint, align, cow, has_lock) \
     688           0 :     HAS_COW_##cow(type, name, footprint)
     689           0 :   FD_BANKS_ITER(X)
     690           0 :   #undef X
     691           0 :   #undef HAS_COW_0
     692           0 :   #undef HAS_COW_1
     693           0 : }

Generated by: LCOV version 1.14