LCOV - code coverage report
Current view: top level - disco/store - fd_store.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 131 134 97.8 %
Date: 2026-11-12 04:25:03 Functions: 15 660 2.3 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_store_fd_store_h
       2             : #define HEADER_fd_src_disco_store_fd_store_h
       3             : 
       4             : #include "../../disco/shred/fd_fec_set.h"
       5             : #include "../../ballet/shred/fd_shred.h"
       6             : #include "../../flamenco/fd_rwlock.h"
       7             : #include "../../flamenco/fd_flamenco_base.h"
       8             : #include "../../util/fd_hash32.h"
       9             : #include "../../util/hist/fd_histf.h"
      10             : #include "../../util/shmem/fd_shmem.h"
      11             : #include "../../util/tile/fd_tile.h"
      12             : 
      13             : #define FD_STORE_ALIGN (128UL)
      14             : 
      15             : /* The launcher creates the Store backing file before starting any tile
      16             :    and passes these descriptors through exec.  Keep them adjacent to the
      17             :    accdb descriptor range, but distinct from it. */
      18           0 : #define FD_STORE_FD_RW (123459)
      19           0 : #define FD_STORE_FD_RO (123458)
      20             : 
      21             : /* Spill and cache slots are page aligned. */
      22        2118 : #define FD_STORE_PAYLOAD_PAGE_SZ (FD_SHMEM_NORMAL_PAGE_SZ)
      23             : 
      24             : FD_FN_CONST static inline ulong
      25         498 : fd_store_payload_slot_sz( ulong fec_data_max ) {
      26         498 :   ulong rounded;
      27         498 :   if( FD_UNLIKELY( __builtin_uaddl_overflow( fec_data_max, FD_STORE_PAYLOAD_PAGE_SZ-1UL, &rounded ) ) ) return 0UL;
      28         492 :   return rounded & ~(FD_STORE_PAYLOAD_PAGE_SZ-1UL);
      29         498 : }
      30         138 : #define FD_STORE_MAGIC (0xf17eda2ce75702eeUL) /* firedancer store version 14 */
      31             : 
      32        3566 : #define FD_STORE_FEC_DATA_EMPTY       (0U)
      33           0 : #define FD_STORE_FEC_DATA_RAM_WRITING (1U)
      34        1592 : #define FD_STORE_FEC_DATA_RAM_READY   (2U)
      35        1296 : #define FD_STORE_FEC_DATA_DISK        (3U)
      36        1440 : #define FD_STORE_FEC_DATA_CONSUMED    (4U)
      37         660 : #define FD_STORE_FEC_DATA_SPILLING    (5U)
      38             : 
      39             : /* Shred ring keys are slot<<32 | shred_idx, so slot<2^32 and shred_idx
      40             :    <2^32.  The per-slot hint reuses the key with bit 31 as the valid
      41             :    flag, which further bounds shred_idx<2^31 (see FD_SHREDB_HINT_VALID). */
      42             : 
      43             : #define FD_SHREDB_KEY_SLOT_MAX  (1UL<<32)
      44        2109 : #define FD_SHREDB_HINT_VALID    (1UL<<31)
      45             : 
      46             : FD_FN_CONST static inline ulong
      47        2845 : fd_shredb_key_pack( ulong slot, uint shred_idx ) {
      48        2845 :   return (slot << 32) | (ulong)shred_idx;
      49        2845 : }
      50             : 
      51             : FD_FN_CONST static inline ulong
      52        2169 : fd_shredb_key_slot( ulong key ) {
      53        2169 :   return fd_ulong_extract( key, 32, 63 );
      54        2169 : }
      55             : 
      56             : FD_FN_CONST static inline uint
      57        2325 : fd_shredb_key_shred_idx( ulong key ) {
      58        2325 :   return (uint)fd_ulong_extract( key, 0, 31 );
      59        2325 : }
      60             : 
      61             : typedef __attribute__((aligned(4))) ulong fd_shredb_map_key_t;
      62             : 
      63             : FD_STATIC_ASSERT( sizeof(fd_shredb_map_key_t)==8UL, shredb_map_key_footprint );
      64             : FD_STATIC_ASSERT( alignof(fd_shredb_map_key_t)==4UL, shredb_map_key_align );
      65             : 
      66             : struct fd_shredb_root_key {
      67             :   uchar root[ FD_SHRED_MERKLE_NODE_SZ ];
      68             :   uchar off; /* 0 <= off < 32 */
      69             : };
      70             : typedef struct fd_shredb_root_key fd_shredb_root_key_t;
      71             : 
      72             : FD_STATIC_ASSERT( sizeof(fd_shredb_root_key_t)==21UL, shredb_root_key_footprint );
      73             : 
      74             : static inline fd_shredb_root_key_t
      75             : fd_shredb_root_key( uchar const * merkle_root,
      76        1338 :                     uint          shred_idx ) {
      77        1338 :   fd_shredb_root_key_t key;
      78        1338 :   memcpy( key.root, merkle_root, FD_SHRED_MERKLE_NODE_SZ );
      79        1338 :   key.off = (uchar)(shred_idx % FD_FEC_SHRED_CNT);
      80        1338 :   return key;
      81        1338 : }
      82             : 
      83             : /* One ring entry provides keys and chain links to both maps.  Its
      84             :    seven-byte tag and 21-byte root key leave no padding in 44 bytes.
      85             :    tag_hi extends the low 30 ticket bits in tag by 24 bits; the bottom
      86             :    two tag bits hold the cell state.  All fields use disk_lock. */
      87             : struct fd_shredb_ring_entry {
      88             :   uint                 tag;
      89             :   uchar                tag_hi[ 3 ];
      90             :   fd_shredb_root_key_t root_key;
      91             :   fd_shredb_map_key_t  key;
      92             :   uint                 slot_next;
      93             :   uint                 root_next;
      94             : };
      95             : typedef struct fd_shredb_ring_entry fd_shredb_ring_entry_t;
      96             : FD_STATIC_ASSERT( sizeof(fd_shredb_ring_entry_t)==44UL, shredb_ring_entry_footprint );
      97             : 
      98        5931 : #define FD_SHREDB_TAG_SEQ_MASK ((1UL<<54)-1UL)
      99             : 
     100        1227 : #define FD_SHREDB_CELL_INVALID    (0UL)
     101        1233 : #define FD_SHREDB_CELL_WRITING    (1UL)
     102        4011 : #define FD_SHREDB_CELL_READY      (2UL)
     103        5289 : #define FD_SHREDB_CELL_STATE_MASK (3UL)
     104             : 
     105             : /* The slot and root maps are non-concurrent separately-chained hash maps
     106             :    (fd_map_chain) over the shared ring pool.  Each has its own bucket-head
     107             :    array and threads collisions through its corresponding next field.
     108             :    All access is serialized by the store's disk_lock. */
     109             : 
     110             : #define MAP_NAME   fd_shredb_slot_map
     111             : #define MAP_ELE_T  fd_shredb_ring_entry_t
     112             : #define MAP_KEY_T  fd_shredb_map_key_t
     113        1209 : #define MAP_KEY    key
     114        2301 : #define MAP_NEXT   slot_next
     115        6327 : #define MAP_IDX_T  uint
     116             : #include "../../util/tmpl/fd_map_chain.c"
     117             : 
     118             : #define MAP_NAME               fd_shredb_root_map
     119             : #define MAP_ELE_T              fd_shredb_ring_entry_t
     120             : #define MAP_KEY_T              fd_shredb_root_key_t
     121        1227 : #define MAP_KEY                root_key
     122        2124 : #define MAP_KEY_EQ(k0,k1)      (!memcmp( (k0), (k1), sizeof(fd_shredb_root_key_t) ))
     123        4773 : #define MAP_KEY_HASH(key,seed) fd_hash( (seed), (key), sizeof(fd_shredb_root_key_t) )
     124        2313 : #define MAP_NEXT               root_next
     125        6078 : #define MAP_IDX_T              uint
     126             : #include "../../util/tmpl/fd_map_chain.c"
     127             : 
     128             : struct __attribute__((aligned(64))) fd_shredb_entry {
     129             :   ulong  tag;
     130             :   ulong  key;
     131             :   uchar  root[ FD_SHRED_MERKLE_NODE_SZ ]; /* merkle root prefix of the shred's FEC set */
     132             :   ushort shred_sz;
     133             :   uchar  shred[ FD_SHRED_MAX_SZ ];
     134             : };
     135             : typedef struct fd_shredb_entry fd_shredb_entry_t;
     136             : 
     137             : FD_STATIC_ASSERT( sizeof(fd_shredb_entry_t)==1280UL, shred_disk_entry_footprint );
     138             : 
     139             : #define FD_SHREDB_MAX_SIZE_GIB (((ulong)UINT_MAX*sizeof(fd_shredb_entry_t))/(1UL<<30))
     140             : 
     141             : FD_FN_CONST static inline ulong
     142         468 : fd_shredb_max_shreds( ulong gib ) {
     143         468 :   if( FD_UNLIKELY( !gib || gib>(ULONG_MAX>>30) ) ) return 0UL;
     144         468 :   return (gib<<30) / sizeof(fd_shredb_entry_t);
     145         468 : }
     146             : 
     147             : FD_FN_CONST static inline ulong
     148         228 : fd_shredb_max_slots( ulong gib ) {
     149         228 :   return fd_ulong_max( !!gib, fd_shredb_max_shreds( gib )/FD_FEC_SHRED_CNT );
     150         228 : }
     151             : 
     152             : /* The chain count estimator halves its input, so dividing by four
     153             :    targets max_shreds/8 buckets.  This reduces bucket memory at the
     154             :    expense of longer chains. */
     155             : FD_FN_CONST static inline ulong
     156         228 : fd_shredb_disk_chain_cnt( ulong max_shreds ) {
     157         228 :   return fd_shredb_slot_map_chain_cnt_est( max_shreds/4UL );
     158         228 : }
     159             : 
     160             : struct __attribute__((aligned(FD_STORE_ALIGN))) fd_store_fec {
     161             :   fd_hash_t key;
     162             :   uint      data_idx;                       /* RAM cache slot when RAM_*, spill-file slot when DISK */
     163             :   uint      next;                           /* managed by fd_pool / fd_map_chain_para */
     164             :   uint      data_sz;                        /* sz of the FEC set payload, <= fec_data_max */
     165             :   uint      cache_prev;                     /* RAM_READY LRU links, UINT_MAX when unlinked */
     166             :   uint      cache_next;
     167             :   uint      slot;                           /* slot_to_fecs key, raised to the last published root */
     168             :   uint      slot_next;                      /* managed by slot_to_fecs */
     169             :   ushort    data_pin_cnt;                   /* active payload views */
     170             :   uchar     data_state;                     /* FD_STORE_FEC_DATA_* */
     171             :   uchar     data_consume_pending;
     172             :   ushort    shred_sz[ FD_FEC_SHRED_CNT ];   /* payload size of each data shred */
     173             : };
     174             : typedef struct fd_store_fec fd_store_fec_t;
     175             : 
     176             : FD_STATIC_ASSERT( sizeof(fd_store_fec_t)==FD_STORE_ALIGN, fd_store_fec_footprint );
     177             : 
     178             : #define POOL_NAME  fd_store_pool
     179        3258 : #define POOL_ELE_T fd_store_fec_t
     180             : #define POOL_IDX_T uint
     181             : #include "../../util/tmpl/fd_pool_para.c"
     182             : 
     183             : #define MAP_NAME               fd_store_map
     184        3114 : #define MAP_ELE_T              fd_store_fec_t
     185             : #define MAP_KEY_T              fd_hash_t
     186        1515 : #define MAP_KEY                key
     187        2857 : #define MAP_KEY_EQ(k0,k1)      (!memcmp((k0),(k1), sizeof(fd_hash_t)))
     188        5956 : #define MAP_KEY_HASH(key,seed) fd_hash32( (key)->uc, (seed) )
     189        3033 : #define MAP_IDX_T              uint
     190             : #include "../../util/tmpl/fd_map_chain_para.c"
     191             : 
     192             : /* slot_to_fecs has one partition per shred tile.  Each inserter
     193             :    appends only to its own partition, so concurrent inserts under the
     194             :    shared fec_lock never touch the same chain.  Only fd_store_publish
     195             :    removes, under the exclusive fec_lock. */
     196             : 
     197             : #define MAP_NAME     fd_store_slot_to_fecs
     198             : #define MAP_ELE_T    fd_store_fec_t
     199             : #define MAP_KEY_T    uint
     200        1519 : #define MAP_KEY      slot
     201        3019 : #define MAP_NEXT     slot_next
     202        3190 : #define MAP_IDX_T    uint
     203             : #define MAP_MULTI    1
     204             : #include "../../util/tmpl/fd_map_chain.c"
     205             : 
     206             : struct fd_store {
     207             :   ulong magic;
     208             :   ulong fec_max;
     209             :   ulong fec_data_max;
     210             :   ulong store_gaddr;
     211             :   ulong map_gaddr;
     212             :   ulong pool_mem_gaddr;
     213             :   ulong pool_ele_gaddr;
     214             :   ulong shred_tile_cnt;
     215             :   ulong slot_to_fecs_gaddr;                 /* shred_tile_cnt maps, slot_to_fecs_sz apart */
     216             :   ulong slot_to_fecs_sz;
     217             :   ulong root;                               /* last published root */
     218             :   atomic_ulong slot_lo;                     /* no FEC is linked below it, ULONG_MAX before the first insert */
     219             : 
     220             :   ulong payload_slot_sz;
     221             :   ulong payload_sz;                          /* logical spill region size: payload_slot_sz*fec_max */
     222             :   ulong wire_off;                            /* byte offset where the rserve wire region begins */
     223             : 
     224             :   /* RAM FEC payload cache.  cache_slot_cnt is usually much smaller than
     225             :      fec_max.  cache_free is a stack of slot indices protected by
     226             :      cache_lock. */
     227             :   ulong        cache_slot_cnt;
     228             :   ulong        cache_data_gaddr;
     229             :   ulong        cache_free_gaddr;
     230             :   ulong        cache_free_cnt;
     231             :   ulong        cache_free_target;
     232             :   ulong        cache_free_low_water;
     233             :   uint         cache_preevict_active;
     234             :   uint         cache_lru_head;
     235             :   uint         cache_lru_tail;
     236             :   ulong        cache_pinned_cnt;
     237             :   ulong        spill_free_gaddr;
     238             :   ulong        spill_free_cnt;
     239             :   ulong        spill_slot_cnt;
     240             :   atomic_ulong spill_live_cnt;
     241             :   atomic_ulong fec_spill_cnt;
     242             :   atomic_ulong fec_spill_bytes;
     243             :   atomic_ulong fec_spill_read_cnt;
     244             :   atomic_ulong fec_spill_read_bytes;
     245             :   fd_rwlock_t cache_lock;
     246             : 
     247             :   /* Spilled payloads are read into this buffer under spill_read_lock. */
     248             :   ulong        spill_read_data_gaddr;
     249             :   fd_rwlock_t  spill_read_lock;
     250             : 
     251             :   /* Reassembly removal returns metadata synchronously, matching the
     252             :      original Store capacity contract. */
     253             :   fd_rwlock_t  fec_lock;
     254             : 
     255             :   /* Arena used by shred tiles for assembly and recovery. */
     256             :   ulong        fec_set_cnt;
     257             :   ulong        fec_sets_gaddr;
     258             : 
     259             :   /* On-disk shred index. Lives in the wire region of the shared file
     260             :      at byte offset wire_off + ring_idx*sizeof(entry).  shred_map keys
     261             :      cells by (slot,idx), first version wins.  root_map keys every cell
     262             :      by (root,idx%32).  Both maps share the ring pool and disk_lock. */
     263             :   ulong        shred_map_gaddr; /* fd_shredb_slot_map over the ring pool */
     264             :   ulong        ring_pool_gaddr;
     265             :   ulong        root_map_gaddr;  /* fd_shredb_root_map over the ring pool */
     266             :   fd_rwlock_t  disk_lock;
     267             :   ulong        slot_hint_gaddr;
     268             :   ulong        disk_max_shreds;
     269             :   ulong        disk_max_slots;
     270             :   ulong        max_shreds_per_block; /* bounds shred idxs, <=FD_SHREDB_HINT_VALID */
     271             :   atomic_ulong disk_reservation_head;
     272             :   atomic_ulong disk_cnt;
     273             :   atomic_ulong disk_insert_cnt;
     274             :   atomic_ulong disk_write_bytes;
     275             : };
     276             : typedef struct fd_store fd_store_t;
     277             : 
     278             : FD_PROTOTYPES_BEGIN
     279             : 
     280             : /* Store contains a Merkle-root keyed FEC map, a payload cache, and an
     281             :    on-disk shred ring.
     282             : 
     283             :    Shred reserves a payload, fills it, inserts the FEC, and then notifies
     284             :    Replay.  The corresponding reassembly node owns the FEC until
     285             :    removal.
     286             :    Removal waits for payload users, then returns the payload and metadata
     287             :    synchronously.  fec_max therefore covers reassembly and complete-FEC
     288             :    messages in flight.
     289             : 
     290             :    Payloads enter the RAM cache and spill by LRU to page-sized file slots.
     291             :    Freed slots are immediately eligible for reuse and keep their disk
     292             :    blocks; a new slot is only used when none is free.  The file layout
     293             :    is:
     294             : 
     295             :     [ sparse spill slots (payload_slot_sz*fec_max) ][ shred ring ]
     296             : 
     297             :     wire_off is the fixed start of the shred ring.  Spill slots that
     298             :     were never used do not consume disk blocks.
     299             : 
     300             :     Shred-ring writers reserve cells and mark only the target cell WRITING
     301             :     while its pwrite is in progress. */
     302             : 
     303             : FD_FN_CONST static inline ulong
     304        1626 : fd_store_align( void ) {
     305        1626 :   return FD_STORE_PAYLOAD_PAGE_SZ;
     306        1626 : }
     307             : 
     308             : static inline int
     309             : fd_store_layout_append( ulong * l,
     310             :                         ulong   align,
     311             :                         ulong   cnt,
     312        3876 :                         ulong   ele_sz ) {
     313        3876 :   ulong bytes;
     314        3876 :   ulong rounded;
     315        3876 :   ulong next;
     316        3876 :   if( FD_UNLIKELY( !align || !fd_ulong_is_pow2( align ) ) ) return -1;
     317        3876 :   if( FD_UNLIKELY( __builtin_umull_overflow( cnt, ele_sz, &bytes ) ) ) return -1;
     318        3870 :   if( FD_UNLIKELY( __builtin_uaddl_overflow( *l, align-1UL, &rounded ) ) ) return -1;
     319        3870 :   rounded &= ~(align-1UL);
     320        3870 :   if( FD_UNLIKELY( __builtin_uaddl_overflow( rounded, bytes, &next ) ) ) return -1;
     321        3870 :   *l = next;
     322        3870 :   return 0;
     323        3870 : }
     324             : 
     325             : FD_FN_CONST static inline ulong
     326             : fd_store_footprint( ulong fec_max,
     327             :                     ulong fec_data_max,
     328             :                     ulong shred_storage_gib,
     329             :                     ulong shred_cache_bytes,
     330             :                     ulong fec_set_cnt,
     331         342 :                     ulong shred_tile_cnt ) {
     332         342 :   if( FD_UNLIKELY( !fec_max || !fec_data_max || fec_max>UINT_MAX || fec_data_max>UINT_MAX ||
     333         342 :                    shred_storage_gib>FD_SHREDB_MAX_SIZE_GIB ) ) return 0UL;
     334         324 :   ulong chain_cnt = fd_store_map_chain_cnt_est( fec_max );
     335         324 :   ulong slot_to_fecs_sz = fd_ulong_align_up( fd_store_slot_to_fecs_footprint( fd_store_slot_to_fecs_chain_cnt_est( fec_max ) ), fd_store_slot_to_fecs_align() );
     336         324 :   ulong payload_slot_sz = fd_store_payload_slot_sz( fec_data_max );
     337         324 :   if( FD_UNLIKELY( !payload_slot_sz ) ) return 0UL;
     338         324 :   ulong cache_slot_cnt = shred_cache_bytes
     339         324 :                        ? fd_ulong_min( fec_max, fd_ulong_max( 1UL, shred_cache_bytes / payload_slot_sz ) )
     340         324 :                        : fec_max;
     341         324 :   ulong l = FD_LAYOUT_INIT;
     342         324 :   if( FD_UNLIKELY( fd_store_layout_append( &l, fd_store_align(),         1UL,            sizeof(fd_store_t) ) ||
     343         324 :                    fd_store_layout_append( &l, fd_store_map_align(),     1UL,            fd_store_map_footprint( chain_cnt ) ) ||
     344         324 :                    fd_store_layout_append( &l, fd_store_pool_align(),    1UL,            fd_store_pool_footprint() ) ||
     345         324 :                    fd_store_layout_append( &l, alignof(fd_store_fec_t),  fec_max,         sizeof(fd_store_fec_t) ) ||
     346         324 :                    fd_store_layout_append( &l, fd_store_slot_to_fecs_align(), shred_tile_cnt, slot_to_fecs_sz ) ||
     347         324 :                    fd_store_layout_append( &l, FD_STORE_PAYLOAD_PAGE_SZ, cache_slot_cnt, payload_slot_sz ) ||
     348         324 :                    fd_store_layout_append( &l, alignof(ulong),           cache_slot_cnt, sizeof(ulong) ) ||
     349         324 :                    fd_store_layout_append( &l, alignof(uint),            fec_max,         sizeof(uint) ) ||
     350         324 :                    fd_store_layout_append( &l, FD_STORE_PAYLOAD_PAGE_SZ, 1UL,             payload_slot_sz ) ) ) return 0UL;
     351         324 :   if( FD_UNLIKELY( fec_set_cnt && fd_store_layout_append( &l, alignof(fd_fec_set_t), fec_set_cnt, sizeof(fd_fec_set_t) ) ) ) return 0UL;
     352         318 :   if( shred_storage_gib ) {
     353         156 :     ulong max_shreds     = fd_shredb_max_shreds( shred_storage_gib );
     354         156 :     ulong max_slots      = fd_shredb_max_slots( shred_storage_gib );
     355         156 :     ulong disk_chain_cnt = fd_shredb_disk_chain_cnt( max_shreds );
     356         156 :     if( FD_UNLIKELY( !max_shreds || !max_slots ||
     357         156 :                      fd_store_layout_append( &l, fd_shredb_slot_map_align(),      1UL,        fd_shredb_slot_map_footprint( disk_chain_cnt ) ) ||
     358         156 :                      fd_store_layout_append( &l, alignof(fd_shredb_ring_entry_t), max_shreds, sizeof(fd_shredb_ring_entry_t) ) ||
     359         156 :                      fd_store_layout_append( &l, alignof(atomic_ulong),           max_slots,  sizeof(atomic_ulong) ) ||
     360         156 :                      fd_store_layout_append( &l, fd_shredb_root_map_align(),      1UL,        fd_shredb_root_map_footprint( disk_chain_cnt ) ) ) ) return 0UL;
     361         156 :   }
     362         318 :   if( FD_UNLIKELY( fd_store_layout_append( &l, fd_store_align(), 0UL, 1UL ) ) ) return 0UL;
     363         318 :   return l;
     364         318 : }
     365             : 
     366             : /* Formats a footprint-sized, fd_store_align()-aligned region.  fec_max
     367             :    bounds live FECs; fec_data_max bounds each payload.  The remaining size
     368             :    arguments configure the shred ring, RAM cache, and shred-tile arena.
     369             :    max_shreds_per_block bounds shred idxs in the shred ring, in
     370             :    [1,FD_SHREDB_HINT_VALID].  shred_tile_cnt is the number of
     371             :    slot_to_fecs partitions, must be non-zero and match the footprint.
     372             :    Does not create the backing file. */
     373             : 
     374             : void *
     375             : fd_store_new( void       * shmem,
     376             :               ulong        fec_max,
     377             :               ulong        fec_data_max,
     378             :               ulong        shred_storage_gib,
     379             :               ulong        shred_cache_bytes,
     380             :               ulong        fec_set_cnt,
     381             :               ulong        max_shreds_per_block,
     382             :               ulong        seed,
     383             :               ulong        shred_tile_cnt );
     384             : 
     385             : fd_store_t * fd_store_join ( void * shstore );
     386             : void *       fd_store_leave( fd_store_t const * store );
     387             : void *       fd_store_delete( void * shstore );
     388             : 
     389             : /* Creates and sizes the Store backing file */
     390             : 
     391             : int
     392             : fd_store_file_create( char const * path,
     393             :                       ulong        wire_off,
     394             :                       ulong        disk_max_shreds );
     395             : 
     396             : 
     397             : FD_FN_PURE static inline fd_wksp_t *
     398       35690 : fd_store_wksp( fd_store_t const * store ) {
     399       35690 :   return (fd_wksp_t *)( ( (ulong)store ) - store->store_gaddr );
     400       35690 : }
     401             : 
     402             : /* Optional FEC-set arena, partitioned among shred tile kind_ids. */
     403             : 
     404             : FD_FN_PURE static inline fd_fec_set_t *
     405           6 : fd_store_fec_sets( fd_store_t const * store ) {
     406           6 :   return store->fec_set_cnt ? fd_wksp_laddr_fast( fd_store_wksp( store ), store->fec_sets_gaddr ) : NULL;
     407           6 : }
     408             : 
     409             : /* Joins the FEC map using caller-owned local scratch. */
     410             : 
     411             : static inline fd_store_map_t *
     412             : fd_store_map_ljoin( fd_store_t const * store,
     413          84 :                     fd_store_map_t *   map ) {
     414          84 :   fd_wksp_t * wksp = fd_store_wksp( store );
     415          84 :   return fd_store_map_join( map,
     416          84 :                             fd_wksp_laddr_fast( wksp, store->map_gaddr ),
     417          84 :                             fd_wksp_laddr_fast( wksp, store->pool_ele_gaddr ),
     418          84 :                             store->fec_max );
     419          84 : }
     420             : 
     421             : 
     422             : struct fd_store_fec_data_view {
     423             :   uchar          * data;
     424             :   fd_store_fec_t * fec;
     425             :   uint             flags;
     426             : };
     427             : typedef struct fd_store_fec_data_view fd_store_fec_data_view_t;
     428             : 
     429             : struct fd_store_fec_spill_stats {
     430             :   ulong write_cnt;
     431             :   ulong write_bytes;
     432             :   ulong write_ticks;
     433             : };
     434             : typedef struct fd_store_fec_spill_stats fd_store_fec_spill_stats_t;
     435             : 
     436             : struct fd_store_fec_cache_stats {
     437             :   ulong free_cnt;
     438             :   ulong max;
     439             :   ulong target;
     440             :   ulong low_water;
     441             : };
     442             : typedef struct fd_store_fec_cache_stats fd_store_fec_cache_stats_t;
     443             : 
     444             : /* Reserves a RAM payload not yet bound to any FEC and returns it, with
     445             :    its cache slot in *data_idx, or NULL if nothing can be spilled to
     446             :    make room.  Fill it, then hand data_idx to fd_store_insert, which
     447             :    takes ownership of the slot.  spill is optional and reports
     448             :    synchronous fallback spills. */
     449             : 
     450             : uchar *
     451             : fd_store_fec_data_reserve( fd_store_t                  * store,
     452             :                            int                           disk_fd,
     453             :                            uint                        * data_idx,
     454             :                            fd_store_fec_spill_stats_t * spill );
     455             : 
     456             : /* Spills at most one LRU payload while refilling the free reserve. */
     457             : 
     458             : int
     459             : fd_store_fec_data_preevict( fd_store_t                  * store,
     460             :                             int                           disk_fd,
     461             :                             fd_store_fec_spill_stats_t * spill );
     462             : 
     463             : void
     464             : fd_store_fec_cache_stats_query( fd_store_t                 * store,
     465             :                                 fd_store_fec_cache_stats_t * stats );
     466             : 
     467             : /* Pins a published payload.  Returns 0 on success and -1 with an empty
     468             :    view on failure.  The store has one spill-read buffer, so a second
     469             :    spilled view returns -1 while the first is active.  RAM views can
     470             :    coexist.  Release every successful view; publish waits for pins. */
     471             : 
     472             : int
     473             : fd_store_fec_data_view( fd_store_t *               store,
     474             :                         int                        disk_fd,
     475             :                         fd_store_fec_t *           fec,
     476             :                         fd_store_fec_data_view_t * view );
     477             : 
     478             : void
     479             : fd_store_fec_data_view_release( fd_store_t *               store,
     480             :                                 fd_store_fec_data_view_t * view );
     481             : 
     482             : /* Atomically inserts merkle_root, a FEC set of slot, into the caller's
     483             :    slot_to_fecs partition part (the shred tile's).  The new FEC takes
     484             :    the payload reserved by fd_store_fec_data_reserve at data_idx,
     485             :    data_sz bytes split by shred_sz, and is RAM_READY when linked.  Returns
     486             :    FD_MAP_SUCCESS with the new FEC, or FD_MAP_ERR_KEY with *fec==NULL if
     487             :    present, in which case the cache slot is freed. Pool exhaustion is a
     488             :    topology invariant violation. */
     489             : 
     490             : int
     491             : fd_store_insert( fd_store_t *       store,
     492             :                  fd_store_map_t *   map,
     493             :                  fd_hash_t const *  merkle_root,
     494             :                  ulong              slot,
     495             :                  ulong              part,
     496             :                  uint               data_idx,
     497             :                  uint               data_sz,
     498             :                  ushort const       shred_sz[ FD_FEC_SHRED_CNT ],
     499             :                  fd_store_fec_t **  fec );
     500             : 
     501             : /* Lockless lookup; returns NULL if absent.  The returned pointer is
     502             :    borrowed.  Retain the corresponding reassembly node or otherwise
     503             :    exclude publish while using it. */
     504             : 
     505             : fd_store_fec_t *
     506             : fd_store_query( fd_store_map_t *  map,
     507             :                 fd_hash_t const * merkle_root );
     508             : 
     509             : /* Removes every FEC of a slot below root after its active views and
     510             :    spill I/O finish, returning its payload and metadata.  Walks the
     511             :    slots from the lowest inserted one to root.  Returns how many it
     512             :    removed. */
     513             : 
     514             : ulong
     515             : fd_store_publish( fd_store_t *     store,
     516             :                   fd_store_map_t * map,
     517             :                   ulong            root );
     518             : 
     519             : 
     520             : FD_FN_PURE static inline int
     521        1829 : fd_store_has_disk( fd_store_t const * store ) {
     522        1829 :   return store->disk_max_shreds > 0UL;
     523        1829 : }
     524             : 
     525          45 : #define FD_STORE_DISK_INSERT_ERR       (-1)
     526          18 : #define FD_STORE_DISK_INSERT_DUP       ( 0)
     527        3678 : #define FD_STORE_DISK_INSERT_SUCCESS   ( 1)
     528             : 
     529          24 : #define FD_STORE_DISK_QUERY_BUSY       (-2)
     530         120 : #define FD_STORE_DISK_QUERY_MISS       (-1)
     531          24 : #define FD_STORE_DISK_QUERY_SCAN_LIMIT  (-4)
     532             : 
     533             : struct fd_store_disk_stats {
     534             :   ulong shred_cnt;
     535             :   ulong current_bytes;
     536             :   ulong allocated_bytes;
     537             :   ulong insert_cnt;
     538             :   ulong write_bytes;
     539             : };
     540             : typedef struct fd_store_disk_stats fd_store_disk_stats_t;
     541             : 
     542             : /* Persists one (slot,idx) shred, where idx is below max_shreds_per_block,
     543             :    whose FEC set has merkle root merkle_root (only the first
     544             :    FD_SHRED_MERKLE_NODE_SZ bytes are used).  Every version is indexed by
     545             :    (root,idx%FD_FEC_SHRED_CNT) and inserting a key already held by a
     546             :    READY cell is a no-op, so a different idx that aliases the same
     547             :    offset is dropped too.  The first version stored for a (slot,idx) is
     548             :    also indexed by (slot,idx).  Returns FD_STORE_DISK_INSERT_SUCCESS if
     549             :    written, FD_STORE_DISK_INSERT_DUP if already stored or dropped, or
     550             :    FD_STORE_DISK_INSERT_ERR. */
     551             : 
     552             : int
     553             : fd_store_disk_insert( fd_store_t       * store,
     554             :                       int                disk_fd,
     555             :                       fd_shred_t const * shred,
     556             :                       fd_hash_t const  * merkle_root );
     557             : 
     558             : /* Copies (slot,shred_idx) to out, where shred_idx is below
     559             :    max_shreds_per_block.  Returns its positive byte count, MISS, or
     560             :    retryable BUSY.  Only finds the first version stored. */
     561             : 
     562             : int
     563             : fd_store_disk_query( fd_store_t const * store,
     564             :                      int                disk_fd,
     565             :                      ulong              slot,
     566             :                      uint               shred_idx,
     567             :                      uchar              out[ FD_SHRED_MAX_SZ ] );
     568             : 
     569             : /* fd_store_disk_query_root copies the shred at shred_idx of the FEC set
     570             :    whose merkle root starts with the FD_SHRED_MERKLE_NODE_SZ bytes at
     571             :    merkle_root to out.  Finds any stored version.  Returns its positive
     572             :    byte count, MISS, or retryable BUSY. */
     573             : 
     574             : int
     575             : fd_store_disk_query_root( fd_store_t const * store,
     576             :                           int                disk_fd,
     577             :                           uchar const *      merkle_root,
     578             :                           uint               shred_idx,
     579             :                           uchar              out[ FD_SHRED_MAX_SZ ] );
     580             : 
     581             : /* Returns 0 if a query for (slot,shred_idx), or for the highest shred
     582             :    of slot when shred_idx is UINT_MAX, would certainly miss. */
     583             : 
     584             : int
     585             : fd_store_disk_probe( fd_store_t const * store,
     586             :                      ulong              slot,
     587             :                      uint               shred_idx );
     588             : 
     589             : /* Copies the cached highest stored shred in slot to out.  A shred below
     590             :    min_shred_idx is returned only if it completes the slot.  The compact
     591             :    hint is conservative and never lowered: a collision can keep returning
     592             :    BUSY and a stale upper bound can keep returning SCAN_LIMIT instead of
     593             :    risking a lower, incorrect answer.  Exact queries are unaffected.
     594             :    Otherwise returns a positive byte count or MISS. */
     595             : int
     596             : fd_store_disk_query_highest( fd_store_t const * store,
     597             :                              int                disk_fd,
     598             :                              ulong              slot,
     599             :                              uint               min_shred_idx,
     600             :                              uchar              out[ FD_SHRED_MAX_SZ ] );
     601             : 
     602             : /* Takes an approximate telemetry snapshot.  Returns 0 or MISS. */
     603             : 
     604             : int
     605             : fd_store_disk_stats_query( fd_store_t const *      store,
     606             :                            fd_store_disk_stats_t * stats );
     607             : 
     608             : FD_PROTOTYPES_END
     609             : 
     610             : #endif /* HEADER_fd_src_disco_store_fd_store_h */

Generated by: LCOV version 1.14