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 747 : ulong idx ) { 45 747 : FD_DCHECK_CRIT( visited_set_valid_idx( set, idx ), "idx out of bounds" ); 46 747 : ulong mask = 1UL << (idx & 63UL); 47 747 : ulong * word = &set[ idx>>6 ]; 48 747 : ulong prev = *word; 49 747 : *word = prev | mask; 50 747 : return !!( prev & mask ); 51 747 : } 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 : FD_PROTOTYPES_BEGIN 80 : 81 : static inline void 82 : fd_backup_overrun_push( fd_backup_overrun_t * q, 83 0 : uint acc_idx ) { 84 0 : uint pos = __atomic_fetch_add( &q->head, 1U, __ATOMIC_RELAXED ); 85 0 : fd_backup_overrun_slot_t * slot = &q->slot[ pos & (FD_BACKUP_OVERRUN_DEPTH-1U) ]; 86 0 : while( FD_UNLIKELY( __atomic_load_n( &slot->seq, __ATOMIC_ACQUIRE )!=pos-1U ) ) { 87 0 : FD_SPIN_PAUSE(); 88 0 : } 89 0 : slot->acc_idx = acc_idx; 90 0 : __atomic_store_n( &slot->seq, pos, __ATOMIC_RELEASE ); 91 0 : } 92 : 93 : FD_FN_CONST static inline ulong 94 0 : fd_backup_align( void ) { 95 0 : return fd_ulong_max( alignof(fd_backup_overrun_t), visited_set_align() ); 96 0 : } 97 : 98 : FD_FN_PURE static inline ulong 99 0 : fd_backup_footprint( ulong max_accounts ) { 100 0 : return FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, 101 0 : alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) ), 102 0 : visited_set_align(), visited_set_footprint( max_accounts ) ), 103 0 : fd_backup_align() ); 104 0 : } 105 : 106 : static inline void * 107 : fd_backup_new( void * mem, 108 0 : ulong max_accounts ) { 109 0 : if( FD_UNLIKELY( !mem ) ) return NULL; 110 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_backup_align() ) ) ) return NULL; 111 : 112 0 : FD_SCRATCH_ALLOC_INIT( l, mem ); 113 0 : fd_backup_overrun_t * q = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) ); 114 0 : void * set_mem = FD_SCRATCH_ALLOC_APPEND( l, visited_set_align(), visited_set_footprint( max_accounts ) ); 115 0 : FD_CHECK_CRIT( (ulong)q==(ulong)mem, "layout error" ); 116 : 117 0 : q->head = 0UL; 118 0 : q->tail = 0UL; 119 0 : for( uint i=0U; i<FD_BACKUP_OVERRUN_DEPTH; i++ ) { 120 0 : q->slot[ i ].seq = i-1U; 121 0 : q->slot[ i ].acc_idx = UINT_MAX; 122 0 : } 123 : 124 0 : if( FD_UNLIKELY( !visited_set_new( set_mem, max_accounts ) ) ) return NULL; 125 0 : return mem; 126 0 : } 127 : 128 : /* fd_backup_overrun returns a pointer to the overrun queue. */ 129 : 130 : FD_FN_CONST static inline fd_backup_overrun_t * 131 0 : fd_backup_overrun( void * mem ) { 132 0 : return (fd_backup_overrun_t *)mem; 133 0 : } 134 : 135 : /* fd_backup_set returns a join to the visited bit set. */ 136 : 137 : static inline visited_set_t * 138 0 : fd_backup_set( void * mem ) { 139 0 : FD_SCRATCH_ALLOC_INIT( l, mem ); 140 0 : /* */FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_backup_overrun_t), sizeof(fd_backup_overrun_t) ); 141 0 : void * set_mem = FD_SCRATCH_ALLOC_APPEND( l, visited_set_align(), visited_set_footprint( 1UL ) ); 142 0 : return visited_set_join( set_mem ); 143 0 : } 144 : 145 : FD_PROTOTYPES_END 146 : 147 : #endif /* HEADER_fd_src_discof_backup_fd_backup_shmem_h */