LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp_user.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 273 315 86.7 %
Date: 2024-11-13 11:58:15 Functions: 15 15 100.0 %

          Line data    Source code
       1             : #include "fd_wksp_private.h"
       2             : 
       3             : /* fd_wksp_private_split_before splits a partition (index i2) into two
       4             :    smaller partitions and returns the partition index (i1) of the
       5             :    partition created by the split.  The created partition will be
       6             :    immediately before the original partition.  It will be in the
       7             :    partitioning with a zero tag.  It will not be in the idle stack, used
       8             :    treap or free treap.
       9             : 
      10             :    sz is size of the original partition post split.  This should be in
      11             :    (0,original_sz) (yes, open on both ends such that the post split
      12             :    partitions both have non-zero size.
      13             : 
      14             :    This will pop the idle stack once to assign the index of the newly
      15             :    created partition.  Assumes the caller knows the idle stack is not
      16             :    empty.
      17             : 
      18             :    Assumes the original partition is in the partitioning with a zero
      19             :    tag.  Further assumes the original partition is not in the idle
      20             :    stack, used treap or free treap.
      21             : 
      22             :    fd_wksp_private_split_after is identical except the partition created
      23             :    by the split is after the original partition. */
      24             : 
      25             : static ulong                                                      /* In [0,part_max) */
      26             : fd_wksp_private_split_before( ulong                     i2,       /* In [0,part_max) */
      27             :                               ulong                     s2,       /* In (0,size of i2) */
      28             :                               fd_wksp_t *               wksp,     /* Current local join */
      29    39068409 :                               fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
      30             : 
      31    39068409 :   ulong g3 = pinfo[ i2 ].gaddr_hi;                               /* Old end here */
      32    39068409 :   ulong g2 = g3 - s2;                                            /* New ends here */
      33    39068409 :   ulong g1 = pinfo[ i2 ].gaddr_lo;                               /* New starts here */
      34             : 
      35    39068409 :   ulong i0 = fd_wksp_private_pinfo_idx( pinfo[ i2 ].prev_cidx ); /* Old before */
      36    39068409 :   ulong i1 = fd_wksp_private_idle_stack_pop( wksp, pinfo );      /* New before */
      37             : 
      38    39068409 :   pinfo[ i1 ].gaddr_lo    = g1;
      39    39068409 :   pinfo[ i1 ].gaddr_hi    = g2;
      40    39068409 :   pinfo[ i1 ].tag         = 0UL;
      41    39068409 :   pinfo[ i1 ].in_same     = 0U;
      42    39068409 :   pinfo[ i1 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i0 );
      43    39068409 :   pinfo[ i1 ].next_cidx   = fd_wksp_private_pinfo_cidx( i2 );
      44    39068409 :   pinfo[ i1 ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      45    39068409 :   pinfo[ i1 ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      46    39068409 :   pinfo[ i1 ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      47    39068409 :   pinfo[ i1 ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      48             : 
      49    39068409 :   pinfo[ i2 ].gaddr_lo    = g2;
      50    39068409 :   pinfo[ i2 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i1 );
      51             : 
      52    39068409 :   if( fd_wksp_private_pinfo_idx_is_null( i0 ) ) wksp->part_head_cidx  = fd_wksp_private_pinfo_cidx( i1 );
      53    39019971 :   else                                          pinfo[ i0 ].next_cidx = fd_wksp_private_pinfo_cidx( i1 );
      54             : 
      55    39068409 :   return i1;
      56    39068409 : }
      57             : 
      58             : static ulong                                                     /* In [0,part_max) */
      59             : fd_wksp_private_split_after( ulong                     i1,       /* In [0,part_max) */
      60             :                              ulong                     s1,       /* In (0,size of i2) */
      61             :                              fd_wksp_t *               wksp,     /* Current local join */
      62    73623378 :                              fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
      63             : 
      64    73623378 :   ulong g1 = pinfo[ i1 ].gaddr_lo;                               /* Old starts here */
      65    73623378 :   ulong g2 = g1 + s1;                                            /* New starts here */
      66    73623378 :   ulong g3 = pinfo[ i1 ].gaddr_hi;                               /* New end here */
      67             : 
      68    73623378 :   ulong i2 = fd_wksp_private_idle_stack_pop( wksp, pinfo );      /* New before */
      69    73623378 :   ulong i3 = fd_wksp_private_pinfo_idx( pinfo[ i1 ].next_cidx ); /* Old after */
      70             : 
      71    73623378 :   pinfo[ i2 ].gaddr_lo    = g2;
      72    73623378 :   pinfo[ i2 ].gaddr_hi    = g3;
      73    73623378 :   pinfo[ i2 ].tag         = 0UL;
      74    73623378 :   pinfo[ i2 ].in_same     = 0U;
      75    73623378 :   pinfo[ i2 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i1 );
      76    73623378 :   pinfo[ i2 ].next_cidx   = fd_wksp_private_pinfo_cidx( i3 );
      77    73623378 :   pinfo[ i2 ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      78    73623378 :   pinfo[ i2 ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      79    73623378 :   pinfo[ i2 ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      80    73623378 :   pinfo[ i2 ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      81             : 
      82    73623378 :   pinfo[ i1 ].gaddr_hi    = g2;
      83    73623378 :   pinfo[ i1 ].next_cidx   = fd_wksp_private_pinfo_cidx( i2 );
      84             : 
      85    73623378 :   if( fd_wksp_private_pinfo_idx_is_null( i3 ) ) wksp->part_tail_cidx  = fd_wksp_private_pinfo_cidx( i2 );
      86    64396965 :   else                                          pinfo[ i3 ].prev_cidx = fd_wksp_private_pinfo_cidx( i2 );
      87             : 
      88    73623378 :   return i2;
      89    73623378 : }
      90             : 
      91             : /* fd_wksp_private_merge_before i1 into i2 where i1 is the partition
      92             :    immediately preceding i2.  Assumes that i2 and the partition before
      93             :    it are not tagged and not in the idle stack, free treap or used
      94             :    treap.
      95             : 
      96             :    This will push the idle stack once to make the index used for the
      97             :    preceding partition available for future use.
      98             : 
      99             :    fd_wksp_private_merge_after is identical except the partition to
     100             :    merge the split is after the original partition. */
     101             : 
     102             : static void
     103             : fd_wksp_private_merge_before( ulong                     i1,       /* In [0,part_max), == prev to i2, on idle stack on return */
     104             :                               ulong                     i2,       /* In [0,part_max) */
     105             :                               fd_wksp_t *               wksp,     /* Current local join */
     106    54339294 :                               fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     107             : 
     108    54339294 :   ulong i0 = fd_wksp_private_pinfo_idx( pinfo[ i1 ].prev_cidx ); /* Partition before that (if any) */
     109             : 
     110    54339294 :   pinfo[ i2 ].gaddr_lo  = pinfo[ i1 ].gaddr_lo;
     111    54339294 :   pinfo[ i2 ].prev_cidx = fd_wksp_private_pinfo_cidx( i0 );
     112             : 
     113    54339294 :   if( fd_wksp_private_pinfo_idx_is_null( i0 ) ) wksp->part_head_cidx  = fd_wksp_private_pinfo_cidx( i2 );
     114    52903536 :   else                                          pinfo[ i0 ].next_cidx = fd_wksp_private_pinfo_cidx( i2 );
     115             : 
     116    54339294 :   fd_wksp_private_idle_stack_push( i1, wksp, pinfo );
     117    54339294 : }
     118             : 
     119             : static void
     120             : fd_wksp_private_merge_after( ulong                     i1,       /* In [0,part_max) */
     121             :                              ulong                     i2,       /* In [0,part_max), == next to i1, on idle stack on return */
     122             :                              fd_wksp_t *               wksp,     /* Current local join */
     123    58331052 :                              fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     124             : 
     125    58331052 :   ulong i3 = fd_wksp_private_pinfo_idx( pinfo[ i2 ].next_cidx ); /* Partition after that (if any) */
     126             : 
     127    58331052 :   pinfo[ i1 ].gaddr_hi  = pinfo[ i2 ].gaddr_hi;
     128    58331052 :   pinfo[ i1 ].next_cidx = fd_wksp_private_pinfo_cidx( i3 );
     129             : 
     130    58331052 :   if( fd_wksp_private_pinfo_idx_is_null( i3 ) ) wksp->part_tail_cidx  = fd_wksp_private_pinfo_cidx( i1 );
     131    52911111 :   else                                          pinfo[ i3 ].prev_cidx = fd_wksp_private_pinfo_cidx( i1 );
     132             : 
     133    58331052 :   fd_wksp_private_idle_stack_push( i2, wksp, pinfo );
     134    58331052 : }
     135             : 
     136             : static void
     137             : fd_wksp_private_free( ulong                     i,        /* Partition to free, in [0,part_max) */
     138             :                       fd_wksp_t *               wksp,     /* Current local join */
     139    78555402 :                       fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     140             : 
     141    78555402 :   ulong part_max = wksp->part_max;
     142             : 
     143             :   /* Officially free i */
     144             : 
     145    78555402 :   FD_COMPILER_MFENCE();
     146    78555402 :   FD_VOLATILE( pinfo[ i ].tag ) = 0UL;
     147    78555402 :   FD_COMPILER_MFENCE();
     148             : 
     149             :   /* Remove it from various structures.  It is okay if we are killed in
     150             :      this as next person to try to lock the wksp will detect this and
     151             :      rebuild the workspace. */
     152             : 
     153    78555402 :   if( FD_UNLIKELY( fd_wksp_private_used_treap_remove( i, wksp, pinfo ) ) ) {
     154           0 :     FD_LOG_WARNING(( "corrupt wksp detected" ));
     155           0 :     return;
     156           0 :   }
     157             : 
     158    78555402 :   ulong p = fd_wksp_private_pinfo_idx( pinfo[ i ].prev_cidx );
     159    78555402 :   if( FD_LIKELY( p<part_max ) && !pinfo[ p ].tag ) {
     160    54339294 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_remove( p, wksp, pinfo ) ) ) {
     161           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     162           0 :       return;
     163           0 :     }
     164    54339294 :     fd_wksp_private_merge_before( p, i, wksp, pinfo );
     165    54339294 :   }
     166             : 
     167    78555402 :   ulong n = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     168    78555402 :   if( FD_LIKELY( n<part_max ) && !pinfo[ n ].tag ) {
     169    58331052 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_remove( n, wksp, pinfo ) ) ) {
     170           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     171           0 :       return;
     172           0 :     }
     173    58331052 :     fd_wksp_private_merge_after( i, n, wksp, pinfo );
     174    58331052 :   }
     175             : 
     176    78555402 :   if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( i, wksp, pinfo ) ) ) {
     177           0 :     FD_LOG_WARNING(( "corrupt wksp detected" ));
     178           0 :     return;
     179           0 :   }
     180             : 
     181             : # if FD_HAS_DEEPASAN
     182             :   /* Poison the data region of the now freed allocation. */
     183             :   fd_asan_poison( fd_wksp_laddr_fast( wksp, pinfo[ i ].gaddr_lo ), pinfo[ i ].gaddr_hi - pinfo[ i ].gaddr_lo );
     184             : # endif
     185    78555402 : }
     186             : 
     187             : /* user APIs **********************************************************/
     188             : 
     189             : void *
     190             : fd_wksp_laddr( fd_wksp_t const * wksp,
     191     3146865 :                ulong             gaddr ) {
     192     3146865 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return NULL; }
     193             : 
     194     3146850 :   if( !gaddr ) return NULL; /* "NULL" maps to NULL */
     195             : 
     196             :   /* Note: <= used for gaddr_hi below to support mapping ranges of the
     197             :      form [lo,hi) between local and global address spaces with no
     198             :      special handling if allocation put hi at the very end of the
     199             :      workspace. */
     200             : 
     201     3146835 :   if( FD_UNLIKELY( !((wksp->gaddr_lo<=gaddr) & (gaddr<=wksp->gaddr_hi)) ) ) { FD_LOG_WARNING(( "bad gaddr" )); return NULL; }
     202             : 
     203     3146829 :   return fd_wksp_laddr_fast( wksp, gaddr );
     204     3146835 : }
     205             : 
     206             : ulong
     207             : fd_wksp_gaddr( fd_wksp_t const * wksp,
     208     3145758 :                void const *      laddr ) {
     209     3145758 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return 0UL; }
     210             : 
     211     3145743 :   if( !laddr ) return 0UL; /* NULL maps to "NULL" */
     212             : 
     213     3145731 :   ulong gaddr = fd_wksp_gaddr_fast( wksp, laddr );
     214             : 
     215             :   /* See note above about why <= for gaddr_hi */
     216             : 
     217     3145731 :   if( FD_UNLIKELY( !((wksp->gaddr_lo<=gaddr) & (gaddr<=wksp->gaddr_hi)) ) ) { FD_LOG_WARNING(( "bad laddr" )); return 0UL; }
     218             : 
     219     3145725 :   return gaddr;
     220     3145731 : }
     221             : 
     222             : ulong
     223             : fd_wksp_alloc_at_least( fd_wksp_t * wksp,
     224             :                         ulong       align,
     225             :                         ulong       sz,
     226             :                         ulong       tag,
     227             :                         ulong *     _lo,
     228    79494966 :                         ulong *     _hi ) {
     229    79494966 :   align = fd_ulong_if( !align, FD_WKSP_ALIGN_DEFAULT, align );
     230    79494966 :   ulong footprint = sz + align - 1UL;
     231             : 
     232    79494966 :   if( FD_UNLIKELY( !sz                        ) ) goto fail; /* silent */
     233    79494942 :   if( FD_UNLIKELY( !wksp                      ) ) { FD_LOG_WARNING(( "NULL wksp"   )); goto fail; }
     234    79494933 :   if( FD_UNLIKELY( !fd_ulong_is_pow2( align ) ) ) { FD_LOG_WARNING(( "bad align"   )); goto fail; }
     235    79494918 :   if( FD_UNLIKELY( !tag                       ) ) { FD_LOG_WARNING(( "bad tag"     )); goto fail; }
     236             : 
     237             : # if FD_HAS_DEEPASAN
     238             :   /* ASan requires 8 byte alignment for poisoning because memory is mapped in
     239             :      8 byte intervals to ASan shadow bytes. Update alignment, sz, and footprint
     240             :      to meet manual poisoning requirements. */
     241             :   align = fd_ulong_if( align < FD_ASAN_ALIGN, FD_ASAN_ALIGN, align );
     242             :   if( sz && sz < ULONG_MAX ) {
     243             :     sz = fd_ulong_align_up( sz, FD_ASAN_ALIGN );
     244             :   }
     245             :   footprint = sz + align - 1UL;
     246             : # endif
     247             : 
     248    79494903 :   if( FD_UNLIKELY( footprint < sz             ) ) { FD_LOG_WARNING(( "sz overflow" )); goto fail; }
     249             : 
     250    79494900 :   fd_wksp_private_pinfo_t * pinfo = fd_wksp_private_pinfo( wksp );
     251             : 
     252    79494900 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) goto fail; /* logs details */
     253             : 
     254             :   /* Find the smallest free partition size that can handle footprint.
     255             :      Note: it is theoretically possible when there is corruption that a
     256             :      failure to find a suitable partition could be fixed by rebuilding
     257             :      the wksp.  But this should not be common and is expensive and we
     258             :      can't tell if this is a run-of-the-mill allocation failure
     259             :      (insufficient space or too much fragmentation) or an exotic data
     260             :      corruption case.  So we just fail to keep algo cost strict and let
     261             :      the user decide if they want to attempt extreme measures. */
     262             : 
     263    79494900 :   ulong i = fd_wksp_private_free_treap_query( footprint, wksp, pinfo );
     264    79494900 :   if( FD_UNLIKELY( fd_wksp_private_pinfo_idx_is_null( i ) ) ) {
     265      926313 :     fd_wksp_private_unlock( wksp );
     266      926313 :     FD_LOG_WARNING(( "no free space available in workspace %s with data size %lu", wksp->name, wksp->data_max ));
     267      926313 :     goto fail;
     268      926313 :   }
     269             : 
     270             :   /* At this point, i in [0,max), there is at least one suitable
     271             :      partition.  If there is more than one, use one from the same list. */
     272             : 
     273    78568587 :   if( !fd_wksp_private_free_treap_same_is_empty( i, wksp, pinfo ) ) i = fd_wksp_private_free_treap_same_remove( i, wksp, pinfo );
     274    74818248 :   else if( FD_UNLIKELY( fd_wksp_private_free_treap_remove( i, wksp, pinfo ) ) ) {
     275           0 :     fd_wksp_private_unlock( wksp );
     276           0 :     FD_LOG_WARNING(( "corrupt wksp detected" ));
     277           0 :     goto fail;
     278           0 :   }
     279             : 
     280             :   /* At this point, partition i has a zero tag and is not in the idle
     281             :      stack, free treap, or used treap.  Further, it is guaranteed to be
     282             :      large enough to hold the request.  Trim it to fit the request as
     283             :      tightly as possible. */
     284             :   /* TODO: consider failing if can't trim and overallocation >> sz */
     285             : 
     286    78568587 :   ulong lo = pinfo[ i ].gaddr_lo;
     287    78568587 :   ulong hi = pinfo[ i ].gaddr_hi;
     288             : 
     289    78568587 :   ulong r0 = fd_ulong_align_up( lo, align );
     290    78568587 :   ulong r1 = r0 + sz;
     291             : 
     292    78568587 :   if( FD_UNLIKELY( r0>lo ) ) { /* opt for reasonable alignments */
     293    39664086 :     if( FD_UNLIKELY( fd_wksp_private_idle_stack_is_empty( wksp ) ) ) goto trimmed; /* No partitions avail ... use untrimmed */
     294    39068409 :     ulong j = fd_wksp_private_split_before( i, hi-r0, wksp, pinfo );
     295    39068409 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( j, wksp, pinfo ) ) ) {
     296           0 :       fd_wksp_private_unlock( wksp );
     297           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     298           0 :       goto fail;
     299           0 :     }
     300    39068409 :     lo = r0;
     301    39068409 :   }
     302             : 
     303    77972910 :   if( FD_LIKELY( r1<hi ) ) { /* opt for splitting a final large partition */
     304    74587527 :     if( FD_UNLIKELY( fd_wksp_private_idle_stack_is_empty( wksp ) ) ) goto trimmed; /* No partitions avail ... use untrimmed */
     305    73623378 :     ulong j = fd_wksp_private_split_after( i, sz, wksp, pinfo );
     306    73623378 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( j, wksp, pinfo ) ) ) {
     307           0 :       fd_wksp_private_unlock( wksp );
     308           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     309           0 :       goto fail;
     310           0 :     }
     311    73623378 :     hi = r1;
     312    73623378 :   }
     313             : 
     314    78568587 : trimmed:
     315    78568587 :   if( FD_UNLIKELY( fd_wksp_private_used_treap_insert( i, wksp, pinfo ) ) ) {
     316           0 :     fd_wksp_private_unlock( wksp );
     317           0 :     FD_LOG_WARNING(( "corrupt wksp detected" ));
     318           0 :     goto fail;
     319           0 :   }
     320             : 
     321             :   /* At this point, i is unofficially allocated.  It is okay if we get
     322             :      killed at any point above as the next wksp user to try to lock the
     323             :      wksp will detect that we died in the middle of an operation,
     324             :      potentially leaving the partitioning, idle stack, used treap and/or
     325             :      free treap might be in an inconsistent state and thus proceed to
     326             :      rebuild them.  We now update the tag in the array to make the
     327             :      allocation official. */
     328             : 
     329    78568587 :   FD_COMPILER_MFENCE();
     330    78568587 :   FD_VOLATILE( pinfo[ i ].tag ) = tag;
     331    78568587 :   FD_COMPILER_MFENCE();
     332             : 
     333             : # if FD_HAS_DEEPASAN
     334             :   /* Unpoison the data region of the allocation */
     335             :   fd_asan_unpoison( fd_wksp_laddr_fast( wksp, lo ), hi - lo );
     336             : # endif
     337             : 
     338    78568587 :   fd_wksp_private_unlock( wksp );
     339    78568587 :   *_lo = lo;
     340    78568587 :   *_hi = hi;
     341    78568587 :   return r0;
     342             : 
     343      926379 : fail:
     344      926379 :   *_lo = 0UL;
     345      926379 :   *_hi = 0UL;
     346      926379 :   return 0UL;
     347    78568587 : }
     348             : 
     349             : void
     350             : fd_wksp_free( fd_wksp_t * wksp,
     351    78551124 :               ulong       gaddr ) {
     352    78551124 :   if( FD_UNLIKELY( !gaddr ) ) return;
     353             : 
     354    78551112 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     355             : 
     356    78551109 :   ulong                     part_max = wksp->part_max;
     357    78551109 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     358             : 
     359    78551109 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     360             : 
     361    78551109 :   ulong i = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     362    78551109 :   if( FD_UNLIKELY( i<part_max ) ) fd_wksp_private_free( i, wksp, pinfo ); /* logs details */
     363             : 
     364    78551109 :   fd_wksp_private_unlock( wksp );
     365             : 
     366    78551109 :   if( FD_UNLIKELY( i>=part_max && i!=FD_WKSP_PRIVATE_PINFO_IDX_NULL ) ) {
     367           0 :     FD_LOG_WARNING(( "gaddr does not appear to be a current wksp allocation" ));
     368           0 :   }
     369    78551109 : }
     370             : 
     371             : ulong
     372             : fd_wksp_tag( fd_wksp_t * wksp,
     373   332123508 :              ulong       gaddr ) {
     374   332123508 :   if( FD_UNLIKELY( !wksp ) ) return 0UL;
     375             : 
     376   332123505 :   ulong                     part_max = wksp->part_max;
     377   332123505 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     378             : 
     379   332123505 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return 0UL; /* logs details */
     380             : 
     381   332123505 :   ulong i   = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     382   332123505 :   ulong tag = FD_LIKELY( i<part_max ) ? pinfo[ i ].tag : 0UL;
     383             : 
     384   332123505 :   fd_wksp_private_unlock( wksp );
     385             : 
     386   332123505 :   return tag;
     387   332123505 : }
     388             : 
     389             : ulong
     390             : fd_wksp_tag_query( fd_wksp_t *                wksp,
     391             :                    ulong const *              tag,
     392             :                    ulong                      tag_cnt,
     393             :                    fd_wksp_tag_query_info_t * info,
     394         639 :                    ulong                      info_max ) {
     395             : 
     396         639 :   if( FD_UNLIKELY( !tag_cnt ) ) return 0UL; /* No tags to query */
     397             : 
     398         513 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return 0UL; }
     399         510 :   if( FD_UNLIKELY( !tag  ) ) { FD_LOG_WARNING(( "bad tag" ));   return 0UL; }
     400             : 
     401         507 :   if( FD_UNLIKELY( (!!info_max) & (!info) ) ) { FD_LOG_WARNING(( "NULL info" )); return 0UL; }
     402             : 
     403         504 :   ulong                     part_max = wksp->part_max;
     404         504 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     405             : 
     406         504 :   ulong info_cnt = 0UL;
     407             : 
     408         504 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return 0UL; /* logs details */
     409             : 
     410         504 :   ulong cycle_tag = wksp->cycle_tag++;
     411             : 
     412         504 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     413       29067 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     414       28563 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     415           0 :       fd_wksp_private_unlock( wksp );
     416           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     417           0 :       return 0UL;
     418           0 :     }
     419       28563 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     420             : 
     421       28563 :     ulong _tag = pinfo[ i ].tag;
     422       66459 :     for( ulong tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) { /* TODO: USE BETTER MATCHER */
     423       42219 :       if( tag[ tag_idx ]==_tag ) {
     424        4323 :         if( FD_LIKELY( info_cnt<info_max ) ) {
     425          12 :           info[ info_cnt ].gaddr_lo = pinfo[ i ].gaddr_lo;
     426          12 :           info[ info_cnt ].gaddr_hi = pinfo[ i ].gaddr_hi;
     427          12 :           info[ info_cnt ].tag      = pinfo[ i ].tag;
     428          12 :         }
     429        4323 :         info_cnt++;
     430        4323 :         break;
     431        4323 :       }
     432       42219 :     }
     433             : 
     434       28563 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     435       28563 :   }
     436             : 
     437         504 :   fd_wksp_private_unlock( wksp );
     438         504 :   return info_cnt;
     439         504 : }
     440             : 
     441             : void
     442             : fd_wksp_tag_free( fd_wksp_t *   wksp,
     443             :                   ulong const * tag,
     444         336 :                   ulong         tag_cnt ) {
     445         336 :   if( FD_UNLIKELY( !tag_cnt ) ) return; /* No tags to free */
     446             : 
     447         270 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     448         267 :   if( FD_UNLIKELY( !tag  ) ) { FD_LOG_WARNING(( "bad tag" ));   return; }
     449             : 
     450         264 :   ulong                     part_max = wksp->part_max;
     451         264 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     452             : 
     453         264 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     454             : 
     455             :   /* Push matching used partitions onto a stack */
     456             : 
     457         264 :   ulong top = FD_WKSP_PRIVATE_PINFO_IDX_NULL;
     458             : 
     459         264 :   ulong cycle_tag = wksp->cycle_tag++;
     460             : 
     461         264 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     462       17955 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     463       17691 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     464           0 :       fd_wksp_private_unlock( wksp );
     465           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     466           0 :       return;
     467           0 :     }
     468       17691 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     469             : 
     470       17691 :     ulong _tag = pinfo[ i ].tag;
     471       17691 :     if( _tag ) { /* TODO: use a more efficient matcher */
     472       20760 :       ulong tag_idx; for( tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) if( tag[ tag_idx ]==_tag ) break;
     473       10332 :       if( tag_idx<tag_cnt ) {
     474        4314 :         pinfo[ i ].stack_cidx = fd_wksp_private_pinfo_cidx( top );
     475        4314 :         top = i;
     476        4314 :       }
     477       10332 :     }
     478       17691 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     479       17691 :   }
     480             : 
     481             :   /* Free partitions on the stack */
     482             : 
     483        4578 :   while( !fd_wksp_private_pinfo_idx_is_null( top ) ) {
     484        4314 :     i   = top;
     485        4314 :     top = fd_wksp_private_pinfo_idx( pinfo[ i ].stack_cidx );
     486        4314 :     fd_wksp_private_free( i, wksp, pinfo );
     487        4314 :   }
     488             : 
     489         264 :   fd_wksp_private_unlock( wksp );
     490         264 : }
     491             : 
     492             : void
     493             : fd_wksp_memset( fd_wksp_t * wksp,
     494             :                 ulong       gaddr,
     495    74045916 :                 int         c ) {
     496    74045916 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     497             : 
     498    74045913 :   ulong                     part_max = wksp->part_max;
     499    74045913 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     500             : 
     501    74045913 :   int err;
     502             : 
     503    74045913 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     504             : 
     505    74045913 :   ulong i = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     506    74045913 :   if( FD_UNLIKELY( i>=part_max ) ) err = 1;
     507    74045907 :   else {
     508    74045907 :     fd_memset( fd_wksp_laddr_fast( wksp, pinfo[ i ].gaddr_lo ), c, fd_wksp_private_pinfo_sz( pinfo + i ) );
     509    74045907 :     err = 0;
     510    74045907 :   }
     511             : 
     512    74045913 :   fd_wksp_private_unlock( wksp );
     513             : 
     514    74045913 :   if( FD_UNLIKELY( err ) ) FD_LOG_WARNING(( "gaddr does not seem to point to a current wksp allocation" ));
     515    74045913 : }
     516             : 
     517             : void
     518             : fd_wksp_reset( fd_wksp_t * wksp,
     519         300 :                uint        seed ) {
     520         300 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     521             : 
     522             : # if FD_HAS_DEEPASAN
     523             :   /* Poison entire workspace except wksp header and the pinfo array. */
     524             :   ulong footprint = fd_wksp_footprint( wksp->part_max, wksp->data_max );
     525             :   void * wksp_data = (void*)((ulong)wksp + fd_wksp_private_pinfo_off());
     526             :   fd_asan_poison( wksp_data, footprint - fd_wksp_private_pinfo_off() );
     527             :   fd_wksp_private_pinfo_t * pinfo_arr = fd_wksp_private_pinfo( wksp );
     528             :   for( ulong i=0; i<wksp->part_max; i++ ) {
     529             :     fd_asan_unpoison( &pinfo_arr[ i ], FD_WKSP_PRIVATE_PINFO_FOOTPRINT );
     530             :   }
     531             : # endif
     532             : 
     533         297 :   ulong                     part_max = wksp->part_max;
     534         297 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     535             : 
     536         297 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     537             : 
     538      232623 :   for( ulong i=0; i<part_max; i++ ) pinfo[ i ].tag = 0UL;
     539         297 :   int err = fd_wksp_rebuild( wksp, seed );
     540             : 
     541         297 :   fd_wksp_private_unlock( wksp );
     542             : 
     543         297 :   if( FD_UNLIKELY( err ) ) FD_LOG_WARNING(( "corrupt wksp detected" ));
     544         297 : }
     545             : 
     546             : fd_wksp_usage_t *
     547             : fd_wksp_usage( fd_wksp_t *       wksp,
     548             :                ulong const *     tag,
     549             :                ulong             tag_cnt,
     550      116481 :                fd_wksp_usage_t * usage ) {
     551             : 
     552             :   /* Check input args */
     553             : 
     554      116481 :   if( FD_UNLIKELY( !usage ) ) { FD_LOG_WARNING(( "bad usage" )); return usage; }
     555             : 
     556      116478 :   fd_memset( usage, 0, sizeof(fd_wksp_usage_t) );
     557             : 
     558      116478 :   if( FD_UNLIKELY( !wksp                ) ) { FD_LOG_WARNING(( "bad wksp" )); return usage; }
     559      116475 :   if( FD_UNLIKELY( (!tag) & (!!tag_cnt) ) ) { FD_LOG_WARNING(( "bad tag" ));  return usage; }
     560             : 
     561      116472 :   ulong                     part_max = wksp->part_max;
     562      116472 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     563             : 
     564      116472 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) { FD_LOG_WARNING(( "fd_wksp_private_lock failed" )); return usage; }
     565             : 
     566             :   /* Push matching used partitions onto a stack */
     567             : 
     568      116472 :   usage->total_max = part_max;
     569             : 
     570      116472 :   ulong cycle_tag = wksp->cycle_tag++;
     571             : 
     572      116472 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     573     1023555 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     574      907083 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     575           0 :       fd_wksp_private_unlock( wksp );
     576           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     577           0 :       fd_memset( usage, 0, sizeof(fd_wksp_usage_t) );
     578           0 :     }
     579      907083 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     580             : 
     581      907083 :     ulong part_sz  = fd_wksp_private_pinfo_sz( pinfo + i );
     582      907083 :     ulong part_tag = pinfo[ i ].tag;
     583             : 
     584             :     /* TODO: use a more efficient matcher */
     585     2483346 :     ulong tag_idx; for( tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) if( tag[ tag_idx ]==part_tag ) break;
     586             : 
     587      907083 :     int is_free = !part_tag;
     588      907083 :     int is_used = tag_idx<tag_cnt;
     589             : 
     590      907083 :     usage->total_cnt += 1UL;            usage->total_sz +=                       part_sz;
     591      907083 :     usage->free_cnt  += (ulong)is_free; usage->free_sz  += fd_ulong_if( is_free, part_sz, 0UL );
     592      907083 :     usage->used_cnt  += (ulong)is_used; usage->used_sz  += fd_ulong_if( is_used, part_sz, 0UL );
     593             : 
     594      907083 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     595      907083 :   }
     596             : 
     597      116472 :   fd_wksp_private_unlock( wksp );
     598      116472 :   return usage;
     599      116472 : }

Generated by: LCOV version 1.14