Line data Source code
1 : #include "fd_accdb_admin.h"
2 :
3 : fd_accdb_admin_t *
4 : fd_accdb_admin_join( fd_accdb_admin_t * ljoin,
5 63 : void * shfunk ) {
6 63 : if( FD_UNLIKELY( !ljoin ) ) {
7 0 : FD_LOG_WARNING(( "NULL ljoin" ));
8 0 : return NULL;
9 0 : }
10 63 : if( FD_UNLIKELY( !shfunk ) ) {
11 0 : FD_LOG_WARNING(( "NULL shfunk" ));
12 0 : return NULL;
13 0 : }
14 :
15 63 : memset( ljoin, 0, sizeof(fd_accdb_admin_t) );
16 63 : if( FD_UNLIKELY( !fd_funk_join( ljoin->funk, shfunk ) ) ) {
17 0 : FD_LOG_CRIT(( "fd_funk_join failed" ));
18 0 : }
19 :
20 63 : return ljoin;
21 63 : }
22 :
23 : void *
24 : fd_accdb_admin_leave( fd_accdb_admin_t * admin,
25 60 : void ** opt_shfunk ) {
26 60 : if( FD_UNLIKELY( !admin ) ) FD_LOG_CRIT(( "NULL ljoin" ));
27 :
28 60 : if( FD_UNLIKELY( !fd_funk_leave( admin->funk, opt_shfunk ) ) ) FD_LOG_CRIT(( "fd_funk_leave failed" ));
29 :
30 60 : return admin;
31 60 : }
32 :
33 : /* Begin transaction-level operations. It is assumed that funk_txn data
34 : structures are not concurrently modified. This includes txn_pool and
35 : txn_map. */
36 :
37 : void
38 : fd_accdb_attach_child( fd_accdb_admin_t * db,
39 : fd_funk_txn_xid_t const * xid_parent,
40 571857 : fd_funk_txn_xid_t const * xid_new ) {
41 571857 : FD_LOG_INFO(( "accdb txn xid %lu:%lu: created with parent %lu:%lu",
42 571857 : xid_new ->ul[0], xid_new ->ul[1],
43 571857 : xid_parent->ul[0], xid_parent->ul[1] ));
44 571857 : fd_funk_txn_prepare( db->funk, xid_parent, xid_new );
45 571857 : }
46 :
47 : static void
48 : fd_accdb_txn_cancel_one( fd_accdb_admin_t * admin,
49 347094 : fd_funk_txn_t * txn ) {
50 347094 : FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: cancel", (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
51 :
52 347094 : if( FD_UNLIKELY( txn->state!=FD_FUNK_TXN_STATE_ACTIVE ) ) {
53 0 : FD_LOG_CRIT(( "cannot cancel xid %lu:%lu: unxpected state %u-%s",
54 0 : txn->xid.ul[0], txn->xid.ul[1],
55 0 : txn->state, fd_funk_txn_state_str( txn->state ) ));
56 0 : }
57 347094 : fd_funk_t * funk = admin->funk;
58 347094 : if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( txn->child_head_cidx ) ||
59 347094 : !fd_funk_txn_idx_is_null( txn->child_tail_cidx ) ) ) {
60 0 : FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: txn at %p with xid %lu:%lu has children (data corruption?)",
61 0 : (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
62 0 : }
63 :
64 : /* Phase 1: Drain users from transaction */
65 :
66 347094 : fd_rwlock_write( txn->lock );
67 347094 : FD_COMPILER_MFENCE();
68 347094 : FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_CANCEL;
69 :
70 : /* Phase 2: Detach all records */
71 :
72 347094 : FD_COMPILER_MFENCE();
73 347094 : uint const rec_head_idx = txn->rec_head_idx;
74 347094 : txn->rec_head_idx = FD_FUNK_REC_IDX_NULL;
75 347094 : txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
76 347094 : FD_COMPILER_MFENCE();
77 :
78 : /* Phase 3: Remove records */
79 :
80 347094 : ulong rec_cnt = 0UL;
81 347094 : uint rec_idx = rec_head_idx;
82 1030707 : while( !fd_funk_rec_idx_is_null( rec_idx ) ) {
83 683613 : fd_funk_rec_t * rec = &funk->rec_pool->ele[ rec_idx ];
84 683613 : fd_funk_xid_key_pair_t pair = FD_VOLATILE_CONST( rec->pair );
85 :
86 683613 : uint next_idx = rec->next_idx;
87 683613 : if( FD_UNLIKELY( !fd_funk_txn_xid_eq( pair.xid, &txn->xid ) ) ) {
88 0 : FD_LOG_CRIT(( "Record does not belong to txn being cancelled (data corruption?): rec_idx=%u", rec_idx ));
89 0 : }
90 :
91 : /* Phase 3.1: Hide record */
92 :
93 683613 : fd_funk_rec_query_t query[1];
94 683613 : int remove_err = fd_funk_rec_map_remove( funk->rec_map, &pair, NULL, query, FD_MAP_FLAG_BLOCKING );
95 683613 : if( FD_UNLIKELY( remove_err ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed: %i-%s", remove_err, fd_map_strerror( remove_err ) ));
96 683613 : if( FD_UNLIKELY( query->ele!=rec ) ) FD_LOG_CRIT(( "Found duplicate record in map idx[0]=%p idx[1]=%p", (void *)query->ele, (void *)rec ));
97 :
98 : /* Phase 3.2: Mark record as invalid */
99 :
100 683613 : FD_COMPILER_MFENCE();
101 683613 : memset( &rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
102 683613 : FD_COMPILER_MFENCE();
103 :
104 : /* Phase 3.3: Free record */
105 :
106 683613 : fd_funk_val_flush( rec, funk->alloc, funk->wksp );
107 683613 : rec->next_idx = FD_FUNK_REC_IDX_NULL;
108 683613 : rec->prev_idx = FD_FUNK_REC_IDX_NULL;
109 683613 : fd_funk_rec_pool_release( funk->rec_pool, rec, 1 );
110 683613 : rec_idx = next_idx;
111 683613 : rec_cnt++;
112 683613 : }
113 347094 : admin->metrics.revert_cnt += rec_cnt;
114 347094 : FD_LOG_INFO(( "accdb freed %lu records while cancelling txn %lu:%lu",
115 347094 : rec_cnt, txn->xid.ul[0], txn->xid.ul[1] ));
116 :
117 : /* Phase 4: Remove transaction from fork graph */
118 :
119 347094 : uint self_cidx = fd_funk_txn_cidx( (ulong)( txn-funk->txn_pool->ele ) );
120 347094 : uint prev_cidx = txn->sibling_prev_cidx; ulong prev_idx = fd_funk_txn_idx( prev_cidx );
121 347094 : uint next_cidx = txn->sibling_next_cidx; ulong next_idx = fd_funk_txn_idx( next_cidx );
122 347094 : if( !fd_funk_txn_idx_is_null( next_idx ) ) {
123 156813 : funk->txn_pool->ele[ next_idx ].sibling_prev_cidx = prev_cidx;
124 156813 : }
125 347094 : if( !fd_funk_txn_idx_is_null( prev_idx ) ) {
126 109587 : funk->txn_pool->ele[ prev_idx ].sibling_next_cidx = next_cidx;
127 109587 : }
128 347094 : if( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) {
129 169809 : fd_funk_txn_t * parent = &funk->txn_pool->ele[ fd_funk_txn_idx( txn->parent_cidx ) ];
130 169809 : if( parent->child_head_cidx==self_cidx ) parent->child_head_cidx = next_cidx;
131 169809 : if( parent->child_tail_cidx==self_cidx ) parent->child_tail_cidx = prev_cidx;
132 177285 : } else {
133 177285 : if( funk->shmem->child_head_cidx==self_cidx ) funk->shmem->child_head_cidx = next_cidx;
134 177285 : if( funk->shmem->child_tail_cidx==self_cidx ) funk->shmem->child_tail_cidx = prev_cidx;
135 177285 : }
136 :
137 : /* Phase 5: Remove transcation from index */
138 :
139 347094 : fd_funk_txn_map_query_t query[1];
140 347094 : int remove_err = fd_funk_txn_map_remove( funk->txn_map, &txn->xid, NULL, query, FD_MAP_FLAG_BLOCKING );
141 347094 : if( FD_UNLIKELY( remove_err!=FD_MAP_SUCCESS ) ) {
142 0 : FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: fd_funk_txn_map_remove(%lu:%lu) failed: %i-%s",
143 0 : txn->xid.ul[0], txn->xid.ul[1], remove_err, fd_map_strerror( remove_err ) ));
144 0 : }
145 :
146 : /* Phase 6: Free transaction object */
147 :
148 347094 : txn->parent_cidx = UINT_MAX;
149 347094 : txn->sibling_prev_cidx = UINT_MAX;
150 347094 : txn->sibling_next_cidx = UINT_MAX;
151 347094 : fd_rwlock_unwrite( txn->lock );
152 347094 : FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_FREE;
153 347094 : fd_funk_txn_pool_release( funk->txn_pool, txn, 1 );
154 347094 : }
155 :
156 : /* Cancels txn and all children */
157 :
158 : static void
159 : fd_accdb_txn_cancel_tree( fd_accdb_admin_t * accdb,
160 347094 : fd_funk_txn_t * txn ) {
161 516891 : for(;;) {
162 516891 : ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
163 516891 : if( fd_funk_txn_idx_is_null( child_idx ) ) break;
164 169797 : fd_funk_txn_t * child = &accdb->funk->txn_pool->ele[ child_idx ];
165 169797 : fd_accdb_txn_cancel_tree( accdb, child );
166 169797 : }
167 347094 : fd_accdb_txn_cancel_one( accdb, txn );
168 347094 : }
169 :
170 : /* Cancels all left/right siblings */
171 :
172 : static void
173 : fd_accdb_txn_cancel_prev_list( fd_accdb_admin_t * accdb,
174 224739 : fd_funk_txn_t * txn ) {
175 224739 : ulong self_idx = (ulong)( txn - accdb->funk->txn_pool->ele );
176 313806 : for(;;) {
177 313806 : ulong prev_idx = fd_funk_txn_idx( txn->sibling_prev_cidx );
178 313806 : if( FD_UNLIKELY( prev_idx==self_idx ) ) FD_LOG_CRIT(( "detected cycle in fork graph" ));
179 313806 : if( fd_funk_txn_idx_is_null( prev_idx ) ) break;
180 89067 : fd_funk_txn_t * sibling = &accdb->funk->txn_pool->ele[ prev_idx ];
181 89067 : fd_accdb_txn_cancel_tree( accdb, sibling );
182 89067 : }
183 224739 : }
184 :
185 : static void
186 : fd_accdb_txn_cancel_next_list( fd_accdb_admin_t * accdb,
187 224781 : fd_funk_txn_t * txn ) {
188 224781 : ulong self_idx = (ulong)( txn - accdb->funk->txn_pool->ele );
189 312969 : for(;;) {
190 312969 : ulong next_idx = fd_funk_txn_idx( txn->sibling_next_cidx );
191 312969 : if( FD_UNLIKELY( next_idx==self_idx ) ) FD_LOG_CRIT(( "detected cycle in fork graph" ));
192 312969 : if( fd_funk_txn_idx_is_null( next_idx ) ) break;
193 88188 : fd_funk_txn_t * sibling = &accdb->funk->txn_pool->ele[ next_idx ];
194 88188 : fd_accdb_txn_cancel_tree( accdb, sibling );
195 88188 : }
196 224781 : }
197 :
198 : void
199 : fd_accdb_cancel( fd_accdb_admin_t * accdb,
200 42 : fd_funk_txn_xid_t const * xid ) {
201 42 : fd_funk_t * funk = accdb->funk;
202 :
203 42 : fd_funk_txn_t * txn = fd_funk_txn_query( xid, funk->txn_map );
204 42 : if( FD_UNLIKELY( !txn ) ) {
205 0 : FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: txn with xid %lu:%lu not found", xid->ul[0], xid->ul[1] ));
206 0 : }
207 :
208 42 : fd_accdb_txn_cancel_next_list( accdb, txn );
209 42 : fd_accdb_txn_cancel_tree( accdb, txn );
210 42 : }
211 :
212 : /* fd_accdb_chain_gc_root cleans up a stale "rooted" version of a
213 : record. */
214 :
215 : static void
216 : fd_accdb_chain_gc_root( fd_accdb_admin_t * accdb,
217 593448 : fd_funk_xid_key_pair_t const * pair ) {
218 593448 : fd_funk_t * funk = accdb->funk;
219 :
220 : /* Phase 1: Remove record from map if found */
221 :
222 593448 : fd_funk_rec_query_t query[1];
223 593448 : int rm_err = fd_funk_rec_map_remove( funk->rec_map, pair, NULL, query, FD_MAP_FLAG_BLOCKING );
224 593448 : if( rm_err==FD_MAP_ERR_KEY ) return;
225 593220 : if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed: %i-%s", rm_err, fd_map_strerror( rm_err ) ));
226 :
227 : /* Phase 2: Invalidate record */
228 :
229 593220 : fd_funk_rec_t * old_rec = query->ele;
230 593220 : memset( &old_rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
231 593220 : FD_COMPILER_MFENCE();
232 :
233 : /* Phase 3: Free record */
234 :
235 593220 : old_rec->map_next = FD_FUNK_REC_IDX_NULL;
236 593220 : fd_funk_val_flush( old_rec, funk->alloc, funk->wksp );
237 593220 : fd_funk_rec_pool_release( funk->rec_pool, old_rec, 1 );
238 593220 : accdb->metrics.gc_root_cnt++;
239 593220 : }
240 :
241 : /* fd_accdb_publish_recs moves all records in a transaction to the DB
242 : root. Currently, the DB root is stored by funk, which might change
243 : in the future.
244 :
245 : It is assumed at this point that the txn has no more concurrent
246 : users. */
247 :
248 : static void
249 : fd_accdb_publish_recs( fd_accdb_admin_t * accdb,
250 224739 : fd_funk_txn_t * txn ) {
251 : /* Iterate record list */
252 224739 : uint head = txn->rec_head_idx;
253 224739 : txn->rec_head_idx = FD_FUNK_REC_IDX_NULL;
254 224739 : txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
255 818187 : while( !fd_funk_rec_idx_is_null( head ) ) {
256 593448 : fd_funk_rec_t * rec = &accdb->funk->rec_pool->ele[ head ];
257 :
258 : /* Evict previous value from hash chain */
259 593448 : fd_funk_xid_key_pair_t pair[1];
260 593448 : fd_funk_rec_key_copy( pair->key, rec->pair.key );
261 593448 : fd_funk_txn_xid_set_root( pair->xid );
262 593448 : fd_accdb_chain_gc_root( accdb, pair );
263 :
264 : /* Migrate record to root */
265 593448 : uint next = rec->next_idx;
266 593448 : rec->prev_idx = FD_FUNK_REC_IDX_NULL;
267 593448 : rec->next_idx = FD_FUNK_REC_IDX_NULL;
268 593448 : fd_funk_txn_xid_t const root = { .ul = { ULONG_MAX, ULONG_MAX } };
269 593448 : fd_funk_txn_xid_st_atomic( rec->pair.xid, &root );
270 593448 : accdb->metrics.root_cnt++;
271 :
272 593448 : head = next; /* next record */
273 593448 : }
274 224739 : }
275 :
276 : /* fd_accdb_txn_publish_one merges an in-prep transaction whose
277 : parent is the last published, into the parent. */
278 :
279 : static void
280 : fd_accdb_txn_publish_one( fd_accdb_admin_t * accdb,
281 224739 : fd_funk_txn_t * txn ) {
282 224739 : fd_funk_t * funk = accdb->funk;
283 :
284 : /* Phase 1: Mark transaction as "last published" */
285 :
286 224739 : fd_funk_txn_xid_t xid[1]; fd_funk_txn_xid_copy( xid, fd_funk_txn_xid( txn ) );
287 224739 : if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) ) {
288 0 : FD_LOG_CRIT(( "fd_accdb_publish failed: txn with xid %lu:%lu is not a child of the last published txn", xid->ul[0], xid->ul[1] ));
289 0 : }
290 224739 : fd_funk_txn_xid_st_atomic( funk->shmem->last_publish, xid );
291 224739 : FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: publish", (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
292 :
293 : /* Phase 2: Drain users from transaction */
294 :
295 224739 : fd_rwlock_write( txn->lock );
296 224739 : FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_PUBLISH;
297 :
298 : /* Phase 3: Migrate records */
299 :
300 224739 : fd_accdb_publish_recs( accdb, txn );
301 :
302 : /* Phase 4: Remove transaction from fork graph
303 :
304 : Because the transaction has no more records, removing it from the
305 : fork graph has no visible side effects to concurrent query ops
306 : (always return "no found") or insert ops (refuse to write to a
307 : "publish" state txn). */
308 :
309 224739 : { /* Adjust the parent pointers of the children to point to "last published" */
310 224739 : ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
311 372294 : while( FD_UNLIKELY( !fd_funk_txn_idx_is_null( child_idx ) ) ) {
312 147555 : funk->txn_pool->ele[ child_idx ].parent_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
313 147555 : child_idx = fd_funk_txn_idx( funk->txn_pool->ele[ child_idx ].sibling_next_cidx );
314 147555 : }
315 224739 : }
316 :
317 : /* Phase 5: Remove transaction from index
318 :
319 : The transaction is now an orphan and won't get any new records. */
320 :
321 224739 : fd_funk_txn_map_query_t query[1];
322 224739 : int remove_err = fd_funk_txn_map_remove( funk->txn_map, xid, NULL, query, 0 );
323 224739 : if( FD_UNLIKELY( remove_err!=FD_MAP_SUCCESS ) ) {
324 0 : FD_LOG_CRIT(( "fd_accdb_publish failed: fd_funk_txn_map_remove failed: %i-%s", remove_err, fd_map_strerror( remove_err ) ));
325 0 : }
326 :
327 : /* Phase 6: Free transaction object */
328 :
329 224739 : fd_rwlock_unwrite( txn->lock );
330 224739 : FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_FREE;
331 224739 : txn->parent_cidx = UINT_MAX;
332 224739 : txn->sibling_prev_cidx = UINT_MAX;
333 224739 : txn->sibling_next_cidx = UINT_MAX;
334 224739 : txn->child_head_cidx = UINT_MAX;
335 224739 : txn->child_tail_cidx = UINT_MAX;
336 224739 : fd_funk_txn_pool_release( funk->txn_pool, txn, 1 );
337 224739 : }
338 :
339 : void
340 : fd_accdb_advance_root( fd_accdb_admin_t * accdb,
341 224739 : fd_funk_txn_xid_t const * xid ) {
342 224739 : fd_funk_t * funk = accdb->funk;
343 :
344 224739 : fd_funk_txn_t * txn = fd_funk_txn_query( xid, funk->txn_map );
345 224739 : if( FD_UNLIKELY( !txn ) ) {
346 0 : FD_LOG_CRIT(( "fd_accdb_txn_advance_root failed: txn with xid %lu:%lu not found", xid->ul[0], xid->ul[1] ));
347 0 : }
348 :
349 224739 : if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) ) {
350 0 : FD_LOG_CRIT(( "fd_accdb_txn_advance_root: parent of txn %lu:%lu is not root", xid->ul[0], xid->ul[1] ));
351 0 : }
352 :
353 224739 : FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: advancing root",
354 224739 : (void *)txn,
355 224739 : xid->ul[0], xid->ul[1] ));
356 :
357 224739 : fd_accdb_txn_cancel_prev_list( accdb, txn );
358 224739 : fd_accdb_txn_cancel_next_list( accdb, txn );
359 224739 : txn->sibling_prev_cidx = UINT_MAX;
360 224739 : txn->sibling_next_cidx = UINT_MAX;
361 :
362 : /* Children of transaction are now children of root */
363 224739 : funk->shmem->child_head_cidx = txn->child_head_cidx;
364 224739 : funk->shmem->child_tail_cidx = txn->child_tail_cidx;
365 :
366 224739 : fd_accdb_txn_publish_one( accdb, txn );
367 224739 : }
368 :
369 : /* reset_rec_map frees all records in a funk instance. */
370 :
371 : static void
372 15 : reset_rec_map( fd_funk_t * funk ) {
373 15 : fd_wksp_t * wksp = funk->wksp;
374 15 : fd_alloc_t * alloc = funk->alloc;
375 15 : fd_funk_rec_map_t * rec_map = funk->rec_map;
376 15 : fd_funk_rec_pool_t * rec_pool = funk->rec_pool;
377 :
378 15 : ulong chain_cnt = fd_funk_rec_map_chain_cnt( rec_map );
379 975 : for( ulong chain_idx=0UL; chain_idx<chain_cnt; chain_idx++ ) {
380 960 : for(
381 960 : fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter( rec_map, chain_idx );
382 1203 : !fd_funk_rec_map_iter_done( iter );
383 960 : ) {
384 243 : fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( iter );
385 243 : ulong next = fd_funk_rec_map_private_idx( rec->map_next );;
386 :
387 : /* Remove rec object from map */
388 243 : fd_funk_rec_map_query_t rec_query[1];
389 243 : int err = fd_funk_rec_map_remove( rec_map, fd_funk_rec_pair( rec ), NULL, rec_query, FD_MAP_FLAG_BLOCKING );
390 243 : fd_funk_rec_key_t key; fd_funk_rec_key_copy( &key, rec->pair.key );
391 243 : if( FD_UNLIKELY( err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed (%i-%s)", err, fd_map_strerror( err ) ));
392 :
393 : /* Free rec resources */
394 243 : rec->map_next = FD_FUNK_REC_IDX_NULL;
395 243 : rec->next_idx = FD_FUNK_REC_IDX_NULL;
396 243 : rec->prev_idx = FD_FUNK_REC_IDX_NULL;
397 243 : memset( &rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
398 243 : fd_funk_val_flush( rec, alloc, wksp );
399 243 : fd_funk_rec_pool_release( rec_pool, rec, 1 );
400 243 : iter.ele_idx = next;
401 243 : }
402 960 : }
403 15 : }
404 :
405 : /* clear_txn_list does a depth-first traversal of the txn tree.
406 : Removes all txns. */
407 :
408 : static void
409 : clear_txn_list( fd_funk_t * funk,
410 27 : ulong txn_head_idx ) {
411 27 : fd_funk_txn_pool_t * txn_pool = funk->txn_pool;
412 27 : fd_funk_txn_map_t * txn_map = funk->txn_map;
413 27 : for( ulong idx = txn_head_idx;
414 39 : !fd_funk_txn_idx_is_null( idx );
415 27 : ) {
416 12 : fd_funk_txn_t * txn = &txn_pool->ele[ idx ];
417 12 : fd_funk_txn_state_assert( txn, FD_FUNK_TXN_STATE_ACTIVE );
418 12 : ulong next_idx = fd_funk_txn_idx( txn->sibling_next_cidx );
419 12 : ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
420 12 : txn->rec_head_idx = FD_FUNK_REC_IDX_NULL;
421 12 : txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
422 12 : txn->child_head_cidx = UINT_MAX;
423 12 : txn->child_tail_cidx = UINT_MAX;
424 12 : txn->parent_cidx = UINT_MAX;
425 12 : txn->sibling_prev_cidx = UINT_MAX;
426 12 : txn->sibling_next_cidx = UINT_MAX;
427 12 : clear_txn_list( funk, child_idx );
428 12 : fd_funk_txn_map_query_t query[1];
429 12 : int rm_err = fd_funk_txn_map_remove( txn_map, &txn->xid, NULL, query, FD_MAP_FLAG_BLOCKING );
430 12 : if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_txn_map_remove failed (%i-%s)", rm_err, fd_map_strerror( rm_err ) ));
431 12 : txn->state = FD_FUNK_TXN_STATE_FREE;
432 12 : int free_err = fd_funk_txn_pool_release( txn_pool, txn, 1 );
433 12 : if( FD_UNLIKELY( free_err!=FD_POOL_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_txn_pool_release failed (%i)", free_err ));
434 12 : idx = next_idx;
435 12 : }
436 27 : funk->shmem->child_head_cidx = UINT_MAX;
437 27 : funk->shmem->child_tail_cidx = UINT_MAX;
438 27 : }
439 :
440 : void
441 15 : fd_accdb_clear( fd_accdb_admin_t * cache ) {
442 15 : fd_funk_t * funk = cache->funk;
443 15 : clear_txn_list( funk, fd_funk_txn_idx( funk->shmem->child_head_cidx ) );
444 15 : reset_rec_map( funk );
445 15 : }
446 :
447 : void
448 198 : fd_accdb_verify( fd_accdb_admin_t * admin ) {
449 198 : FD_TEST( fd_funk_verify( admin->funk )==FD_FUNK_SUCCESS );
450 198 : }
|