LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp_user.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 281 328 85.7 %
Date: 2025-01-08 12:08:44 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    40404438 :                               fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
      30             : 
      31    40404438 :   ulong g3 = pinfo[ i2 ].gaddr_hi;                               /* Old end here */
      32    40404438 :   ulong g2 = g3 - s2;                                            /* New ends here */
      33    40404438 :   ulong g1 = pinfo[ i2 ].gaddr_lo;                               /* New starts here */
      34             : 
      35    40404438 :   ulong i0 = fd_wksp_private_pinfo_idx( pinfo[ i2 ].prev_cidx ); /* Old before */
      36    40404438 :   ulong i1 = fd_wksp_private_idle_stack_pop( wksp, pinfo );      /* New before */
      37             : 
      38    40404438 :   pinfo[ i1 ].gaddr_lo    = g1;
      39    40404438 :   pinfo[ i1 ].gaddr_hi    = g2;
      40    40404438 :   pinfo[ i1 ].tag         = 0UL;
      41    40404438 :   pinfo[ i1 ].in_same     = 0U;
      42    40404438 :   pinfo[ i1 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i0 );
      43    40404438 :   pinfo[ i1 ].next_cidx   = fd_wksp_private_pinfo_cidx( i2 );
      44    40404438 :   pinfo[ i1 ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      45    40404438 :   pinfo[ i1 ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      46    40404438 :   pinfo[ i1 ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      47    40404438 :   pinfo[ i1 ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      48             : 
      49    40404438 :   pinfo[ i2 ].gaddr_lo    = g2;
      50    40404438 :   pinfo[ i2 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i1 );
      51             : 
      52    40404438 :   if( fd_wksp_private_pinfo_idx_is_null( i0 ) ) wksp->part_head_cidx  = fd_wksp_private_pinfo_cidx( i1 );
      53    40355997 :   else                                          pinfo[ i0 ].next_cidx = fd_wksp_private_pinfo_cidx( i1 );
      54             : 
      55    40404438 :   return i1;
      56    40404438 : }
      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    76287627 :                              fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
      63             : 
      64    76287627 :   ulong g1 = pinfo[ i1 ].gaddr_lo;                               /* Old starts here */
      65    76287627 :   ulong g2 = g1 + s1;                                            /* New starts here */
      66    76287627 :   ulong g3 = pinfo[ i1 ].gaddr_hi;                               /* New end here */
      67             : 
      68    76287627 :   ulong i2 = fd_wksp_private_idle_stack_pop( wksp, pinfo );      /* New before */
      69    76287627 :   ulong i3 = fd_wksp_private_pinfo_idx( pinfo[ i1 ].next_cidx ); /* Old after */
      70             : 
      71    76287627 :   pinfo[ i2 ].gaddr_lo    = g2;
      72    76287627 :   pinfo[ i2 ].gaddr_hi    = g3;
      73    76287627 :   pinfo[ i2 ].tag         = 0UL;
      74    76287627 :   pinfo[ i2 ].in_same     = 0U;
      75    76287627 :   pinfo[ i2 ].prev_cidx   = fd_wksp_private_pinfo_cidx( i1 );
      76    76287627 :   pinfo[ i2 ].next_cidx   = fd_wksp_private_pinfo_cidx( i3 );
      77    76287627 :   pinfo[ i2 ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      78    76287627 :   pinfo[ i2 ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      79    76287627 :   pinfo[ i2 ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      80    76287627 :   pinfo[ i2 ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      81             : 
      82    76287627 :   pinfo[ i1 ].gaddr_hi    = g2;
      83    76287627 :   pinfo[ i1 ].next_cidx   = fd_wksp_private_pinfo_cidx( i2 );
      84             : 
      85    76287627 :   if( fd_wksp_private_pinfo_idx_is_null( i3 ) ) wksp->part_tail_cidx  = fd_wksp_private_pinfo_cidx( i2 );
      86    65383167 :   else                                          pinfo[ i3 ].prev_cidx = fd_wksp_private_pinfo_cidx( i2 );
      87             : 
      88    76287627 :   return i2;
      89    76287627 : }
      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    55840467 :                               fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     107             : 
     108    55840467 :   ulong i0 = fd_wksp_private_pinfo_idx( pinfo[ i1 ].prev_cidx ); /* Partition before that (if any) */
     109             : 
     110    55840467 :   pinfo[ i2 ].gaddr_lo  = pinfo[ i1 ].gaddr_lo;
     111    55840467 :   pinfo[ i2 ].prev_cidx = fd_wksp_private_pinfo_cidx( i0 );
     112             : 
     113    55840467 :   if( fd_wksp_private_pinfo_idx_is_null( i0 ) ) wksp->part_head_cidx  = fd_wksp_private_pinfo_cidx( i2 );
     114    54322263 :   else                                          pinfo[ i0 ].next_cidx = fd_wksp_private_pinfo_cidx( i2 );
     115             : 
     116    55840467 :   fd_wksp_private_idle_stack_push( i1, wksp, pinfo );
     117    55840467 : }
     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    60833319 :                              fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     124             : 
     125    60833319 :   ulong i3 = fd_wksp_private_pinfo_idx( pinfo[ i2 ].next_cidx ); /* Partition after that (if any) */
     126             : 
     127    60833319 :   pinfo[ i1 ].gaddr_hi  = pinfo[ i2 ].gaddr_hi;
     128    60833319 :   pinfo[ i1 ].next_cidx = fd_wksp_private_pinfo_cidx( i3 );
     129             : 
     130    60833319 :   if( fd_wksp_private_pinfo_idx_is_null( i3 ) ) wksp->part_tail_cidx  = fd_wksp_private_pinfo_cidx( i1 );
     131    53667135 :   else                                          pinfo[ i3 ].prev_cidx = fd_wksp_private_pinfo_cidx( i1 );
     132             : 
     133    60833319 :   fd_wksp_private_idle_stack_push( i2, wksp, pinfo );
     134    60833319 : }
     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    79597617 :                       fd_wksp_private_pinfo_t * pinfo ) { /* == fd_wksp_private_pinfo( wksp ) */
     140             : 
     141    79597617 :   ulong part_max = wksp->part_max;
     142             : 
     143             :   /* Officially free i */
     144             : 
     145    79597617 :   FD_COMPILER_MFENCE();
     146    79597617 :   FD_VOLATILE( pinfo[ i ].tag ) = 0UL;
     147    79597617 :   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    79597617 :   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    79597617 :   ulong p = fd_wksp_private_pinfo_idx( pinfo[ i ].prev_cidx );
     159    79597617 :   if( FD_LIKELY( p<part_max ) && !pinfo[ p ].tag ) {
     160    55840467 :     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    55840467 :     fd_wksp_private_merge_before( p, i, wksp, pinfo );
     165    55840467 :   }
     166             : 
     167    79597617 :   ulong n = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     168    79597617 :   if( FD_LIKELY( n<part_max ) && !pinfo[ n ].tag ) {
     169    60833319 :     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    60833319 :     fd_wksp_private_merge_after( i, n, wksp, pinfo );
     174    60833319 :   }
     175             : 
     176    79597617 :   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    79597617 : }
     186             : 
     187             : /* user APIs **********************************************************/
     188             : 
     189             : void *
     190             : fd_wksp_laddr( fd_wksp_t const * wksp,
     191     3146934 :                ulong             gaddr ) {
     192     3146934 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return NULL; }
     193             : 
     194     3146919 :   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     3146904 :   if( FD_UNLIKELY( !((wksp->gaddr_lo<=gaddr) & (gaddr<=wksp->gaddr_hi)) ) ) { FD_LOG_WARNING(( "bad gaddr" )); return NULL; }
     202             : 
     203     3146898 :   return fd_wksp_laddr_fast( wksp, gaddr );
     204     3146904 : }
     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    80603808 :                         ulong *     _hi ) {
     229    80603808 :   align = fd_ulong_if( !align, FD_WKSP_ALIGN_DEFAULT, align );
     230    80603808 :   ulong footprint = sz + align - 1UL;
     231             : 
     232    80603808 :   if( FD_UNLIKELY( !sz                        ) ) goto fail; /* silent */
     233    80603784 :   if( FD_UNLIKELY( !wksp                      ) ) { FD_LOG_WARNING(( "NULL wksp"   )); goto fail; }
     234    80603775 :   if( FD_UNLIKELY( !fd_ulong_is_pow2( align ) ) ) { FD_LOG_WARNING(( "bad align"   )); goto fail; }
     235    80603757 :   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    80603739 :   if( FD_UNLIKELY( footprint < sz             ) ) { FD_LOG_WARNING(( "sz overflow" )); goto fail; }
     249             : 
     250    80603733 :   fd_wksp_private_pinfo_t * pinfo = fd_wksp_private_pinfo( wksp );
     251             : 
     252    80603733 :   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    80603733 :   ulong i = fd_wksp_private_free_treap_query( footprint, wksp, pinfo );
     264    80603733 :   if( FD_UNLIKELY( fd_wksp_private_pinfo_idx_is_null( i ) ) ) {
     265          12 :     fd_wksp_private_unlock( wksp );
     266          12 :     FD_LOG_WARNING(( "no free space available in workspace %s with data size %lu", wksp->name, wksp->data_max ));
     267          12 :     goto fail;
     268          12 :   }
     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    80603721 :   if( !fd_wksp_private_free_treap_same_is_empty( i, wksp, pinfo ) ) i = fd_wksp_private_free_treap_same_remove( i, wksp, pinfo );
     274    76998993 :   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.  We check before we trim that there are enough
     284             :      idle partitions available to complete the request (this improves
     285             :      checkpointing as all allocated partitions will be reasonably
     286             :      tight). */
     287             : 
     288    80603721 :   ulong lo = pinfo[ i ].gaddr_lo;
     289    80603721 :   ulong hi = pinfo[ i ].gaddr_hi;
     290             : 
     291    80603721 :   ulong r0 = fd_ulong_align_up( lo, align );
     292    80603721 :   ulong r1 = r0 + sz;
     293             : 
     294    80603721 :   ulong part_max = wksp->part_max;
     295    80603721 :   ulong idle_idx = fd_wksp_private_pinfo_idx( wksp->idle_top_cidx );
     296   197630127 :   for( int idle_rem = (r0>lo) + (r1<hi); idle_rem; idle_rem-- ) {
     297   118021725 :     if( FD_UNLIKELY( idle_idx >= part_max ) ) {
     298      995319 :       if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( i, wksp, pinfo ) ) ) { /* Could eliminate this with additional surgery */
     299           0 :         fd_wksp_private_unlock( wksp );
     300           0 :         FD_LOG_WARNING(( "corrupt wksp detected" ));
     301           0 :         goto fail;
     302           0 :       }
     303      995319 :       fd_wksp_private_unlock( wksp );
     304      995319 :       FD_LOG_WARNING(( "too few partitions available for allocation (part_max %lu)", part_max ));
     305      995319 :       goto fail;
     306      995319 :     }
     307   117026406 :     idle_idx = fd_wksp_private_pinfo_idx( pinfo[ idle_idx ].parent_cidx );
     308   117026406 :   }
     309             : 
     310    79608402 :   if( FD_UNLIKELY( r0>lo ) ) { /* opt for reasonable alignments */
     311    40404438 :     ulong j = fd_wksp_private_split_before( i, hi-r0, wksp, pinfo );
     312    40404438 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( j, wksp, pinfo ) ) ) {
     313           0 :       fd_wksp_private_unlock( wksp );
     314           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     315           0 :       goto fail;
     316           0 :     }
     317    40404438 :     lo = r0;
     318    40404438 :   }
     319             : 
     320    79608402 :   if( FD_LIKELY( r1<hi ) ) { /* opt for splitting a final large partition */
     321    76287627 :     ulong j = fd_wksp_private_split_after( i, sz, wksp, pinfo );
     322    76287627 :     if( FD_UNLIKELY( fd_wksp_private_free_treap_insert( j, wksp, pinfo ) ) ) {
     323           0 :       fd_wksp_private_unlock( wksp );
     324           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     325           0 :       goto fail;
     326           0 :     }
     327    76287627 :     hi = r1;
     328    76287627 :   }
     329             : 
     330    79608402 :   if( FD_UNLIKELY( fd_wksp_private_used_treap_insert( i, wksp, pinfo ) ) ) {
     331           0 :     fd_wksp_private_unlock( wksp );
     332           0 :     FD_LOG_WARNING(( "corrupt wksp detected" ));
     333           0 :     goto fail;
     334           0 :   }
     335             : 
     336             :   /* At this point, i is unofficially allocated.  It is okay if we get
     337             :      killed at any point above as the next wksp user to try to lock the
     338             :      wksp will detect that we died in the middle of an operation,
     339             :      potentially leaving the partitioning, idle stack, used treap and/or
     340             :      free treap might be in an inconsistent state and thus proceed to
     341             :      rebuild them.  We now update the tag in the array to make the
     342             :      allocation official. */
     343             : 
     344    79608402 :   FD_COMPILER_MFENCE();
     345    79608402 :   FD_VOLATILE( pinfo[ i ].tag ) = tag;
     346    79608402 :   FD_COMPILER_MFENCE();
     347             : 
     348             : # if FD_HAS_DEEPASAN
     349             :   /* Unpoison the data region of the allocation */
     350             :   fd_asan_unpoison( fd_wksp_laddr_fast( wksp, lo ), hi - lo );
     351             : # endif
     352             : 
     353    79608402 :   fd_wksp_private_unlock( wksp );
     354    79608402 :   *_lo = lo;
     355    79608402 :   *_hi = hi;
     356    79608402 :   return r0;
     357             : 
     358      995406 : fail:
     359      995406 :   *_lo = 0UL;
     360      995406 :   *_hi = 0UL;
     361      995406 :   return 0UL;
     362    79608402 : }
     363             : 
     364             : void
     365             : fd_wksp_free( fd_wksp_t * wksp,
     366    79593567 :               ulong       gaddr ) {
     367    79593567 :   if( FD_UNLIKELY( !gaddr ) ) return;
     368             : 
     369    79593555 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     370             : 
     371    79593552 :   ulong                     part_max = wksp->part_max;
     372    79593552 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     373             : 
     374    79593552 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     375             : 
     376    79593552 :   ulong i = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     377    79593552 :   if( FD_UNLIKELY( i<part_max ) ) fd_wksp_private_free( i, wksp, pinfo ); /* logs details */
     378             : 
     379    79593552 :   fd_wksp_private_unlock( wksp );
     380             : 
     381    79593552 :   if( FD_UNLIKELY( i>=part_max && i!=FD_WKSP_PRIVATE_PINFO_IDX_NULL ) ) {
     382           0 :     FD_LOG_WARNING(( "gaddr does not appear to be a current wksp allocation" ));
     383           0 :   }
     384    79593552 : }
     385             : 
     386             : ulong
     387             : fd_wksp_tag( fd_wksp_t * wksp,
     388   353384034 :              ulong       gaddr ) {
     389   353384034 :   if( FD_UNLIKELY( !wksp ) ) return 0UL;
     390             : 
     391   353384031 :   ulong                     part_max = wksp->part_max;
     392   353384031 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     393             : 
     394   353384031 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return 0UL; /* logs details */
     395             : 
     396   353384031 :   ulong i   = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     397   353384031 :   ulong tag = FD_LIKELY( i<part_max ) ? pinfo[ i ].tag : 0UL;
     398             : 
     399   353384031 :   fd_wksp_private_unlock( wksp );
     400             : 
     401   353384031 :   return tag;
     402   353384031 : }
     403             : 
     404             : ulong
     405             : fd_wksp_tag_query( fd_wksp_t *                wksp,
     406             :                    ulong const *              tag,
     407             :                    ulong                      tag_cnt,
     408             :                    fd_wksp_tag_query_info_t * info,
     409         690 :                    ulong                      info_max ) {
     410             : 
     411         690 :   if( FD_UNLIKELY( !tag_cnt ) ) return 0UL; /* No tags to query */
     412             : 
     413         564 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return 0UL; }
     414         561 :   if( FD_UNLIKELY( !tag  ) ) { FD_LOG_WARNING(( "bad tag" ));   return 0UL; }
     415             : 
     416         558 :   if( FD_UNLIKELY( (!!info_max) & (!info) ) ) { FD_LOG_WARNING(( "NULL info" )); return 0UL; }
     417             : 
     418         555 :   ulong                     part_max = wksp->part_max;
     419         555 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     420             : 
     421         555 :   ulong info_cnt = 0UL;
     422             : 
     423         555 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return 0UL; /* logs details */
     424             : 
     425         555 :   ulong cycle_tag = wksp->cycle_tag++;
     426             : 
     427         555 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     428       28521 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     429       27966 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     430           0 :       fd_wksp_private_unlock( wksp );
     431           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     432           0 :       return 0UL;
     433           0 :     }
     434       27966 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     435             : 
     436       27966 :     ulong _tag = pinfo[ i ].tag;
     437       64953 :     for( ulong tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) { /* TODO: USE BETTER MATCHER */
     438       41100 :       if( tag[ tag_idx ]==_tag ) {
     439        4113 :         if( FD_LIKELY( info_cnt<info_max ) ) {
     440          12 :           info[ info_cnt ].gaddr_lo = pinfo[ i ].gaddr_lo;
     441          12 :           info[ info_cnt ].gaddr_hi = pinfo[ i ].gaddr_hi;
     442          12 :           info[ info_cnt ].tag      = pinfo[ i ].tag;
     443          12 :         }
     444        4113 :         info_cnt++;
     445        4113 :         break;
     446        4113 :       }
     447       41100 :     }
     448             : 
     449       27966 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     450       27966 :   }
     451             : 
     452         555 :   fd_wksp_private_unlock( wksp );
     453         555 :   return info_cnt;
     454         555 : }
     455             : 
     456             : void
     457             : fd_wksp_tag_free( fd_wksp_t *   wksp,
     458             :                   ulong const * tag,
     459         393 :                   ulong         tag_cnt ) {
     460         393 :   if( FD_UNLIKELY( !tag_cnt ) ) return; /* No tags to free */
     461             : 
     462         327 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     463         324 :   if( FD_UNLIKELY( !tag  ) ) { FD_LOG_WARNING(( "bad tag" ));   return; }
     464             : 
     465         321 :   ulong                     part_max = wksp->part_max;
     466         321 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     467             : 
     468         321 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     469             : 
     470             :   /* Push matching used partitions onto a stack */
     471             : 
     472         321 :   ulong top = FD_WKSP_PRIVATE_PINFO_IDX_NULL;
     473             : 
     474         321 :   ulong cycle_tag = wksp->cycle_tag++;
     475             : 
     476         321 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     477       17613 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     478       17292 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     479           0 :       fd_wksp_private_unlock( wksp );
     480           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     481           0 :       return;
     482           0 :     }
     483       17292 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     484             : 
     485       17292 :     ulong _tag = pinfo[ i ].tag;
     486       17292 :     if( _tag ) { /* TODO: use a more efficient matcher */
     487       19806 :       ulong tag_idx; for( tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) if( tag[ tag_idx ]==_tag ) break;
     488        9888 :       if( tag_idx<tag_cnt ) {
     489        4104 :         pinfo[ i ].stack_cidx = fd_wksp_private_pinfo_cidx( top );
     490        4104 :         top = i;
     491        4104 :       }
     492        9888 :     }
     493       17292 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     494       17292 :   }
     495             : 
     496             :   /* Free partitions on the stack */
     497             : 
     498        4425 :   while( !fd_wksp_private_pinfo_idx_is_null( top ) ) {
     499        4104 :     i   = top;
     500        4104 :     top = fd_wksp_private_pinfo_idx( pinfo[ i ].stack_cidx );
     501        4104 :     fd_wksp_private_free( i, wksp, pinfo );
     502        4104 :   }
     503             : 
     504         321 :   fd_wksp_private_unlock( wksp );
     505         321 : }
     506             : 
     507             : void
     508             : fd_wksp_memset( fd_wksp_t * wksp,
     509             :                 ulong       gaddr,
     510    73978992 :                 int         c ) {
     511    73978992 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     512             : 
     513    73978989 :   ulong                     part_max = wksp->part_max;
     514    73978989 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     515             : 
     516    73978989 :   int err;
     517             : 
     518    73978989 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     519             : 
     520    73978989 :   ulong i = fd_wksp_private_used_treap_query( gaddr, wksp, pinfo );
     521    73978989 :   if( FD_UNLIKELY( i>=part_max ) ) err = 1;
     522    73978974 :   else {
     523    73978974 :     fd_memset( fd_wksp_laddr_fast( wksp, pinfo[ i ].gaddr_lo ), c, fd_wksp_private_pinfo_sz( pinfo + i ) );
     524    73978974 :     err = 0;
     525    73978974 :   }
     526             : 
     527    73978989 :   fd_wksp_private_unlock( wksp );
     528             : 
     529    73978989 :   if( FD_UNLIKELY( err ) ) FD_LOG_WARNING(( "gaddr does not seem to point to a current wksp allocation" ));
     530    73978989 : }
     531             : 
     532             : void
     533             : fd_wksp_reset( fd_wksp_t * wksp,
     534         339 :                uint        seed ) {
     535         339 :   if( FD_UNLIKELY( !wksp ) ) { FD_LOG_WARNING(( "NULL wksp" )); return; }
     536             : 
     537             : # if FD_HAS_DEEPASAN
     538             :   /* Poison entire workspace except wksp header and the pinfo array. */
     539             :   ulong footprint = fd_wksp_footprint( wksp->part_max, wksp->data_max );
     540             :   void * wksp_data = (void*)((ulong)wksp + fd_wksp_private_pinfo_off());
     541             :   fd_asan_poison( wksp_data, footprint - fd_wksp_private_pinfo_off() );
     542             :   fd_wksp_private_pinfo_t * pinfo_arr = fd_wksp_private_pinfo( wksp );
     543             :   for( ulong i=0; i<wksp->part_max; i++ ) {
     544             :     fd_asan_unpoison( &pinfo_arr[ i ], FD_WKSP_PRIVATE_PINFO_FOOTPRINT );
     545             :   }
     546             : # endif
     547             : 
     548         336 :   ulong                     part_max = wksp->part_max;
     549         336 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     550             : 
     551         336 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) return; /* logs details */
     552             : 
     553      822288 :   for( ulong i=0; i<part_max; i++ ) pinfo[ i ].tag = 0UL;
     554         336 :   int err = fd_wksp_rebuild( wksp, seed );
     555             : 
     556         336 :   fd_wksp_private_unlock( wksp );
     557             : 
     558         336 :   if( FD_UNLIKELY( err ) ) FD_LOG_WARNING(( "corrupt wksp detected" ));
     559         336 : }
     560             : 
     561             : fd_wksp_usage_t *
     562             : fd_wksp_usage( fd_wksp_t *       wksp,
     563             :                ulong const *     tag,
     564             :                ulong             tag_cnt,
     565      414636 :                fd_wksp_usage_t * usage ) {
     566             : 
     567             :   /* Check input args */
     568             : 
     569      414636 :   if( FD_UNLIKELY( !usage ) ) { FD_LOG_WARNING(( "bad usage" )); return usage; }
     570             : 
     571      414633 :   fd_memset( usage, 0, sizeof(fd_wksp_usage_t) );
     572             : 
     573      414633 :   if( FD_UNLIKELY( !wksp                ) ) { FD_LOG_WARNING(( "bad wksp" )); return usage; }
     574      414630 :   if( FD_UNLIKELY( (!tag) & (!!tag_cnt) ) ) { FD_LOG_WARNING(( "bad tag" ));  return usage; }
     575             : 
     576      414627 :   ulong                     part_max = wksp->part_max;
     577      414627 :   fd_wksp_private_pinfo_t * pinfo    = fd_wksp_private_pinfo( wksp );
     578             : 
     579      414627 :   if( FD_UNLIKELY( fd_wksp_private_lock( wksp ) ) ) { FD_LOG_WARNING(( "fd_wksp_private_lock failed" )); return usage; }
     580             : 
     581             :   /* Push matching used partitions onto a stack */
     582             : 
     583      414627 :   usage->total_max = part_max;
     584             : 
     585      414627 :   ulong cycle_tag = wksp->cycle_tag++;
     586             : 
     587      414627 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
     588     1918251 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     589     1503624 :     if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) {
     590           0 :       fd_wksp_private_unlock( wksp );
     591           0 :       FD_LOG_WARNING(( "corrupt wksp detected" ));
     592           0 :       fd_memset( usage, 0, sizeof(fd_wksp_usage_t) );
     593           0 :       return usage;
     594           0 :     }
     595     1503624 :     pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
     596             : 
     597     1503624 :     ulong part_sz  = fd_wksp_private_pinfo_sz( pinfo + i );
     598     1503624 :     ulong part_tag = pinfo[ i ].tag;
     599             : 
     600             :     /* TODO: use a more efficient matcher */
     601     3676848 :     ulong tag_idx; for( tag_idx=0UL; tag_idx<tag_cnt; tag_idx++ ) if( tag[ tag_idx ]==part_tag ) break;
     602             : 
     603     1503624 :     int is_free = !part_tag;
     604     1503624 :     int is_used = tag_idx<tag_cnt;
     605             : 
     606     1503624 :     usage->total_cnt += 1UL;            usage->total_sz +=                       part_sz;
     607     1503624 :     usage->free_cnt  += (ulong)is_free; usage->free_sz  += fd_ulong_if( is_free, part_sz, 0UL );
     608     1503624 :     usage->used_cnt  += (ulong)is_used; usage->used_sz  += fd_ulong_if( is_used, part_sz, 0UL );
     609             : 
     610     1503624 :     i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
     611     1503624 :   }
     612             : 
     613      414627 :   fd_wksp_private_unlock( wksp );
     614      414627 :   return usage;
     615      414627 : }

Generated by: LCOV version 1.14