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 */
|