LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_reclaim.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 68 73 93.2 %
Date: 2026-04-01 06:30:45 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "fd_progcache_reclaim.h"
       2             : #include "fd_progcache_clock.h"
       3             : #include "fd_progcache_user.h"
       4             : #include "../../util/racesan/fd_racesan_target.h"
       5             : 
       6             : void
       7             : fd_prog_reclaim_enqueue( fd_progcache_join_t * join,
       8          51 :                          fd_progcache_rec_t *  rec ) {
       9          51 :   uint idx = (uint)( rec - join->rec.pool->ele );
      10          51 :   ulong rec_max = fd_prog_recp_ele_max( join->rec.pool );
      11          51 :   if( FD_UNLIKELY( (ulong)idx >= rec_max ) )
      12           0 :     FD_LOG_CRIT(( "progcache: corruption detected (reclaim_enqueue rec_idx=%u rec_max=%lu)", idx, rec_max ));
      13          51 :   rec->reclaim_next = join->rec.reclaim_head;
      14          51 :   join->rec.reclaim_head = idx;
      15          51 : }
      16             : 
      17             : static _Bool
      18             : rec_reclaim( fd_progcache_join_t * join,
      19          57 :              fd_progcache_rec_t *  rec ) {
      20             : 
      21             :   /* Remove the record from a transaction */
      22             : 
      23          57 :   ulong txn_max = fd_prog_txnp_max( join->txn.pool );
      24          57 :   uint txn_idx = atomic_load_explicit( &rec->txn_idx, memory_order_acquire );
      25          57 :   if( txn_idx!=UINT_MAX ) {
      26           3 :     if( FD_UNLIKELY( (ulong)txn_idx >= txn_max ) )
      27           0 :       FD_LOG_CRIT(( "progcache: corruption detected (rec_reclaim txn_idx=%u txn_max=%lu)", txn_idx, txn_max ));
      28           3 :     fd_progcache_txn_t * txn = &join->txn.pool[ txn_idx ];
      29           3 :     fd_rwlock_write( &txn->lock );
      30           3 :     fd_racesan_hook( "prog_reclaim:pre_cas" );
      31           3 :     if( atomic_compare_exchange_strong_explicit( &rec->txn_idx, &txn_idx, UINT_MAX, memory_order_acq_rel, memory_order_acquire ) ) {
      32             :       /* A transaction may not be deallocated before all records are
      33             :          unlinked. */
      34           3 :       fd_progcache_rec_unlink( join->rec.pool->ele, rec, txn, join->rec.pool->ele_max );
      35           3 :     } else {
      36             :       /* Strong CAS failure implies that another thread is already
      37             :          unlinking the record (the rooting logic) */
      38           0 :       FD_CRIT( atomic_load_explicit( &rec->txn_idx, memory_order_relaxed )==UINT_MAX, "concurrency violation" );
      39           0 :     }
      40           3 :     fd_rwlock_unwrite( &txn->lock );
      41           3 :   }
      42          57 :   fd_racesan_hook( "prog_reclaim:post_unlink" );
      43             : 
      44             :   /* Drain existing users
      45             : 
      46             :      Records are removed from recm (index) before the record is selected
      47             :      for reclamation.  Therefore, it is not necessary to acquire a lock.
      48             :      It is fine to wait for existing users to drain. */
      49             : 
      50          57 :   if( FD_UNLIKELY( FD_VOLATILE_CONST( rec->lock.value ) ) ) return 0;
      51             : 
      52             :   /* All users are gone, deallocate record */
      53             : 
      54          51 :   rec->reclaim_next = UINT_MAX;
      55          51 :   fd_progcache_val_free( rec, join );
      56          51 :   rec->exists = 0;
      57          51 :   fd_prog_clock_remove( join->clock.bits, (ulong)( rec - join->rec.pool->ele ) );
      58          51 :   fd_prog_recp_release( join->rec.pool, rec, 1 );
      59          51 :   return 1;
      60          57 : }
      61             : 
      62             : ulong
      63         198 : fd_prog_reclaim_work( fd_progcache_join_t * join ) {
      64         198 :   ulong  rec_max = fd_prog_recp_ele_max( join->rec.pool );
      65         198 :   ulong  cnt     = 0UL;
      66         198 :   uint * prev_p  = &join->rec.reclaim_head;
      67         198 :   uint   cur     = join->rec.reclaim_head;
      68         255 :   while( cur!=UINT_MAX ) {
      69          57 :     if( FD_UNLIKELY( (ulong)cur >= rec_max ) )
      70           0 :       FD_LOG_CRIT(( "progcache: corruption detected (reclaim_work rec_idx=%u rec_max=%lu)", cur, rec_max ));
      71          57 :     fd_progcache_rec_t * rec = &join->rec.pool->ele[ cur ];
      72          57 :     uint next = rec->reclaim_next;
      73          57 :     if( rec_reclaim( join, rec ) ) {
      74          51 :       *prev_p = next;
      75          51 :       cnt++;
      76          51 :     } else {
      77           6 :       prev_p = &rec->reclaim_next;
      78           6 :     }
      79          57 :     cur = next;
      80          57 :   }
      81         198 :   return cnt;
      82         198 : }
      83             : 
      84             : long
      85             : fd_prog_delete_rec( fd_progcache_join_t * cache,
      86          48 :                     fd_progcache_rec_t *  rec ) {
      87          48 :   if( !rec ) return -1L;
      88          48 :   fd_prog_recm_query_t query[1];
      89          48 :   int rm_err = fd_prog_recm_remove( cache->rec.map, &rec->pair, NULL, query, FD_MAP_FLAG_BLOCKING );
      90          48 :   if( rm_err==FD_MAP_ERR_KEY ) return -1L;
      91          45 :   if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_prog_recm_remove failed: %i-%s", rm_err, fd_map_strerror( rm_err ) ));
      92          45 :   if( FD_UNLIKELY( query->ele!=rec ) ) FD_LOG_CRIT(( "record collision (rec=%p found=%p)", (void *)rec, (void *)query->ele ));
      93          45 :   fd_prog_reclaim_enqueue( cache, rec );
      94          45 :   return (long)rec->data_max;
      95          45 : }
      96             : 
      97             : long
      98             : fd_prog_delete_rec_by_key( fd_progcache_join_t *          cache,
      99             :                            fd_funk_xid_key_pair_t const * key,
     100           9 :                            _Bool                          lock ) {
     101           9 :   fd_prog_recm_query_t query[1];
     102           9 :   int rm_err;
     103           9 :   if( lock ) rm_err = fd_prog_recm_remove    ( cache->rec.map, key, NULL, query, FD_MAP_FLAG_BLOCKING );
     104           9 :   else       rm_err = fd_prog_recm_txn_remove( cache->rec.map, key, NULL, query, 0                    );
     105           9 :   if( rm_err==FD_MAP_ERR_KEY ) return -1L;
     106           6 :   if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_prog_recm_remove failed: %i-%s", rm_err, fd_map_strerror( rm_err ) ));
     107           6 :   fd_prog_reclaim_enqueue( cache, query->ele );
     108           6 :   return (long)query->ele->data_max;
     109           6 : }

Generated by: LCOV version 1.14