LCOV - code coverage report
Current view: top level - discof/backup - fd_backup_shmem.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 74 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 55 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_backup_fd_backup_shmem_h
       2             : #define HEADER_fd_src_discof_backup_fd_backup_shmem_h
       3             : 
       4             : /* fd_backup_shmem.h is a shared memory data structure tracking which
       5             :    accounts have been packed into the snapshot.  Each account is tracked by
       6             :    its position in the account index.
       7             : 
       8             :    For each visited account:
       9             :    - mark the account as visited (in snapmk)
      10             :    - copy and compress the account (in snapzp)
      11             :      - if the read failed recover via request from snapzp to snapmk
      12             : 
      13             :    Reads may fail when reading database cache that is concurrently
      14             :    evicted.  Accounts that failed to be read are added to the overrun
      15             :    queue, then retried via a later disk read.
      16             : 
      17             :    Data structures:
      18             :    - bit vector shadowing the account index
      19             :    - MPSC queue tracking overruns */
      20             : 
      21             : #include "../../util/fd_util.h"
      22             : 
      23             : /* Declare a bit vector */
      24             : 
      25             : #define SET_NAME visited_set
      26             : #include "../../util/tmpl/fd_set_dynamic.c"
      27             : 
      28             : static inline int
      29             : fd_backup_visited_test( visited_set_t const * set,
      30           0 :                         ulong                 idx ) {
      31           0 :   FD_DCHECK_CRIT( visited_set_valid_idx( set, idx ), "idx out of bounds" );
      32           0 :   return (int)( ( set[ idx>>6 ] >> (idx & 63UL) ) & 1UL );
      33           0 : }
      34             : 
      35             : static inline void
      36             : fd_backup_visited_insert( visited_set_t * set,
      37           0 :                           ulong           idx ) {
      38           0 :   FD_DCHECK_CRIT( visited_set_valid_idx( set, idx ), "idx out of bounds" );
      39           0 :   set[ idx>>6 ] |= 1UL << (idx & 63UL);
      40           0 : }
      41             : 
      42             : static inline int
      43             : fd_backup_visited_test_and_set( visited_set_t * set,
      44           0 :                                 ulong           idx ) {
      45           0 :   FD_DCHECK_CRIT( visited_set_valid_idx( set, idx ), "idx out of bounds" );
      46           0 :   ulong   mask = 1UL << (idx & 63UL);
      47           0 :   ulong * word = &set[ idx>>6 ];
      48           0 :   ulong   prev = *word;
      49           0 :   *word = prev | mask;
      50           0 :   return !!( prev & mask );
      51           0 : }
      52             : 
      53             : static inline void
      54             : fd_backup_visited_remove( visited_set_t * set,
      55           0 :                           ulong           idx ) {
      56           0 :   FD_DCHECK_CRIT( visited_set_valid_idx( set, idx ), "idx out of bounds" );
      57           0 :   set[ idx>>6 ] &= ~(1UL << (idx & 63UL));
      58           0 : }
      59             : 
      60             : /* Declare an MPSC queue for reporting overruns */
      61             : 
      62           0 : #define FD_BACKUP_OVERRUN_DEPTH (4096U)
      63             : 
      64             : struct __attribute__((aligned(8))) fd_backup_overrun_slot {
      65             :   uint seq;
      66             :   uint acc_idx;
      67             : };
      68             : 
      69             : typedef struct fd_backup_overrun_slot fd_backup_overrun_slot_t;
      70             : 
      71             : struct fd_backup_overrun {
      72             :   uint head __attribute__((aligned(128)));
      73             :   uint tail __attribute__((aligned(128)));
      74             :   fd_backup_overrun_slot_t slot[ FD_BACKUP_OVERRUN_DEPTH ] __attribute__((aligned(128)));
      75             : };
      76             : 
      77             : typedef struct fd_backup_overrun fd_backup_overrun_t;
      78             : 
      79             : /* Per-snapzp statistics for the snapshot currently being produced.
      80             :    Each snapzp tile owns one cache-line-sized entry.  snapmk reads all
      81             :    entries after the final flush barrier. */
      82             : 
      83             : #define FD_BACKUP_STATS_MAX 64UL
      84             : 
      85             : struct __attribute__((aligned(128))) fd_backup_worker_stats {
      86             :   ulong account_cnt;
      87             :   ulong account_sz;
      88             :   ulong tombstone_cnt;
      89             :   ulong cached_account_cnt;
      90             :   ulong disk_account_cnt;
      91             :   ulong zstd_data_frame_cnt;
      92             :   ulong zstd_padding_sz;
      93             :   ulong uncompressed_sz;
      94             :   ulong compress_ticks;
      95             :   ulong io_blocked_ticks;
      96             :   ulong reserved[ 6 ];
      97             : };
      98             : 
      99             : typedef struct fd_backup_worker_stats fd_backup_worker_stats_t;
     100             : 
     101             : struct fd_backup_stats {
     102             :   fd_backup_worker_stats_t worker[ FD_BACKUP_STATS_MAX ];
     103             : };
     104             : 
     105             : typedef struct fd_backup_stats fd_backup_stats_t;
     106             : 
     107             : FD_PROTOTYPES_BEGIN
     108             : 
     109             : static inline void
     110             : fd_backup_overrun_push( fd_backup_overrun_t * q,
     111           0 :                         uint                  acc_idx ) {
     112           0 :   uint pos = __atomic_fetch_add( &q->head, 1U, __ATOMIC_RELAXED );
     113           0 :   fd_backup_overrun_slot_t * slot = &q->slot[ pos & (FD_BACKUP_OVERRUN_DEPTH-1U) ];
     114           0 :   while( FD_UNLIKELY( __atomic_load_n( &slot->seq, __ATOMIC_ACQUIRE )!=pos-1U ) ) {
     115           0 :     FD_SPIN_PAUSE();
     116           0 :   }
     117           0 :   slot->acc_idx = acc_idx;
     118           0 :   __atomic_store_n( &slot->seq, pos, __ATOMIC_RELEASE );
     119           0 : }
     120             : 
     121             : FD_FN_CONST static inline ulong
     122           0 : fd_backup_align( void ) {
     123           0 :   return fd_ulong_max( fd_ulong_max( alignof(fd_backup_overrun_t), alignof(fd_backup_stats_t) ), visited_set_align() );
     124           0 : }
     125             : 
     126             : FD_FN_PURE static inline ulong
     127           0 : fd_backup_footprint( ulong max_accounts ) {
     128           0 :   ulong l = FD_LAYOUT_INIT;
     129           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t)             );
     130           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_backup_stats_t),   sizeof(fd_backup_stats_t)               );
     131           0 :   l = FD_LAYOUT_APPEND( l, visited_set_align(),          visited_set_footprint( max_accounts )   );
     132           0 :   return FD_LAYOUT_FINI( l, fd_backup_align() );
     133           0 : }
     134             : 
     135             : static inline void *
     136             : fd_backup_new( void * mem,
     137           0 :                ulong  max_accounts ) {
     138           0 :   if( FD_UNLIKELY( !mem ) ) return NULL;
     139           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_backup_align() ) ) ) return NULL;
     140             : 
     141           0 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     142           0 :   fd_backup_overrun_t * q       = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) );
     143           0 :   fd_backup_stats_t *   stats   = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_stats_t), sizeof(fd_backup_stats_t) );
     144           0 :   void *                set_mem = FD_SCRATCH_ALLOC_APPEND( l, visited_set_align(),      visited_set_footprint( max_accounts ) );
     145           0 :   FD_CHECK_CRIT( (ulong)q==(ulong)mem, "layout error" );
     146             : 
     147           0 :   q->head = 0UL;
     148           0 :   q->tail = 0UL;
     149           0 :   for( uint i=0U; i<FD_BACKUP_OVERRUN_DEPTH; i++ ) {
     150           0 :     q->slot[ i ].seq     = i-1U;
     151           0 :     q->slot[ i ].acc_idx = UINT_MAX;
     152           0 :   }
     153             : 
     154           0 :   fd_memset( stats, 0, sizeof(fd_backup_stats_t) );
     155             : 
     156           0 :   if( FD_UNLIKELY( !visited_set_new( set_mem, max_accounts ) ) ) return NULL;
     157           0 :   return mem;
     158           0 : }
     159             : 
     160             : /* fd_backup_overrun returns a pointer to the overrun queue. */
     161             : 
     162             : FD_FN_CONST static inline fd_backup_overrun_t *
     163           0 : fd_backup_overrun( void * mem ) {
     164           0 :   return (fd_backup_overrun_t *)mem;
     165           0 : }
     166             : 
     167             : /* fd_backup_stats returns per-worker snapshot statistics. */
     168             : 
     169             : static inline fd_backup_stats_t *
     170           0 : fd_backup_stats( void * mem ) {
     171           0 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     172           0 :   /*                        */FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) );
     173           0 :   fd_backup_stats_t * stats = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_stats_t), sizeof(fd_backup_stats_t) );
     174           0 :   return stats;
     175           0 : }
     176             : 
     177             : /* fd_backup_set returns a join to the visited bit set. */
     178             : 
     179             : static inline visited_set_t *
     180           0 : fd_backup_set( void * mem ) {
     181           0 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     182           0 :   /*             */FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) );
     183           0 :   /*             */FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_stats_t),   sizeof(fd_backup_stats_t)   );
     184           0 :   void * set_mem = FD_SCRATCH_ALLOC_APPEND( l, visited_set_align(),          visited_set_footprint( 1UL ) );
     185           0 :   return visited_set_join( set_mem );
     186           0 : }
     187             : 
     188             : FD_PROTOTYPES_END
     189             : 
     190             : #endif /* HEADER_fd_src_discof_backup_fd_backup_shmem_h */

Generated by: LCOV version 1.14