Line data Source code
1 : #include "fd_bank.h"
2 : #include "../../util/fd_util_base.h"
3 :
4 : ulong
5 24 : fd_bank_align( void ) {
6 24 : return alignof(fd_bank_t);
7 24 : }
8 :
9 : ulong
10 6 : fd_bank_footprint( void ) {
11 6 : ulong l = FD_LAYOUT_INIT;
12 6 : l = FD_LAYOUT_APPEND( l, fd_bank_align(), sizeof(fd_bank_t) );
13 6 : return FD_LAYOUT_FINI( l, fd_bank_align() );
14 6 : }
15 :
16 : /* Bank accesssors */
17 :
18 : #define HAS_COW_1(type, name, footprint, align, has_lock) \
19 : type const * \
20 0 : fd_bank_##name##_locking_query( fd_bank_t * bank ) { \
21 0 : fd_rwlock_read( &bank->name##_lock ); \
22 0 : /* If the pool element hasn't been setup yet, then return NULL */ \
23 0 : fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank ); \
24 0 : if( FD_UNLIKELY( name##_pool==NULL ) ) { \
25 0 : FD_LOG_CRIT(( "NULL " #name " pool" )); \
26 0 : } \
27 0 : if( bank->name##_pool_idx==fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
28 0 : return NULL; \
29 0 : } \
30 0 : fd_bank_##name##_t * bank_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx ); \
31 0 : return (type *)bank_##name->data; \
32 0 : } \
33 : void \
34 0 : fd_bank_##name##_end_locking_query( fd_bank_t * bank ) { \
35 0 : fd_rwlock_unread( &bank->name##_lock ); \
36 0 : } \
37 : type * \
38 0 : fd_bank_##name##_locking_modify( fd_bank_t * bank ) { \
39 0 : fd_rwlock_write( &bank->name##_lock ); \
40 0 : /* If the dirty flag is set, then we already have a pool element */ \
41 0 : /* that was copied over for the current bank. We can simply just */ \
42 0 : /* query the pool element and return it. */ \
43 0 : fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank ); \
44 0 : if( FD_UNLIKELY( name##_pool==NULL ) ) { \
45 0 : FD_LOG_CRIT(( "NULL " #name " pool" )); \
46 0 : } \
47 0 : if( bank->name##_dirty ) { \
48 0 : fd_bank_##name##_t * bank_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx ); \
49 0 : return (type *)bank_##name->data; \
50 0 : } \
51 0 : fd_bank_##name##_t * child_##name = fd_bank_##name##_pool_ele_acquire( name##_pool ); \
52 0 : if( FD_UNLIKELY( !child_##name ) ) { \
53 0 : FD_LOG_CRIT(( "Failed to acquire " #name " pool element" )); \
54 0 : } \
55 0 : /* If the dirty flag has not been set yet, we need to allocated a */ \
56 0 : /* new pool element and copy over the data from the parent idx. */ \
57 0 : /* We also need to mark the dirty flag. */ \
58 0 : ulong child_idx = fd_bank_##name##_pool_idx( name##_pool, child_##name ); \
59 0 : if( bank->name##_pool_idx!=fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
60 0 : fd_bank_##name##_t * parent_##name = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx ); \
61 0 : fd_memcpy( child_##name->data, parent_##name->data, fd_bank_##name##_footprint ); \
62 0 : } \
63 0 : bank->name##_pool_idx = child_idx; \
64 0 : bank->name##_dirty = 1; \
65 0 : return (type *)child_##name->data; \
66 0 : } \
67 : void \
68 0 : fd_bank_##name##_end_locking_modify( fd_bank_t * bank ) { \
69 0 : fd_rwlock_unwrite( &bank->name##_lock ); \
70 0 : }
71 :
72 :
73 : #define HAS_LOCK_0(type, name) \
74 : type const * \
75 42 : fd_bank_##name##_query( fd_bank_t * bank ) { \
76 42 : return (type const *)fd_type_pun_const( bank->name ); \
77 42 : } \
78 : type * \
79 0 : fd_bank_##name##_modify( fd_bank_t * bank ) { \
80 0 : return (type *)fd_type_pun( bank->name ); \
81 0 : }
82 :
83 : #define HAS_LOCK_1(type, name) \
84 : type const * \
85 : fd_bank_##name##_locking_query( fd_bank_t * bank ) { \
86 : fd_rwlock_read( &bank->name##_lock ); \
87 : return (type const *)fd_type_pun_const( bank->name ); \
88 : } \
89 : type * \
90 : fd_bank_##name##_locking_modify( fd_bank_t * bank ) { \
91 : fd_rwlock_write( &bank->name##_lock ); \
92 : ACQUIRE_WRITE_##has_lock( name ); \
93 : return (type *)fd_type_pun( bank->name ); \
94 : } \
95 : void \
96 : fd_bank_##name##_end_locking_query( fd_bank_t * bank ) { \
97 : fd_rwlock_unread( &bank->name##_lock ); \
98 : } \
99 : void \
100 : fd_bank_##name##_end_locking_modify( fd_bank_t * bank ) { \
101 : fd_rwlock_unwrite( &bank->name##_lock ); \
102 : }
103 :
104 : #define HAS_COW_0(type, name, footprint, align, has_lock) \
105 : HAS_LOCK_##has_lock(type, name) \
106 : void \
107 15 : fd_bank_##name##_set( fd_bank_t * bank, type value ) { \
108 15 : FD_STORE( type, bank->name, value ); \
109 15 : } \
110 : type \
111 42 : fd_bank_##name##_get( fd_bank_t * bank ) { \
112 42 : type val = FD_LOAD( type, bank->name ); \
113 42 : return val; \
114 42 : }
115 :
116 : #define X(type, name, footprint, align, cow, has_lock) \
117 : HAS_COW_##cow(type, name, footprint, align, has_lock)
118 : FD_BANKS_ITER(X)
119 : #undef X
120 : #undef HAS_COW_0
121 : #undef HAS_COW_1
122 : #undef HAS_LOCK_0
123 : #undef HAS_LOCK_1
124 :
125 : /**********************************************************************/
126 :
127 : ulong
128 114 : fd_banks_align( void ) {
129 : /* TODO: The magic number here can probably be removed. */
130 114 : return 128UL;
131 114 : }
132 :
133 : ulong
134 12 : fd_banks_footprint( ulong max_banks ) {
135 :
136 12 : ulong l = FD_LAYOUT_INIT;
137 12 : l = FD_LAYOUT_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
138 12 : l = FD_LAYOUT_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_banks ) );
139 12 : l = FD_LAYOUT_APPEND( l, fd_banks_map_align(), fd_banks_map_footprint( max_banks ) );
140 :
141 : /* Need to count the footprint for all of the CoW pools. */
142 12 : #define HAS_COW_1(name) \
143 96 : l = FD_LAYOUT_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( max_banks ) );
144 :
145 : /* Do nothing for these. */
146 12 : #define HAS_COW_0(name)
147 :
148 12 : #define X(type, name, footprint, align, cow, has_lock) \
149 96 : HAS_COW_##cow(name)
150 96 : FD_BANKS_ITER(X)
151 12 : #undef X
152 12 : #undef HAS_COW_0
153 12 : #undef HAS_COW_1
154 :
155 12 : return FD_LAYOUT_FINI( l, fd_banks_align() );
156 12 : }
157 :
158 : void *
159 6 : fd_banks_new( void * shmem, ulong max_banks ) {
160 :
161 6 : fd_banks_t * banks = (fd_banks_t *)shmem;
162 :
163 6 : if( FD_UNLIKELY( !banks ) ) {
164 0 : FD_LOG_WARNING(( "NULL banks" ));
165 0 : return NULL;
166 0 : }
167 :
168 6 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks, fd_banks_align() ) ) ) {
169 0 : FD_LOG_WARNING(( "misaligned banks" ));
170 0 : return NULL;
171 0 : }
172 :
173 : /* Set the rwlock to unlocked. */
174 6 : fd_rwlock_unwrite( &banks->rwlock );
175 :
176 : /* First, layout the banks and the pool/map used by fd_banks_t. */
177 6 : FD_SCRATCH_ALLOC_INIT( l, banks );
178 6 : banks = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
179 6 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_banks ) );
180 6 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_map_align(), fd_banks_map_footprint( max_banks ) );
181 :
182 : /* Need to layout all of the CoW pools. */
183 0 : #define HAS_COW_1(name) \
184 48 : void * name##_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( max_banks ) ); \
185 48 : memset( name##_pool_mem, 0, fd_bank_##name##_pool_footprint( max_banks ) );
186 :
187 : /* Do nothing for these. */
188 0 : #define HAS_COW_0(name)
189 :
190 0 : #define X(type, name, footprint, align, cow, has_lock) \
191 48 : HAS_COW_##cow(name)
192 48 : FD_BANKS_ITER(X)
193 48 : #undef X
194 48 : #undef HAS_COW_0
195 48 : #undef HAS_COW_1
196 :
197 48 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() ) != (ulong)banks + fd_banks_footprint( max_banks ) ) ) {
198 0 : FD_LOG_WARNING(( "fd_banks_new: bad layout" ));
199 0 : return NULL;
200 0 : }
201 :
202 6 : void * pool = fd_banks_pool_new( pool_mem, max_banks );
203 6 : if( FD_UNLIKELY( !pool ) ) {
204 0 : FD_LOG_WARNING(( "Failed to create bank pool" ));
205 0 : return NULL;
206 0 : }
207 :
208 6 : fd_bank_t * bank_pool = fd_banks_pool_join( pool );
209 6 : if( FD_UNLIKELY( !bank_pool ) ) {
210 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
211 0 : return NULL;
212 0 : }
213 :
214 6 : fd_banks_set_bank_pool( banks, bank_pool );
215 :
216 6 : void * map = fd_banks_map_new( map_mem, max_banks, 999UL );
217 6 : if( FD_UNLIKELY( !map ) ) {
218 0 : FD_LOG_WARNING(( "Failed to create bank map" ));
219 0 : return NULL;
220 0 : }
221 :
222 6 : fd_banks_map_t * bank_map = fd_banks_map_join( map_mem );
223 6 : if( FD_UNLIKELY( !bank_map ) ) {
224 0 : FD_LOG_WARNING(( "Failed to join bank map" ));
225 0 : return NULL;
226 0 : }
227 :
228 6 : fd_banks_set_bank_map( banks, bank_map );
229 :
230 : /* Now, call _new() and _join() for all of the CoW pools. */
231 6 : #define HAS_COW_1(name) \
232 48 : void * name##_mem = fd_bank_##name##_pool_new( name##_pool_mem, max_banks ); \
233 48 : if( FD_UNLIKELY( !name##_mem ) ) { \
234 0 : FD_LOG_WARNING(( "Failed to create " #name " pool" )); \
235 0 : return NULL; \
236 0 : } \
237 48 : fd_bank_##name##_t * name##_pool = fd_bank_##name##_pool_join( name##_pool_mem ); \
238 48 : if( FD_UNLIKELY( !name##_pool ) ) { \
239 0 : FD_LOG_WARNING(( "Failed to join " #name " pool" )); \
240 0 : return NULL; \
241 0 : } \
242 48 : fd_banks_set_##name##_pool( banks, name##_pool );
243 :
244 : /* Do nothing for these. */
245 6 : #define HAS_COW_0(name)
246 :
247 6 : #define X(type, name, footprint, align, cow, has_lock) \
248 48 : HAS_COW_##cow(name)
249 48 : FD_BANKS_ITER(X)
250 6 : #undef X
251 6 : #undef HAS_COW_0
252 6 : #undef HAS_COW_1
253 :
254 6 : banks->max_banks = max_banks;
255 6 : banks->magic = FD_BANKS_MAGIC;
256 :
257 6 : return shmem;
258 90 : }
259 :
260 : fd_banks_t *
261 6 : fd_banks_join( void * mem ) {
262 6 : fd_banks_t * banks = (fd_banks_t *)mem;
263 :
264 6 : if( FD_UNLIKELY( !banks ) ) {
265 0 : FD_LOG_WARNING(( "NULL banks" ));
266 0 : return NULL;
267 0 : }
268 :
269 6 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks, fd_banks_align() ) ) ) {
270 0 : FD_LOG_WARNING(( "misaligned banks" ));
271 0 : return NULL;
272 0 : }
273 :
274 6 : if( FD_UNLIKELY( banks->magic!=FD_BANKS_MAGIC ) ) {
275 0 : FD_LOG_WARNING(( "Invalid banks magic" ));
276 0 : return NULL;
277 0 : }
278 :
279 6 : FD_SCRATCH_ALLOC_INIT( l, banks );
280 6 : banks = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
281 6 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( banks->max_banks ) );
282 6 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_map_align(), fd_banks_map_footprint( banks->max_banks ) );
283 :
284 : /* Need to layout all of the CoW pools. */
285 0 : #define HAS_COW_1(name) \
286 48 : void * name##_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_##name##_pool_align(), fd_bank_##name##_pool_footprint( banks->max_banks ) );
287 :
288 : /* Don't need to layout if not CoW. */
289 0 : #define HAS_COW_0(name)
290 :
291 0 : #define X(type, name, footprint, align, cow, has_lock) \
292 48 : HAS_COW_##cow(name)
293 48 : FD_BANKS_ITER(X)
294 0 : #undef X
295 0 : #undef HAS_COW_0
296 0 : #undef HAS_COW_1
297 :
298 6 : FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() );
299 :
300 48 : fd_bank_t * banks_pool = fd_banks_get_bank_pool( banks );
301 48 : if( FD_UNLIKELY( !banks_pool ) ) {
302 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
303 0 : return NULL;
304 0 : }
305 :
306 6 : if( FD_UNLIKELY( banks_pool!=fd_banks_pool_join( pool_mem ) ) ) {
307 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
308 0 : return NULL;
309 0 : }
310 :
311 6 : fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
312 6 : if( FD_UNLIKELY( !bank_map ) ) {
313 0 : FD_LOG_WARNING(( "Failed to join bank map" ));
314 0 : return NULL;
315 0 : }
316 :
317 6 : if( FD_UNLIKELY( bank_map!=fd_banks_map_join( map_mem ) ) ) {
318 0 : FD_LOG_WARNING(( "Failed to join bank map" ));
319 0 : return NULL;
320 0 : }
321 :
322 : /* Now, call _join() for all of the CoW pools. */
323 6 : #define HAS_COW_1(name) \
324 48 : fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
325 48 : if( FD_UNLIKELY( !name##_pool ) ) { \
326 0 : FD_LOG_WARNING(( "Failed to join " #name " pool" )); \
327 0 : return NULL; \
328 0 : } \
329 48 : if( FD_UNLIKELY( name##_pool!=fd_bank_##name##_pool_join( name##_pool_mem ) ) ) { \
330 0 : FD_LOG_WARNING(( "Failed to join " #name " pool" )); \
331 0 : return NULL; \
332 0 : }
333 :
334 : /* Do nothing when the field is not CoW. */
335 6 : #define HAS_COW_0(name)
336 :
337 6 : #define X(type, name, footprint, align, cow, has_lock) \
338 48 : HAS_COW_##cow(name)
339 96 : FD_BANKS_ITER(X)
340 6 : #undef X
341 6 : #undef HAS_COW_0
342 6 : #undef HAS_COW_1
343 :
344 :
345 6 : return banks;
346 96 : }
347 :
348 : void *
349 0 : fd_banks_leave( fd_banks_t * banks ) {
350 :
351 0 : if( FD_UNLIKELY( !banks ) ) {
352 0 : FD_LOG_WARNING(( "NULL banks" ));
353 0 : return NULL;
354 0 : }
355 :
356 0 : return (void *)banks;
357 0 : }
358 :
359 : void *
360 0 : fd_banks_delete( void * shmem ) {
361 :
362 0 : if( FD_UNLIKELY( !shmem ) ) {
363 0 : FD_LOG_WARNING(( "NULL banks" ));
364 0 : return NULL;
365 0 : }
366 :
367 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shmem, fd_banks_align() ) ) ) {
368 0 : FD_LOG_WARNING(( "misaligned banks" ));
369 0 : return NULL;
370 0 : }
371 :
372 0 : return shmem;
373 0 : }
374 :
375 : fd_bank_t *
376 6 : fd_banks_init_bank( fd_banks_t * banks, ulong slot ) {
377 :
378 6 : if( FD_UNLIKELY( !banks ) ) {
379 0 : FD_LOG_WARNING(( "NULL banks" ));
380 0 : return NULL;
381 0 : }
382 :
383 6 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
384 6 : fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
385 :
386 6 : fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
387 6 : if( FD_UNLIKELY( bank==NULL ) ) {
388 0 : FD_LOG_WARNING(( "Failed to acquire bank" ));
389 0 : return NULL;
390 0 : }
391 :
392 6 : memset( bank, 0, fd_bank_footprint() );
393 :
394 6 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
395 6 : bank->slot = slot;
396 6 : bank->next = null_idx;
397 6 : bank->parent_idx = null_idx;
398 6 : bank->child_idx = null_idx;
399 6 : bank->sibling_idx = null_idx;
400 :
401 : /* Set all CoW fields to null. */
402 6 : #define HAS_COW_1(name) \
403 48 : fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
404 48 : fd_bank_set_##name##_pool( bank, name##_pool ); \
405 48 : bank->name##_pool_idx = fd_bank_##name##_pool_idx_null( name##_pool ); \
406 48 : bank->name##_dirty = 0;
407 :
408 : /* Do nothing for these. */
409 6 : #define HAS_COW_0(name)
410 :
411 6 : #define HAS_LOCK_1(name) \
412 48 : fd_rwlock_unwrite(&bank->name##_lock);
413 6 : #define HAS_LOCK_0(name)
414 :
415 6 : #define X(type, name, footprint, align, cow, has_lock) \
416 318 : HAS_COW_##cow(name); \
417 318 : HAS_LOCK_##has_lock(name)
418 318 : FD_BANKS_ITER(X)
419 6 : #undef X
420 6 : #undef HAS_COW_0
421 6 : #undef HAS_COW_1
422 6 : #undef HAS_LOCK_0
423 6 : #undef HAS_LOCK_1
424 :
425 6 : fd_banks_map_ele_insert( bank_map, bank, bank_pool );
426 :
427 : /* Now that the node is inserted, update the root */
428 :
429 6 : banks->root = slot;
430 6 : banks->root_idx = fd_banks_pool_idx( bank_pool, bank );
431 :
432 6 : return bank;
433 6 : }
434 :
435 : fd_bank_t *
436 15 : fd_banks_get_bank( fd_banks_t * banks, ulong slot ) {
437 :
438 15 : fd_bank_t * bank = NULL;
439 :
440 15 : fd_rwlock_read( &banks->rwlock );
441 :
442 15 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
443 15 : fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
444 :
445 15 : bank = fd_banks_map_ele_query( bank_map, &slot, NULL, bank_pool );
446 15 : if( FD_UNLIKELY( !bank ) ) {
447 6 : FD_LOG_WARNING(( "Failed to get bank" ));
448 6 : return NULL;
449 6 : }
450 :
451 9 : fd_rwlock_unread( &banks->rwlock );
452 :
453 9 : return bank;
454 15 : }
455 :
456 :
457 : fd_bank_t *
458 : fd_banks_clone_from_parent( fd_banks_t * banks,
459 : ulong slot,
460 30 : ulong parent_slot ) {
461 :
462 30 : fd_rwlock_write( &banks->rwlock );
463 :
464 30 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
465 30 : fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
466 :
467 : /* First query for the parent bank */
468 :
469 30 : fd_bank_t * parent_bank = fd_banks_map_ele_query( bank_map, &parent_slot, NULL, bank_pool );
470 :
471 30 : if( FD_UNLIKELY( !parent_bank ) ) {
472 0 : FD_LOG_WARNING(( "Failed to get bank" ));
473 0 : fd_rwlock_unwrite( &banks->rwlock );
474 0 : return NULL;
475 0 : }
476 :
477 30 : if( FD_UNLIKELY( parent_bank->slot != parent_slot ) ) {
478 0 : FD_LOG_WARNING(( "Parent slot mismatch" ));
479 0 : fd_rwlock_unwrite( &banks->rwlock );
480 0 : return NULL;
481 0 : }
482 :
483 30 : ulong parent_idx = fd_banks_pool_idx( bank_pool, parent_bank );
484 :
485 : /* Now acquire a new bank */
486 :
487 30 : fd_bank_t * new_bank = fd_banks_pool_ele_acquire( bank_pool );
488 30 : if( FD_UNLIKELY( !new_bank ) ) {
489 0 : FD_LOG_WARNING(( "Failed to acquire bank" ));
490 0 : fd_rwlock_unwrite( &banks->rwlock );
491 0 : return NULL;
492 0 : }
493 :
494 30 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
495 :
496 30 : new_bank->slot = slot;
497 30 : new_bank->next = null_idx;
498 30 : new_bank->parent_idx = null_idx;
499 30 : new_bank->child_idx = null_idx;
500 30 : new_bank->sibling_idx = null_idx;
501 :
502 30 : fd_banks_map_ele_insert( bank_map, new_bank, bank_pool );
503 :
504 30 : ulong child_idx = fd_banks_pool_idx( bank_pool, new_bank );
505 :
506 : /* Link node->parent */
507 :
508 30 : new_bank->parent_idx = parent_idx;
509 :
510 : /* Link parent->node and sibling->node */
511 :
512 30 : if( FD_LIKELY( parent_bank->child_idx == null_idx ) ) {
513 :
514 : /* This is the first child so set as left-most child */
515 :
516 18 : parent_bank->child_idx = child_idx;
517 :
518 18 : } else {
519 :
520 : /* Already have children so iterate to right-most sibling. */
521 :
522 12 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
523 15 : while( curr_bank->sibling_idx != null_idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
524 :
525 : /* Link to right-most sibling. */
526 :
527 12 : curr_bank->sibling_idx = child_idx;
528 :
529 12 : }
530 :
531 : /* We want to copy over the fields from the parent to the child,
532 : except for the fields which correspond to the header of the bank
533 : struct which is used for pool and map management. We can take
534 : advantage of the fact that those fields are laid out at the top
535 : of the bank struct. */
536 :
537 30 : memcpy( (uchar *)new_bank + FD_BANK_HEADER_SIZE, (uchar *)parent_bank + FD_BANK_HEADER_SIZE, sizeof(fd_bank_t) - FD_BANK_HEADER_SIZE );
538 :
539 : /* Setup all of the CoW fields. */
540 30 : #define HAS_COW_1(name) \
541 240 : new_bank->name##_pool_idx = parent_bank->name##_pool_idx; \
542 240 : new_bank->name##_dirty = 0UL; \
543 240 : fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
544 240 : fd_bank_set_##name##_pool( new_bank, name##_pool );
545 :
546 : /* Do nothing if not CoW. */
547 30 : #define HAS_COW_0(name)
548 :
549 : /* Setup locks for new bank as free. */
550 30 : #define HAS_LOCK_1(name) \
551 240 : fd_rwlock_unwrite(&new_bank->name##_lock);
552 30 : #define HAS_LOCK_0(name)
553 :
554 30 : #define X(type, name, footprint, align, cow, has_lock) \
555 1590 : HAS_COW_##cow(name); \
556 1590 : HAS_LOCK_##has_lock(name)
557 1590 : FD_BANKS_ITER(X)
558 30 : #undef X
559 30 : #undef HAS_COW_0
560 30 : #undef HAS_COW_1
561 30 : #undef HAS_LOCK_0
562 30 : #undef HAS_LOCK_1
563 :
564 30 : fd_rwlock_unwrite( &banks->rwlock );
565 :
566 30 : return new_bank;
567 30 : }
568 :
569 : fd_bank_t const *
570 3 : fd_banks_publish( fd_banks_t * banks, ulong slot ) {
571 :
572 3 : fd_rwlock_write( &banks->rwlock );
573 :
574 3 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
575 3 : fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
576 :
577 3 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
578 :
579 : /* We want to replace the old root with the new root. This means we
580 : have to remove banks that aren't descendants of the new root. */
581 :
582 3 : fd_bank_t const * old_root = fd_banks_root( banks );
583 3 : if( FD_UNLIKELY( !old_root ) ) {
584 0 : FD_LOG_WARNING(( "Failed to get root bank" ));
585 0 : fd_rwlock_unwrite( &banks->rwlock );
586 0 : return NULL;
587 0 : }
588 :
589 3 : fd_bank_t * new_root = fd_banks_map_ele_query( bank_map, &slot, NULL, bank_pool );
590 3 : if( FD_UNLIKELY( !new_root ) ) {
591 0 : FD_LOG_WARNING(( "Failed to get new root bank" ));
592 0 : fd_rwlock_unwrite( &banks->rwlock );
593 0 : return NULL;
594 0 : }
595 :
596 3 : fd_bank_t * head = fd_banks_map_ele_remove( bank_map, &old_root->slot, NULL, bank_pool );
597 3 : head->next = fd_banks_pool_idx_null( bank_pool );
598 3 : fd_bank_t * tail = head;
599 :
600 21 : while( head ) {
601 18 : fd_bank_t * child = fd_banks_pool_ele( bank_pool, head->child_idx );
602 :
603 36 : while( FD_LIKELY( child ) ) {
604 :
605 18 : if( FD_LIKELY( child!=new_root ) ) {
606 :
607 : /* Remove the child from the map first and push onto the
608 : frontier list that needs to be iterated through */
609 15 : tail->next = fd_banks_map_idx_remove( bank_map,
610 15 : &child->slot,
611 15 : fd_banks_pool_idx_null( bank_pool ),
612 15 : bank_pool );
613 :
614 15 : tail = fd_banks_pool_ele( bank_pool, tail->next );
615 15 : tail->next = fd_banks_pool_idx_null( bank_pool );
616 :
617 15 : }
618 :
619 18 : child = fd_banks_pool_ele( bank_pool, child->sibling_idx );
620 18 : }
621 :
622 18 : fd_bank_t * next = fd_banks_pool_ele( bank_pool, head->next );
623 :
624 : /* Decide if we need to free any CoW fields. We free a CoW member
625 : from its pool if the dirty flag is set unless it is the same
626 : pool that the new root uses. */
627 18 : #define HAS_COW_1(name) \
628 144 : if( head->name##_dirty && head->name##_pool_idx!=new_root->name##_pool_idx ) { \
629 0 : fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
630 0 : fd_bank_##name##_pool_idx_release( name##_pool, head->name##_pool_idx ); \
631 0 : }
632 : /* Do nothing for these. */
633 18 : #define HAS_COW_0(name)
634 :
635 18 : #define X(type, name, footprint, align, cow, has_lock) \
636 144 : HAS_COW_##cow(name)
637 144 : FD_BANKS_ITER(X)
638 18 : #undef X
639 18 : #undef HAS_COW_0
640 18 : #undef HAS_COW_1
641 :
642 :
643 18 : fd_banks_pool_ele_release( bank_pool, head );
644 18 : head = next;
645 18 : }
646 :
647 : /* If the new root did not have the dirty bit set, that means the node
648 : didn't own the pool index. Change the ownership to the new root. */
649 3 : #define HAS_COW_1(name) \
650 24 : fd_bank_##name##_t * name##_pool = fd_banks_get_##name##_pool( banks ); \
651 24 : if( new_root->name##_pool_idx!=fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
652 0 : new_root->name##_dirty = 1; \
653 0 : }
654 : /* Do nothing if not CoW. */
655 3 : #define HAS_COW_0(name)
656 :
657 3 : #define X(type, name, footprint, align, cow, has_lock) \
658 24 : HAS_COW_##cow(name)
659 24 : FD_BANKS_ITER(X)
660 3 : #undef X
661 3 : #undef HAS_COW_0
662 3 : #undef HAS_COW_1
663 :
664 3 : new_root->parent_idx = null_idx;
665 3 : banks->root_idx = fd_banks_map_idx_query( bank_map, &slot, null_idx, bank_pool );
666 3 : banks->root = slot;
667 :
668 3 : fd_rwlock_unwrite( &banks->rwlock );
669 :
670 3 : return new_root;
671 3 : }
672 :
673 : void
674 0 : fd_bank_clear_bank( fd_bank_t * bank ) {
675 :
676 0 : #define HAS_COW_1(type, name, footprint) \
677 0 : fd_bank_##name##_t * name##_pool = fd_bank_get_##name##_pool( bank ); \
678 0 : if( bank->name##_pool_idx==fd_bank_##name##_pool_idx_null( name##_pool ) ) { \
679 0 : return; \
680 0 : } \
681 0 : fd_bank_##name##_t * name##_ele = fd_bank_##name##_pool_ele( name##_pool, bank->name##_pool_idx ); \
682 0 : fd_memset( name##_ele->data, 0, footprint );
683 :
684 0 : #define HAS_COW_0(type, name, footprint) \
685 0 : fd_memset( bank->name, 0, footprint );
686 :
687 0 : #define X(type, name, footprint, align, cow, has_lock) \
688 0 : HAS_COW_##cow(type, name, footprint)
689 0 : FD_BANKS_ITER(X)
690 0 : #undef X
691 0 : #undef HAS_COW_0
692 0 : #undef HAS_COW_1
693 0 : }
|