LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 105 116 90.5 %
Date: 2025-07-01 05:00:49 Functions: 29 4255 0.7 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_bank_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_bank_h
       3             : 
       4             : #include "../fd_flamenco_base.h"
       5             : 
       6             : #include "../../ballet/lthash/fd_lthash.h"
       7             : #include "../../funk/fd_funk.h"
       8             : 
       9             : #include "../types/fd_types.h"
      10             : #include "../leaders/fd_leaders.h"
      11             : #include "../features/fd_features.h"
      12             : #include "../fd_rwlock.h"
      13             : 
      14             : FD_PROTOTYPES_BEGIN
      15             : 
      16           6 : #define FD_BANKS_MAGIC 0X99999AA9999UL
      17             : 
      18             : /* TODO: Some optimizations, cleanups, future work:
      19             :    1. Simple data types (ulong, int, etc) should be stored as their
      20             :       underlying type instead of a byte array.
      21             :    2. Remove the slot_ctx entirely and just use the bank struct
      22             :       directly in the runtime.
      23             :    3. For some of the more complex types in the bank, we should provide
      24             :       a way to layout the data ahead of time instead of manually.
      25             :       calculating the offsets/layout of the offset-based struct.
      26             :       This could likely be emitted from fd_types
      27             :    4. Perhaps make the query/modify scoping more explicit. Right now,
      28             :       the caller is free to use the API wrong if there are no locks.
      29             :       Maybe just expose a different API if there are no locks?
      30             :    5. Rename fd_banks_t to fd_bank_mgr_t.
      31             :    7. Add locks around the CoW pools.
      32             :    8. Rename locks to suffix with _query_locking and _query_locking_end
      33             :   */
      34             : 
      35             : /* A fd_bank_t struct is the represenation of the bank state on Solana
      36             :    for a given slot. More specifically, the bank state corresponds to
      37             :    all information needed during execution that is not stored on-chain,
      38             :    but is instead cached in a validator's memory. Each of these bank
      39             :    fields are repesented by a member of the fd_bank_t struct.
      40             : 
      41             :    Management of fd_bank_t structs must be fork-aware: the state of each
      42             :    fd_bank_t must be based on the fd_bank_t of it's parent slot. This
      43             :    state is managed by the fd_banks_t struct.
      44             : 
      45             :    In order to support fork-awareness, there are a few key features
      46             :    that fd_banks_t and fd_bank_t MUST support:
      47             :    1. Query for any non-rooted slot's bank: create a fast lookup
      48             :       from slot to bank
      49             :    2. Be able to create a new bank for a given slot from the bank of
      50             :       that slot's parent and maintain some tree-like structure to
      51             :       track the parent-child relationships: copy the contents from a
      52             :       parent bank into a child bank.
      53             :    3. Prune the set of active banks to keep the root updated as the
      54             :       network progresses: free resources of fd_bank_t structs that
      55             :       are are not direct descendants of the root bank (remove parents
      56             :       and any competing lineages).
      57             :    4. Each bank will have field(s) that are concurrently read/write
      58             :       from multiple threads: add read-write locks to the fields that are
      59             :       concurrently written to.
      60             :    5. In practice, a bank state for a given slot can be very large and
      61             :       not all of the fields are written to every slot. Therefore, it can
      62             :       be very expensive to copy the entire bank state for a given slot
      63             :       each time a bank is created. In order to avoid large memcpys, we
      64             :       can use a CoW mechanism for certain fields.
      65             : 
      66             :   Each field of a fd_bank_t has a pre-specified set of fields including
      67             :     - name: the name of the field
      68             :     - footprint: the size of the field in bytes
      69             :     - align: the alignment of the field
      70             :     - CoW: whether the field is CoW
      71             :     - has_lock: whether the field has a rw-lock
      72             :     - type: type of the field
      73             : 
      74             :   fd_banks_t is represented by a left-child, right-sibling n-ary tree
      75             :   (as inspired by fd_ghost) to keep track of the parent-child fork tree.
      76             :   The underlying data structure is a map of fd_bank_t structs that is
      77             :   keyed by slot. This map is backed by a simple memory pool.
      78             : 
      79             :   Each field in fd_bank_t that is not CoW is laid out contiguously in
      80             :   the fd_bank_t struct as simple uchar buffers. This allows for a simple
      81             :   memcpy to clone the bank state from a parent to a child.
      82             : 
      83             :   Each field that is CoW has its own memory pool. The memory
      84             :   corresponding to the field is not located in the fd_bank_t struct and
      85             :   is instead represented by a pool index and a dirty flag. If the field
      86             :   is modified, then the dirty flag is set, and an element of the pool
      87             :   is acquired and the data is copied over from the parent pool idx.
      88             : 
      89             :   fd_bank_t also holds all of the rw-locks for the fields that have
      90             :   rw-locks.
      91             : 
      92             :   So, when a bank is cloned from a parent, the non CoW fields are copied
      93             :   over and the CoW fields just copy over a pool index. The CoW behavior
      94             :   is completely abstracted away from the caller as callers have to
      95             :   query/modify fields using specific APIs.
      96             : 
      97             :   NOTE: An important invariant is that if a field is CoW, then it must
      98             :   have a rw-lock.
      99             : 
     100             :   The usage pattern is as follows:
     101             : 
     102             :    To create an initial bank:
     103             :    fd_bank_t * bank_init = fd_bank_init_bank( banks, slot );
     104             : 
     105             :    To clone bank from parent banks:
     106             :    fd_bank_t * bank_clone = fd_banks_clone_from_parent( banks, slot, parent_slot );
     107             : 
     108             :    To publish a bank (aka update the root bank):
     109             :    fd_bank_t * bank_publish = fd_banks_publish( banks, slot );
     110             : 
     111             :    To query some arbitrary bank:
     112             :    fd_bank_t * bank_query = fd_banks_get_bank( banks, slot );
     113             : 
     114             :   To access fields in the bank if a field does not have a lock:
     115             : 
     116             :   fd_struct_t const * field = fd_bank_field_query( bank );
     117             :   OR
     118             :   fd_struct field = fd_bank_field_get( bank );
     119             : 
     120             :   To modify fields in the bank if a field does not have a lock:
     121             : 
     122             :   fd_struct_t * field = fd_bank_field_modify( bank );
     123             :   OR
     124             :   fd_bank_field_set( bank, value );
     125             : 
     126             :   IMPORTANT SAFETY NOTE: fd_banks_t assumes that there is only one bank
     127             :   being executed against at a time. However, it is safe to call
     128             :   fd_banks_publish while threads are executing against a bank.
     129             : 
     130             :   */
     131             : 
     132             : /* Define additional fields to the bank struct here. If trying to add
     133             :    a CoW field to the bank, define a pool for it as done below. */
     134             : 
     135             : #define FD_BANKS_ITER(X)                                                                                                                                                                                                             \
     136             :   /* type,                             name,                        footprint,                                 align,                                      CoW, has lock */                                                          \
     137          93 :   X(fd_clock_timestamp_votes_global_t, clock_timestamp_votes,       5000000UL,                                 128UL,                                      1,   1    )  /* TODO: This needs to get sized out */                      \
     138          93 :   X(fd_account_keys_global_t,          stake_account_keys,          100000000UL,                               128UL,                                      1,   1    )  /* Supports roughly 3M stake accounts */                     \
     139          93 :   X(fd_account_keys_global_t,          vote_account_keys,           3200000UL,                                 128UL,                                      1,   1    )  /* Supports roughly 100k vote accounts */                    \
     140          36 :   X(fd_block_hash_queue_global_t,      block_hash_queue,            50000UL,                                   128UL,                                      0,   0    )  /* Block hash queue */                                       \
     141          36 :   X(fd_fee_rate_governor_t,            fee_rate_governor,           sizeof(fd_fee_rate_governor_t),            alignof(fd_fee_rate_governor_t),            0,   0    )  /* Fee rate governor */                                      \
     142          36 :   X(ulong,                             capitalization,              sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Capitalization */                                         \
     143          36 :   X(ulong,                             lamports_per_signature,      sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Lamports per signature */                                 \
     144          36 :   X(ulong,                             prev_lamports_per_signature, sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Previous lamports per signature */                        \
     145          36 :   X(ulong,                             transaction_count,           sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Transaction count */                                      \
     146          36 :   X(ulong,                             parent_signature_cnt,        sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Parent signature count */                                 \
     147          36 :   X(ulong,                             tick_height,                 sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Tick height */                                            \
     148          36 :   X(ulong,                             max_tick_height,             sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Max tick height */                                        \
     149          36 :   X(ulong,                             hashes_per_tick,             sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Hashes per tick */                                        \
     150          36 :   X(uint128,                           ns_per_slot,                 sizeof(uint128),                           alignof(uint128),                           0,   0    )  /* NS per slot */                                            \
     151          36 :   X(ulong,                             ticks_per_slot,              sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Ticks per slot */                                         \
     152          36 :   X(ulong,                             genesis_creation_time,       sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Genesis creation time */                                  \
     153          36 :   X(double,                            slots_per_year,              sizeof(double),                            alignof(double),                            0,   0    )  /* Slots per year */                                         \
     154          36 :   X(fd_inflation_t,                    inflation,                   sizeof(fd_inflation_t),                    alignof(fd_inflation_t),                    0,   0    )  /* Inflation */                                              \
     155          36 :   X(ulong,                             total_epoch_stake,           sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Total epoch stake */                                      \
     156          24 :                                                                                                                                                                         /* This is only used for the get_epoch_stake syscall. */     \
     157          24 :                                                                                                                                                                         /* If we are executing in epoch E, this is the total */      \
     158          24 :                                                                                                                                                                         /* stake at the end of epoch E-1. */                         \
     159          36 :   X(ulong,                             eah_start_slot,              sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* EAH start slot */                                         \
     160          36 :   X(ulong,                             eah_stop_slot,               sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* EAH stop slot */                                          \
     161          36 :   X(ulong,                             eah_interval,                sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* EAH interval */                                           \
     162          36 :   X(ulong,                             block_height,                sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Block height */                                           \
     163          36 :   X(fd_hash_t,                         epoch_account_hash,          sizeof(fd_hash_t),                         alignof(fd_hash_t),                         0,   0    )  /* Epoch account hash */                                     \
     164          36 :   X(ulong,                             execution_fees,              sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Execution fees */                                         \
     165          36 :   X(ulong,                             priority_fees,               sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Priority fees */                                          \
     166          36 :   X(ulong,                             signature_count,             sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Signature count */                                        \
     167          36 :   X(ulong,                             use_prev_epoch_stake,        sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Use prev epoch stake */                                   \
     168          36 :   X(fd_hash_t,                         poh,                         sizeof(fd_hash_t),                         alignof(fd_hash_t),                         0,   0    )  /* PoH */                                                    \
     169          36 :   X(fd_sol_sysvar_last_restart_slot_t, last_restart_slot,           sizeof(fd_sol_sysvar_last_restart_slot_t), alignof(fd_sol_sysvar_last_restart_slot_t), 0,   0    )  /* Last restart slot */                                      \
     170          36 :   X(fd_cluster_version_t,              cluster_version,             sizeof(fd_cluster_version_t),              alignof(fd_cluster_version_t),              0,   0    )  /* Cluster version */                                        \
     171          36 :   X(ulong,                             prev_slot,                   sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Previous slot */                                          \
     172          36 :   X(fd_hash_t,                         bank_hash,                   sizeof(fd_hash_t),                         alignof(fd_hash_t),                         0,   0    )  /* Bank hash */                                              \
     173          36 :   X(fd_hash_t,                         prev_bank_hash,              sizeof(fd_hash_t),                         alignof(fd_hash_t),                         0,   0    )  /* Previous bank hash */                                     \
     174          36 :   X(fd_hash_t,                         genesis_hash,                sizeof(fd_hash_t),                         alignof(fd_hash_t),                         0,   0    )  /* Genesis hash */                                           \
     175          36 :   X(fd_epoch_schedule_t,               epoch_schedule,              sizeof(fd_epoch_schedule_t),               alignof(fd_epoch_schedule_t),               0,   0    )  /* Epoch schedule */                                         \
     176          36 :   X(fd_rent_t,                         rent,                        sizeof(fd_rent_t),                         alignof(fd_rent_t),                         0,   0    )  /* Rent */                                                   \
     177          36 :   X(fd_slot_lthash_t,                  lthash,                      sizeof(fd_slot_lthash_t),                  alignof(fd_slot_lthash_t),                  0,   0    )  /* LTHash */                                                 \
     178          93 :   X(fd_vote_accounts_global_t,         next_epoch_stakes,           200000000UL,                               128UL,                                      1,   1    )  /* Next epoch stakes, ~4K per account * 50k vote accounts */ \
     179          24 :                                                                                                                                                                         /* These are the stakes that determine the leader */         \
     180          24 :                                                                                                                                                                         /* schedule for the upcoming epoch.  If we are executing */  \
     181          24 :                                                                                                                                                                         /* in epoch E, these are the stakes at the end of epoch */   \
     182          24 :                                                                                                                                                                         /* E-1 and they determined the leader schedule for epoch */  \
     183          24 :                                                                                                                                                                         /* E+1. */                                                   \
     184          93 :   X(fd_vote_accounts_global_t,         epoch_stakes,                200000000UL,                               128UL,                                      1,   1    )  /* Epoch stakes ~4K per account * 50k vote accounts */       \
     185          93 :   X(fd_epoch_reward_status_global_t,   epoch_reward_status,         160000000UL,                               128UL,                                      1,   1    )  /* Epoch reward status */                                    \
     186          93 :   X(fd_epoch_leaders_t,                epoch_leaders,               1000000UL,                                 128UL,                                      1,   1    )  /* Epoch leaders */                                          \
     187          93 :   X(fd_stakes_global_t,                stakes,                      400000000UL,                               128UL,                                      1,   1    )  /* Stakes */                                                 \
     188          36 :   X(fd_features_t,                     features,                    sizeof(fd_features_t),                     alignof(fd_features_t),                     0,   0    )  /* Features */                                               \
     189          36 :   X(ulong,                             txn_count,                   sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Transaction count */                                      \
     190          36 :   X(ulong,                             nonvote_txn_count,           sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Nonvote transaction count */                              \
     191          36 :   X(ulong,                             failed_txn_count,            sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Failed transaction count */                               \
     192          36 :   X(ulong,                             nonvote_failed_txn_count,    sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Nonvote failed transaction count */                       \
     193          36 :   X(ulong,                             total_compute_units_used,    sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Total compute units used */                               \
     194          36 :   X(ulong,                             part_width,                  sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Part width */                                             \
     195          36 :   X(ulong,                             slots_per_epoch,             sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Slots per epoch */                                        \
     196          36 :   X(ulong,                             shred_cnt,                   sizeof(ulong),                             alignof(ulong),                             0,   0    )  /* Shred count */                                            \
     197          36 :   X(int,                               enable_exec_recording,       sizeof(int),                               alignof(int),                               0,   0    )  /* Enable exec recording */
     198             : 
     199             : /* Invariant Every CoW field must have a rw-lock */
     200             : #define X(type, name, footprint, align, cow, has_lock) \
     201             :   FD_STATIC_ASSERT( (cow == 1 && has_lock == 1) || (cow == 0), CoW fields must have a rw-lock );
     202             :   FD_BANKS_ITER(X)
     203             : #undef X
     204             : 
     205             : /* If a member of the bank is CoW then it needs a corresponding pool
     206             :    which is defined here. If a type if not a CoW then it does not need
     207             :    to be in a pool and is laid out contigiously in the bank struct. */
     208             : 
     209             : /* Declare a pool object wrapper for all CoW fields. */
     210             : #define HAS_COW_1(name, footprint, align)                    \
     211             :   static const ulong fd_bank_##name##_align     = align;     \
     212             :   static const ulong fd_bank_##name##_footprint = footprint; \
     213             :                                                              \
     214             :   struct fd_bank_##name {                                    \
     215             :     ulong next;                                              \
     216             :     uchar data[footprint]__attribute__((aligned(align)));    \
     217             :   };                                                         \
     218             :   typedef struct fd_bank_##name fd_bank_##name##_t;
     219             : 
     220             : /* Do nothing if CoW is not enabled. */
     221             : #define HAS_COW_0(name, footprint, align)
     222             : 
     223             : #define X(type, name, footprint, align, cow, has_lock) \
     224             :   HAS_COW_##cow(name, footprint, align)
     225             :   FD_BANKS_ITER(X)
     226             : 
     227             : #undef X
     228             : #undef HAS_COW_0
     229             : #undef HAS_COW_1
     230             : 
     231             : #define POOL_NAME fd_bank_clock_timestamp_votes_pool
     232          63 : #define POOL_T    fd_bank_clock_timestamp_votes_t
     233             : #include "../../util/tmpl/fd_pool.c"
     234             : #undef POOL_NAME
     235             : #undef POOL_T
     236             : 
     237             : #define POOL_NAME fd_bank_stake_account_keys_pool
     238          63 : #define POOL_T    fd_bank_stake_account_keys_t
     239             : #include "../../util/tmpl/fd_pool.c"
     240             : #undef POOL_NAME
     241             : #undef POOL_T
     242             : 
     243             : #define POOL_NAME fd_bank_vote_account_keys_pool
     244          63 : #define POOL_T    fd_bank_vote_account_keys_t
     245             : #include "../../util/tmpl/fd_pool.c"
     246             : #undef POOL_NAME
     247             : #undef POOL_T
     248             : 
     249             : #define POOL_NAME fd_bank_next_epoch_stakes_pool
     250          63 : #define POOL_T    fd_bank_next_epoch_stakes_t
     251             : #include "../../util/tmpl/fd_pool.c"
     252             : #undef POOL_NAME
     253             : #undef POOL_T
     254             : 
     255             : #define POOL_NAME fd_bank_epoch_stakes_pool
     256          63 : #define POOL_T    fd_bank_epoch_stakes_t
     257             : #include "../../util/tmpl/fd_pool.c"
     258             : #undef POOL_NAME
     259             : #undef POOL_T
     260             : 
     261             : #define POOL_NAME fd_bank_epoch_reward_status_pool
     262          63 : #define POOL_T    fd_bank_epoch_reward_status_t
     263             : #include "../../util/tmpl/fd_pool.c"
     264             : #undef POOL_NAME
     265             : #undef POOL_T
     266             : 
     267             : #define POOL_NAME fd_bank_epoch_leaders_pool
     268          63 : #define POOL_T    fd_bank_epoch_leaders_t
     269             : #include "../../util/tmpl/fd_pool.c"
     270             : #undef POOL_NAME
     271             : #undef POOL_T
     272             : 
     273             : #define POOL_NAME fd_bank_stakes_pool
     274          63 : #define POOL_T    fd_bank_stakes_t
     275             : #include "../../util/tmpl/fd_pool.c"
     276             : #undef POOL_NAME
     277             : #undef POOL_T
     278             : 
     279             : /* As mentioned above, the overall layout of the bank struct:
     280             :    - Fields used for internal pool/bank management
     281             :    - Non-Cow fields
     282             :    - CoW fields
     283             :    - Locks for CoW fields
     284             : 
     285             :    The CoW fields are laid out contiguously in the bank struct.
     286             :    The locks for the CoW fields are laid out contiguously after the
     287             :    CoW fields.
     288             : */
     289             : 
     290             : struct fd_bank {
     291          90 :   #define FD_BANK_HEADER_SIZE (40UL)
     292             : 
     293             :   /* Fields used for internal pool and bank management */
     294             :   ulong             slot;        /* slot this node is tracking, also the map key */
     295             :   ulong             next;        /* reserved for internal use by fd_pool_para, fd_map_chain_para and fd_banks_publish */
     296             :   ulong             parent_idx;  /* index of the parent in the node pool */
     297             :   ulong             child_idx;   /* index of the left-child in the node pool */
     298             :   ulong             sibling_idx; /* index of the right-sibling in the node pool */
     299             : 
     300             :   /* First, layout all non-CoW fields contiguously. This is done to
     301             :      allow for cloning the bank state with a simple memcpy. Each
     302             :      non-CoW field is just represented as a byte array. */
     303             : 
     304             :   #define HAS_COW_1(type, name, footprint, align)
     305             : 
     306             :   #define HAS_COW_0(type, name, footprint, align) \
     307             :     uchar name[footprint] __attribute__((aligned(align)));
     308             : 
     309             :   #define X(type, name, footprint, align, cow, has_lock) \
     310             :     HAS_COW_##cow(type, name, footprint, align)
     311             :   FD_BANKS_ITER(X)
     312             :   #undef X
     313             :   #undef HAS_COW_0
     314             :   #undef HAS_COW_1
     315             : 
     316             :   /* Now, layout all information needed for CoW fields. These are only
     317             :      copied when explicitly requested by the caller. The field's data
     318             :      is located at teh pool idx in the pool. If the dirty flag has been
     319             :      set, then the element has been copied over for this bank. */
     320             : 
     321             :   #define HAS_COW_1(type, name, footprint, align) \
     322             :     int                  name##_dirty;            \
     323             :     ulong                name##_pool_idx;         \
     324             :     ulong                name##_pool_offset;
     325             : 
     326             :   #define HAS_COW_0(type, name, footprint, align)
     327             : 
     328             :   #define X(type, name, footprint, align, cow, has_lock) \
     329             :     HAS_COW_##cow(type, name, footprint, align)
     330             :   FD_BANKS_ITER(X)
     331             :   #undef X
     332             :   #undef HAS_COW_0
     333             :   #undef HAS_COW_1
     334             : 
     335             :   /* Now emit locks for all fields that need a rwlock. */
     336             : 
     337             :   #define HAS_LOCK_1(type, name, footprint, align) \
     338             :     fd_rwlock_t name##_lock;
     339             : 
     340             :   #define HAS_LOCK_0(type, name, footprint, align) /* Do nothing for these. */
     341             : 
     342             :   #define X(type, name, footprint, align, cow, has_lock) \
     343             :     HAS_LOCK_##has_lock(type, name, footprint, align)
     344             :   FD_BANKS_ITER(X)
     345             :   #undef X
     346             :   #undef HAS_LOCK_0
     347             :   #undef HAS_LOCK_1
     348             : 
     349             : };
     350             : typedef struct fd_bank fd_bank_t;
     351             : 
     352             : #define HAS_COW_1(type, name, footprint, align)                                  \
     353             : static inline void                                                               \
     354         288 : fd_bank_set_##name##_pool( fd_bank_t * bank, fd_bank_##name##_t * bank_pool ) {  \
     355         288 :   void * bank_pool_mem = fd_bank_##name##_pool_leave( bank_pool );               \
     356         288 :   if( FD_UNLIKELY( !bank_pool_mem ) ) {                                          \
     357           0 :     FD_LOG_CRIT(( "Failed to leave bank pool" ));                                \
     358           0 :   }                                                                              \
     359         288 :   bank->name##_pool_offset = (ulong)bank_pool_mem - (ulong)bank;                 \
     360         288 : }                                                                                \
     361             : static inline fd_bank_##name##_t *                                               \
     362           0 : fd_bank_get_##name##_pool( fd_bank_t * bank ) {                                  \
     363           0 :   return fd_bank_##name##_pool_join( (uchar *)bank + bank->name##_pool_offset ); \
     364           0 : }
     365             : #define HAS_COW_0(type, name, footprint, align) /* Do nothing for these. */
     366             : 
     367             : #define X(type, name, footprint, align, cow, has_lock) \
     368             :   HAS_COW_##cow(type, name, footprint, align)
     369             : FD_BANKS_ITER(X)
     370             : #undef X
     371             : #undef HAS_COW_0
     372             : #undef HAS_COW_1
     373             : 
     374             : 
     375             : /* fd_bank_t is the alignment for the bank state. */
     376             : 
     377             : ulong
     378             : fd_bank_align( void );
     379             : 
     380             : /* fd_bank_t is the footprint for the bank state. This does NOT
     381             :    include the footprint for the CoW state. */
     382             : 
     383             : ulong
     384             : fd_bank_footprint( void );
     385             : 
     386             : /**********************************************************************/
     387             : /* fd_banks_t is the main struct used to manage the bank state. It can
     388             :    be used to query/modify/clone/publish the bank state.
     389             : 
     390             :    fd_banks_t contains some metadata a map/pool pair to manage the banks.
     391             :    It also contains pointers to the CoW pools.
     392             : 
     393             :    The data is laid out contigiously in memory starting from fd_banks_t;
     394             :    this can be seen in fd_banks_footprint(). */
     395             : 
     396             : #define POOL_NAME fd_banks_pool
     397          81 : #define POOL_T    fd_bank_t
     398             : #include "../../util/tmpl/fd_pool.c"
     399             : #undef POOL_NAME
     400             : #undef POOL_T
     401             : 
     402             : #define MAP_NAME  fd_banks_map
     403             : #define MAP_ELE_T fd_bank_t
     404          36 : #define MAP_KEY   slot
     405             : #include "../../util/tmpl/fd_map_chain.c"
     406             : #undef MAP_NAME
     407             : #undef MAP_ELE_T
     408             : #undef MAP_KEY
     409             : 
     410             : struct fd_banks {
     411             :   ulong             magic;     /* ==FD_BANKS_MAGIC */
     412             :   ulong             max_banks; /* Maximum number of banks */
     413             :   ulong             root;      /* root slot */
     414             :   ulong             root_idx;  /* root idx */
     415             : 
     416             :   fd_rwlock_t       rwlock;      /* rwlock for fd_banks_t */
     417             : 
     418             :   ulong             pool_offset; /* offset of pool from banks */
     419             :   ulong             map_offset; /* offset of map from banks */
     420             : 
     421             :   /* Layout all CoW pools. */
     422             : 
     423             :   #define HAS_COW_1(type, name, footprint, align) \
     424             :     ulong           name##_pool_offset; /* offset of pool from banks */
     425             : 
     426             :   #define HAS_COW_0(type, name, footprint, align) /* Do nothing for these. */
     427             : 
     428             :   #define X(type, name, footprint, align, cow, has_lock) \
     429             :     HAS_COW_##cow(type, name, footprint, align)
     430             :   FD_BANKS_ITER(X)
     431             :   #undef X
     432             :   #undef HAS_COW_0
     433             :   #undef HAS_COW_1
     434             : };
     435             : typedef struct fd_banks fd_banks_t;
     436             : 
     437             : /* Bank accesssors */
     438             : 
     439             : #define HAS_LOCK_1(type, name) \
     440             :   type const * fd_bank_##name##_locking_query( fd_bank_t * bank ); \
     441             :   void fd_bank_##name##_end_locking_query( fd_bank_t * bank );     \
     442             :   type * fd_bank_##name##_locking_modify( fd_bank_t * bank );      \
     443             :   void fd_bank_##name##_end_locking_modify( fd_bank_t * bank );
     444             : 
     445             : #define HAS_LOCK_0(type, name)                             \
     446             :   type const * fd_bank_##name##_query( fd_bank_t * bank ); \
     447             :   type * fd_bank_##name##_modify( fd_bank_t * bank );
     448             : 
     449             : #define X(type, name, footprint, align, cow, has_lock) \
     450             :   void fd_bank_##name##_set( fd_bank_t * bank, type value );       \
     451             :   type fd_bank_##name##_get( fd_bank_t * bank );                   \
     452             :   HAS_LOCK_##has_lock(type, name)
     453             : FD_BANKS_ITER(X)
     454             : #undef X
     455             : 
     456             : #undef HAS_LOCK_0
     457             : #undef HAS_LOCK_1
     458             : 
     459             : /* Simple getters and setters for members of fd_banks_t.*/
     460             : 
     461             : static inline fd_bank_t *
     462          63 : fd_banks_get_bank_pool( fd_banks_t const * banks ) {
     463          63 :   return fd_banks_pool_join( ((uchar *)banks + banks->pool_offset) );
     464          63 : }
     465             : 
     466             : static inline fd_banks_map_t *
     467          60 : fd_banks_get_bank_map( fd_banks_t const * banks ) {
     468          60 :   return fd_banks_map_join( ((uchar *)banks + banks->map_offset) );
     469          60 : }
     470             : 
     471             : static inline void
     472           6 : fd_banks_set_bank_pool( fd_banks_t * banks, fd_bank_t * bank_pool ) {
     473           6 :   void * bank_pool_mem = fd_banks_pool_leave( bank_pool );
     474           6 :   if( FD_UNLIKELY( !bank_pool_mem ) ) {
     475           0 :     FD_LOG_CRIT(( "Failed to leave bank pool" ));
     476           0 :   }
     477           6 :   banks->pool_offset = (ulong)bank_pool_mem - (ulong)banks;
     478           6 : }
     479             : 
     480             : static inline void
     481           6 : fd_banks_set_bank_map( fd_banks_t * banks, fd_banks_map_t * bank_map ) {
     482           6 :   void * bank_map_mem = fd_banks_map_leave( bank_map );
     483           6 :   if( FD_UNLIKELY( !bank_map_mem ) ) {
     484           0 :     FD_LOG_CRIT(( "Failed to leave bank map" ));
     485           0 :   }
     486           6 :   banks->map_offset = (ulong)bank_map_mem - (ulong)banks;
     487           6 : }
     488             : 
     489             : #define HAS_COW_1(type, name, footprint, align)                                    \
     490             : static inline fd_bank_##name##_t *                                                 \
     491         360 : fd_banks_get_##name##_pool( fd_banks_t * banks ) {                                 \
     492         360 :   return fd_bank_##name##_pool_join( (uchar *)banks + banks->name##_pool_offset ); \
     493         360 : }                                                                                  \
     494             : static inline void                                                                 \
     495          48 : fd_banks_set_##name##_pool( fd_banks_t * banks, fd_bank_##name##_t * bank_pool ) { \
     496          48 :   void * bank_pool_mem = fd_bank_##name##_pool_leave( bank_pool );                 \
     497          48 :   if( FD_UNLIKELY( !bank_pool_mem ) ) {                                            \
     498           0 :     FD_LOG_CRIT(( "Failed to leave bank pool" ));                                  \
     499           0 :   }                                                                                \
     500          48 :   banks->name##_pool_offset = (ulong)bank_pool_mem - (ulong)banks;                 \
     501          48 : }
     502             : 
     503             : #define HAS_COW_0(type, name, footprint, align) /* Do nothing for these. */
     504             : 
     505             : #define X(type, name, footprint, align, cow, has_lock) \
     506             :   HAS_COW_##cow(type, name, footprint, align)
     507             : FD_BANKS_ITER(X)
     508             : #undef X
     509             : #undef HAS_COW_0
     510             : #undef HAS_COW_1
     511             : 
     512             : /* fd_banks_root reutrns the current root slot for the bank. */
     513             : 
     514             : FD_FN_PURE static inline fd_bank_t const *
     515           3 : fd_banks_root( fd_banks_t const * banks ) {
     516           3 :   return fd_banks_pool_ele_const( fd_banks_get_bank_pool( banks ), banks->root_idx );
     517           3 : }
     518             : 
     519             : /* fd_banks_align() returns the alignment of fd_banks_t */
     520             : 
     521             : ulong
     522             : fd_banks_align( void );
     523             : 
     524             : /* fd_banks_footprint() returns the footprint of fd_banks_t */
     525             : 
     526             : ulong
     527             : fd_banks_footprint( ulong max_banks );
     528             : 
     529             : /* fd_banks_new() creates a new fd_banks_t struct. */
     530             : 
     531             : void *
     532             : fd_banks_new( void * mem, ulong max_banks );
     533             : 
     534             : /* fd_banks_join() joins a new fd_banks_t struct. */
     535             : 
     536             : fd_banks_t *
     537             : fd_banks_join( void * mem );
     538             : 
     539             : /* fd_banks_leave() leaves a bank. */
     540             : 
     541             : void *
     542             : fd_banks_leave( fd_banks_t * banks );
     543             : 
     544             : /* fd_banks_delete() deletes a bank. */
     545             : 
     546             : void *
     547             : fd_banks_delete( void * shmem );
     548             : 
     549             : /* fd_banks_init_bank() initializes a new bank in the bank manager.
     550             :    This should only be used during bootup. This returns an initial
     551             :    fd_bank_t with the corresponding slot. */
     552             : 
     553             : fd_bank_t *
     554             : fd_banks_init_bank( fd_banks_t * banks, ulong slot );
     555             : 
     556             : /* fd_bank_get_bank() returns a bank for a given slot. If said bank
     557             :    does not exist, NULL is returned. */
     558             : 
     559             : fd_bank_t *
     560             : fd_banks_get_bank( fd_banks_t * banks, ulong slot );
     561             : 
     562             : /* fd_banks_clone_from_parent() clones a bank from a parent bank.
     563             :    If the bank corresponding to the parent slot does not exist,
     564             :    NULL is returned. If a bank is not able to be created, NULL is
     565             :    returned. The data from the parent bank will copied over into
     566             :    the new bank.
     567             : 
     568             :    A more detailed note: not all of the data is copied over and this
     569             :    is a shallow clone. All of the CoW fields are not copied over and
     570             :    will only be done so if the caller explicitly calls
     571             :    fd_bank_{*}_modify(). This naming was chosen to emulate the
     572             :    semantics of the Agave client. */
     573             : 
     574             : fd_bank_t *
     575             : fd_banks_clone_from_parent( fd_banks_t * banks,
     576             :                             ulong        slot,
     577             :                             ulong        parent_slot );
     578             : 
     579             : /* fd_banks_publish() publishes a bank to the bank manager. This
     580             :    should only be used when a bank is no longer needed. This will
     581             :    prune off the bank from the bank manager. It returns the new root
     582             :    bank.
     583             : 
     584             :    All banks that are ancestors or siblings of the slot will be
     585             :    cancelled and their resources will be released back to the pool. */
     586             : 
     587             : fd_bank_t const *
     588             : fd_banks_publish( fd_banks_t * banks, ulong slot );
     589             : 
     590             : void
     591             : fd_bank_clear_bank( fd_bank_t * bank );
     592             : 
     593             : FD_PROTOTYPES_END
     594             : 
     595             : #endif /* HEADER_fd_src_flamenco_runtime_fd_bank_h */

Generated by: LCOV version 1.14