Line data Source code
1 : #ifndef HEADER_fd_src_choreo_forks_fd_forks_h 2 : #define HEADER_fd_src_choreo_forks_fd_forks_h 3 : 4 : #include "../../flamenco/runtime/context/fd_exec_epoch_ctx.h" 5 : #include "../../flamenco/runtime/context/fd_exec_slot_ctx.h" 6 : #include "../../flamenco/runtime/fd_blockstore.h" 7 : #include "../fd_choreo_base.h" 8 : #include "../ghost/fd_ghost.h" 9 : 10 : /* FD_FORKS_USE_HANDHOLDING: Define this to non-zero at compile time 11 : to turn on additional runtime checks and logging. */ 12 : 13 : #ifndef FD_FORKS_USE_HANDHOLDING 14 : #define FD_FORKS_USE_HANDHOLDING 1 15 : #endif 16 : 17 : struct fd_fork { 18 : ulong slot; /* the fork head and frontier key */ 19 : ulong next; /* reserved for use by fd_pool and fd_map_chain */ 20 : ulong prev; /* reserved for use by fd_forks_publish */ 21 : int lock; /* IMPORTANT SAFETY TIP! lock is a boolean indicating 22 : whether a fork's most recent block is still being 23 : actively replayed (executed) and should generally not 24 : be read or written to by downstream consumers (eg. 25 : consensus, publishing) and should definitely not be 26 : removed. */ 27 : fd_exec_slot_ctx_t slot_ctx; 28 : }; 29 : 30 : typedef struct fd_fork fd_fork_t; 31 : 32 : #define POOL_NAME fd_fork_pool 33 0 : #define POOL_T fd_fork_t 34 : #include "../../util/tmpl/fd_pool.c" 35 : 36 : #define MAP_NAME fd_fork_frontier 37 : #define MAP_ELE_T fd_fork_t 38 0 : #define MAP_KEY slot 39 : #include "../../util/tmpl/fd_map_chain.c" 40 : 41 : struct fd_forks { 42 : fd_fork_frontier_t * frontier; /* the fork heads, map of slot->fd_fork_t */ 43 : fd_fork_t * pool; /* memory pool of fd_fork_t */ 44 : }; 45 : typedef struct fd_forks fd_forks_t; 46 : 47 : /* fd_forks_{align,footprint} return the required alignment and 48 : footprint of a memory region suitable for use as forks with up to max 49 : fork heads in the frontier. */ 50 : 51 : FD_FN_CONST static inline ulong 52 0 : fd_forks_align( void ) { 53 0 : return alignof( fd_forks_t ); 54 0 : } 55 : 56 : FD_FN_CONST static inline ulong 57 0 : fd_forks_footprint( ulong max ) { 58 0 : return FD_LAYOUT_FINI( 59 0 : FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, 60 0 : alignof( fd_forks_t ), 61 0 : sizeof( fd_forks_t ) ), 62 0 : fd_fork_pool_align(), 63 0 : fd_fork_pool_footprint( max ) ), 64 0 : fd_fork_frontier_align(), 65 0 : fd_fork_frontier_footprint( max ) ), 66 0 : alignof( fd_forks_t ) ); 67 0 : } 68 : 69 : /* fd_forks_new formats an unused memory region for use as a forks. mem 70 : is a non-NULL pointer to this region in the local address space with 71 : the required footprint and alignment. */ 72 : 73 : void * 74 : fd_forks_new( void * shmem, ulong max, ulong seed ); 75 : 76 : /* fd_forks_join joins the caller to the forks. forks points to the 77 : first byte of the memory region backing the forks in the caller's 78 : address space. 79 : 80 : Returns a pointer in the local address space to forks on success. */ 81 : 82 : fd_forks_t * 83 : fd_forks_join( void * forks ); 84 : 85 : /* fd_forks_leave leaves a current local join. Returns a pointer to the 86 : underlying shared memory region on success and NULL on failure (logs 87 : details). Reasons for failure include forks is NULL. */ 88 : 89 : void * 90 : fd_forks_leave( fd_forks_t const * forks ); 91 : 92 : /* fd_forks_delete unformats a memory region used as a forks. Assumes 93 : only the local process is joined to the region. Returns a pointer to 94 : the underlying shared memory region or NULL if used obviously in 95 : error (e.g. forks is obviously not a forks ... logs details). The 96 : ownership of the memory region is transferred to the caller. */ 97 : 98 : void * 99 : fd_forks_delete( void * forks ); 100 : 101 : /* fd_forks_init initializes forks. Assumes forks is a valid local join 102 : and no one else is joined, and non-NULL slot_ctx. Inserts the first 103 : fork into the frontier containing slot_ctx. This should be the 104 : slot_ctx from loading a snapshot, restoring a bank from Funk, or the 105 : genesis slot_ctx. The slot_ctx will be copied into an element 106 : acquired from the memory pool owned by forks. Returns fork on 107 : success, NULL on failure. 108 : 109 : In general, this should be called by the same process that formatted 110 : forks' memory, ie. the caller of fd_forks_new. */ 111 : 112 : fd_fork_t * 113 : fd_forks_init( fd_forks_t * forks, fd_exec_slot_ctx_t const * slot_ctx ); 114 : 115 : /* fd_forks_query queries for the fork corresponding to slot in the 116 : frontier. Returns the fork if found, otherwise NULL. */ 117 : 118 : fd_fork_t * 119 : fd_forks_query( fd_forks_t * forks, ulong slot ); 120 : 121 : /* fd_forks_query_const is the const version of the above. */ 122 : 123 : fd_fork_t const * 124 : fd_forks_query_const( fd_forks_t const * forks, ulong slot ); 125 : 126 : /* fd_forks_advance advances a parent_slot to slot in the frontier. 127 : Assumes parent_slot corresponds to a fork currently in the frontier 128 : (ie. has already been prepared), slot is a child of parent_slot, and 129 : parent_slot has already been replayed. Fails if fork is not frozen. 130 : Returns the updated fork on success, NULL on failure. */ 131 : 132 : fd_fork_t * 133 : fd_forks_advance( fd_forks_t const * forks, fd_fork_t * fork, ulong slot ); 134 : 135 : /* fd_forks_prepare prepares a fork for execution. The fork will either 136 : be an existing fork in the frontier if parent_slot is already a fork 137 : head or it will start a new fork at parent_slot and add it to the 138 : frontier. 139 : 140 : Returns fork on success, NULL on failure. Failure reasons include 141 : parent_slot is not present in the blockstore, is not present in funk, 142 : or does not have a valid ancestry. 143 : 144 : It is possible for the fork to return NULL in a non-error condition. 145 : For example, a leader tries to rollback and start a new fork from a 146 : very old slot that the blockstore has already pruned. In this 147 : scenario, we cannot prepare a new fork at parent_slot because we have 148 : already rooted past it. */ 149 : 150 : fd_fork_t * 151 : fd_forks_prepare( fd_forks_t const * forks, 152 : ulong parent_slot, 153 : fd_acc_mgr_t * acc_mgr, 154 : fd_blockstore_t * blockstore, 155 : fd_exec_epoch_ctx_t * epoch_ctx, 156 : fd_funk_t * funk, 157 : fd_valloc_t valloc ); 158 : 159 : /* fd_forks_publish publishes a new root into forks. Assumes root is a 160 : valid slot that exists in the cluster and has already been replayed. 161 : This prunes all the existing forks in the frontier except descendants 162 : of root. Forks that are not frozen will also not be pruned (warns 163 : when handholding is enabled). */ 164 : 165 : void 166 : fd_forks_publish( fd_forks_t * fork, ulong root, fd_ghost_t const * ghost ); 167 : 168 : /* fd_forks_print prints a forks as a list of the frontiers and number 169 : of forks (pool eles acquired). */ 170 : 171 : static inline void 172 0 : fd_forks_print( fd_forks_t const * forks ) { 173 0 : FD_LOG_NOTICE( ( "\n\n[Frontier]" ) ); 174 0 : for( fd_fork_frontier_iter_t iter = fd_fork_frontier_iter_init( forks->frontier, forks->pool ); 175 0 : !fd_fork_frontier_iter_done( iter, forks->frontier, forks->pool ); 176 0 : iter = fd_fork_frontier_iter_next( iter, forks->frontier, forks->pool ) ) { 177 0 : printf( "%lu\n", fd_fork_frontier_iter_ele_const( iter, forks->frontier, forks->pool )->slot ); 178 0 : } 179 0 : printf( "\n" ); 180 0 : } 181 : 182 : #endif /* HEADER_fd_src_choreo_forks_fd_forks_h */