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