LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp_used_treap.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 156 157 99.4 %
Date: 2024-11-13 11:58:15 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "fd_wksp_private.h"
       2             : 
       3             : ulong
       4             : fd_wksp_private_used_treap_query( ulong                     gaddr,
       5             :                                   fd_wksp_t *               wksp,
       6   634716498 :                                   fd_wksp_private_pinfo_t * pinfo ) {
       7   634716498 :   if( FD_UNLIKELY( !((wksp->gaddr_lo<=gaddr) & (gaddr<wksp->gaddr_hi)) ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Not in range */
       8             : 
       9   522234312 :   ulong part_max  = wksp->part_max;
      10   522234312 :   ulong cycle_tag = wksp->cycle_tag++;
      11             : 
      12   522234312 :   ulong i = fd_wksp_private_pinfo_idx( wksp->part_used_cidx );
      13  2171561991 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
      14  2108598492 :     if( FD_UNLIKELY( i>=part_max                     ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Bad index */
      15  2108598492 :     if( FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Cycle detected */
      16  2108598492 :     pinfo[ i ].cycle_tag = cycle_tag;                                                           /* Mark i as visited */
      17             : 
      18  2108598492 :     ulong gaddr_lo = pinfo[ i ].gaddr_lo;
      19  2108598492 :     ulong gaddr_hi = pinfo[ i ].gaddr_hi;
      20  2108598492 :     if( gaddr <  gaddr_lo ) { i = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx  ); continue; }
      21  1454997354 :     if( gaddr >= gaddr_hi ) { i = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); continue; }
      22   459270813 :     break;
      23  1454997354 :   }
      24             : 
      25   522234312 :   return i;
      26   522234312 : }
      27             : 
      28  5419044954 : #define TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { /*FD_LOG_WARNING(( "FAIL: %s", #c ));*/ return FD_WKSP_ERR_CORRUPT; } } while(0)
      29             : 
      30  2636430513 : #define TEST_AND_MARK( i ) do {                                                                              \
      31  2636430513 :     ulong _i = (i);                                                                                          \
      32  2636430513 :     TEST( fd_wksp_private_pinfo_idx_is_null( _i ) | ((_i<part_max) && (pinfo[ _i ].cycle_tag!=cycle_tag)) ); \
      33  2636430513 :     if( !fd_wksp_private_pinfo_idx_is_null( _i ) ) pinfo[ _i ].cycle_tag = cycle_tag;                        \
      34  2598916836 :   } while(0)
      35             : 
      36  2444393313 : #define TEST_PARENT( i, p ) do {                                                       \
      37  2444393313 :     ulong _i = (i);                                                                    \
      38  2444393313 :     if( _i<part_max ) TEST( fd_wksp_private_pinfo_idx( pinfo[_i].parent_cidx )==(p) ); \
      39  2444393313 :   } while(0)
      40             : 
      41             : int
      42             : fd_wksp_private_used_treap_insert( ulong                     n,
      43             :                                    fd_wksp_t *               wksp,
      44   153590853 :                                    fd_wksp_private_pinfo_t * pinfo ) {
      45             : 
      46   153590853 :   ulong part_max  = wksp->part_max;
      47   153590853 :   ulong cycle_tag = wksp->cycle_tag++;
      48             : 
      49   153590853 :   TEST( n<part_max );               /* Make sure valid n */
      50   153590853 :   pinfo[ n ].cycle_tag = cycle_tag; /* Mark n */
      51             : 
      52   153590853 :   ulong g0 = pinfo[ n ].gaddr_lo;
      53   153590853 :   ulong g1 = pinfo[ n ].gaddr_hi;
      54             : 
      55   153590853 :   TEST( (wksp->gaddr_lo<=g0) & (g0<g1) & (g1<=wksp->gaddr_hi) ); /* Make sure valid range */
      56             : 
      57             :   /* Note: zero tag is okay temporarily.  We assume the caller will set
      58             :      the tag to non-zero immediately afterward to make the allocation
      59             :      "official". */
      60             : 
      61   153590853 :   uint * _p_child_cidx = &wksp->part_used_cidx;
      62             : 
      63   153590853 :   ulong i = fd_wksp_private_pinfo_idx( *_p_child_cidx ); TEST_AND_MARK( i );
      64             : 
      65             :   /* If an empty treap, make n the root and we are done */
      66             : 
      67   152994624 :   if( FD_UNLIKELY( fd_wksp_private_pinfo_idx_is_null( i ) ) ) { /* Assume lots of used partitions typically */
      68      976902 :     pinfo[ n ].in_same     = 0U;
      69      976902 :     pinfo[ n ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      70      976902 :     pinfo[ n ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      71      976902 :     pinfo[ n ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      72      976902 :     pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
      73      976902 :     *_p_child_cidx = fd_wksp_private_pinfo_cidx( n );
      74      976902 :     return FD_WKSP_SUCCESS;
      75      976902 :   }
      76             : 
      77   152017722 :   TEST_PARENT( i, FD_WKSP_PRIVATE_PINFO_IDX_NULL ); /* Make sure good parent link */
      78             : 
      79             :   /* Find the leaf node where we can insert n */
      80             : 
      81             :   /* TODO: Consider pushing path down onto stack and bubble up
      82             :      using the stack? */
      83             : 
      84   975417252 :   for(;;) {
      85             : 
      86             :     /* At this point, i is a valid marked idx with good parent
      87             :        connectivity.  TODO: Consider validating ranges of visited nodes
      88             :        and tags of visited nodes */
      89             : 
      90             :     /* We need to validate both left and right child links to make the
      91             :        bubble up phase robust (because we do that after we insert). */
      92             : 
      93   975417252 :     ulong l = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx  ); TEST_AND_MARK( l ); TEST_PARENT( l, i );
      94   956574471 :     ulong r = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); TEST_AND_MARK( r ); TEST_PARENT( r, i );
      95             : 
      96   938499804 :     int go_left = (g1 <= pinfo[ i ].gaddr_lo);
      97   938499804 :     if( go_left ) { /* 50/50 unpredictable */
      98   447297780 :       _p_child_cidx = &pinfo[ i ].left_cidx;
      99   447297780 :       if( fd_wksp_private_pinfo_idx_is_null( l ) ) break;
     100   394103103 :       i = l;
     101   394103103 :       continue;
     102   447297780 :     }
     103             : 
     104   491202024 :     int go_right = (g0 >= pinfo[ i ].gaddr_hi);
     105   491202024 :     if( FD_LIKELY( go_right ) ) {
     106   491202024 :       _p_child_cidx = &pinfo[ i ].right_cidx;
     107   491202024 :       if( fd_wksp_private_pinfo_idx_is_null( r ) ) break;
     108   429296427 :       i = r;
     109   429296427 :       continue;
     110   491202024 :     }
     111             : 
     112             :     /* Looks like n overlaps i */
     113             : 
     114           0 :     return FD_WKSP_ERR_CORRUPT;
     115   491202024 :   }
     116             : 
     117             :   /* Make n the appropriate child of i.  This might momentarily break
     118             :      the heap property. */
     119             : 
     120   115100274 :   pinfo[ n ].in_same     = 0U;
     121   115100274 :   pinfo[ n ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     122   115100274 :   pinfo[ n ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     123   115100274 :   pinfo[ n ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     124   115100274 :   pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( i );
     125   115100274 :   *_p_child_cidx         = fd_wksp_private_pinfo_cidx( n );
     126             : 
     127             :   /* Bubble n up until the heap property is restored.  Note that in the
     128             :      traversal above, we also validated parent links for this traversal
     129             :      (so that we could insert without worrying about encountering
     130             :      unpleasantness after we changed the treap). */
     131             : 
     132   312694077 :   while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
     133   307970064 :     uint n_prio = pinfo[ n ].heap_prio;
     134   307970064 :     uint i_prio = pinfo[ i ].heap_prio;
     135   307970064 :     int heap_intact = (n_prio<i_prio) | ((n_prio==i_prio) & (!((n ^ i) & 1UL))); /* Flip coin on equal priority */
     136   307970064 :     if( heap_intact ) break;
     137             : 
     138   197593803 :     ulong nl = fd_wksp_private_pinfo_idx( pinfo[ n ].left_cidx   ); /* Validated above */
     139   197593803 :     ulong nr = fd_wksp_private_pinfo_idx( pinfo[ n ].right_cidx  ); /* Validated above */
     140   197593803 :     ulong il = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx   ); /* Validated above */
     141             :   //ulong ir = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx  ); /* Validated above */
     142   197593803 :     ulong p  = fd_wksp_private_pinfo_idx( pinfo[ i ].parent_cidx ); /* Validated above */
     143   197593803 :     _p_child_cidx = fd_wksp_private_pinfo_idx_is_null( p )                 ? &wksp->part_used_cidx 
     144   197593803 :                   : (fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx )==i) ? &pinfo[ p ].left_cidx   /* Validated above */
     145   192869790 :                   :                                                          &pinfo[ p ].right_cidx;
     146             : 
     147   197593803 :     int left_child = (il==n);
     148   197593803 :     if( left_child ) { /* 50/50 unpredictable */
     149             : 
     150    96587808 :       pinfo[ n ].right_cidx  = fd_wksp_private_pinfo_cidx( i  ); pinfo[ i ].parent_cidx = fd_wksp_private_pinfo_cidx( n  );
     151    96587808 :       pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p  ); *_p_child_cidx         = fd_wksp_private_pinfo_cidx( n );
     152             : 
     153    96587808 :       pinfo[ i ].left_cidx = fd_wksp_private_pinfo_cidx( nr );
     154    96587808 :       if( !fd_wksp_private_pinfo_idx_is_null( nr ) ) pinfo[ nr ].parent_cidx = fd_wksp_private_pinfo_cidx( i );
     155             : 
     156   101005995 :     } else {
     157             : 
     158   101005995 :       pinfo[ n ].left_cidx   = fd_wksp_private_pinfo_cidx( i  ); pinfo[ i  ].parent_cidx = fd_wksp_private_pinfo_cidx( n );
     159   101005995 :       pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p  ); *_p_child_cidx          = fd_wksp_private_pinfo_cidx( n );
     160             : 
     161   101005995 :       pinfo[ i ].right_cidx = fd_wksp_private_pinfo_cidx( nl );
     162   101005995 :       if( !fd_wksp_private_pinfo_idx_is_null( nl ) ) pinfo[ nl ].parent_cidx = fd_wksp_private_pinfo_cidx( i );
     163             : 
     164   101005995 :     }
     165             : 
     166   197593803 :     i = p;
     167   197593803 :   }
     168             : 
     169   115100274 :   return FD_WKSP_SUCCESS;
     170   152017722 : }
     171             : 
     172             : int
     173             : fd_wksp_private_used_treap_remove( ulong                     d,
     174             :                                    fd_wksp_t *               wksp,
     175   153546621 :                                    fd_wksp_private_pinfo_t * pinfo ) {
     176             : 
     177   153546621 :   ulong part_max  = wksp->part_max;
     178   153546621 :   ulong cycle_tag = wksp->cycle_tag++;
     179             : 
     180   153546621 :   TEST( d<part_max );
     181   153546621 :   pinfo[ d ].cycle_tag = cycle_tag; /* Mark d */
     182             : 
     183             :   /* d should not be in or have a same list in a used treap */
     184             : 
     185   153546621 :   TEST( !pinfo[ d ].in_same );
     186   153546621 :   TEST( fd_wksp_private_pinfo_idx_is_null( fd_wksp_private_pinfo_idx( pinfo[ d ].same_cidx ) ) );
     187             : 
     188             :   /* Load and validate the environment surrounding d. */
     189             : 
     190   153546621 :   ulong l = fd_wksp_private_pinfo_idx( pinfo[ d ].left_cidx   ); TEST_AND_MARK( l ); TEST_PARENT( l, d );
     191   153546621 :   ulong r = fd_wksp_private_pinfo_idx( pinfo[ d ].right_cidx  ); TEST_AND_MARK( r ); TEST_PARENT( r, d );
     192   153546621 :   ulong p = fd_wksp_private_pinfo_idx( pinfo[ d ].parent_cidx ); TEST_AND_MARK( p );
     193             : 
     194   153546621 :   uint * _p_child_cidx;
     195   153546621 :   if( fd_wksp_private_pinfo_idx_is_null( p ) ) {
     196    43191708 :     _p_child_cidx = &wksp->part_used_cidx;
     197    43191708 :     TEST( (*_p_child_cidx)==d );
     198   110354913 :   } else {
     199   110354913 :     ulong pl = fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx  ); /* One should be marked from above */
     200   110354913 :     ulong pr = fd_wksp_private_pinfo_idx( pinfo[ p ].right_cidx ); /* The other should not */
     201   110354913 :     int is_left_child  = (pl==d);
     202   110354913 :     int is_right_child = (pr==d);
     203   110354913 :     TEST( is_left_child!=is_right_child );
     204   110354511 :     _p_child_cidx = fd_ptr_if( is_left_child, &pinfo[ p ].left_cidx, &pinfo[ p ].right_cidx );
     205   110354511 :   }
     206             : 
     207   206262432 :   for(;;) {
     208             : 
     209             :     /* At this point, we have a non-trivial hole to fill at d.
     210             : 
     211             :        i and j are IDX_NULL as d has no overlapping partitions
     212             :        l is the hole's left subtree (if any), validated and marked
     213             :        r is the hole's right subtree (if any), validated and marked
     214             :        p is the hole's parent (if any), if non-NULL, validated and marked
     215             : 
     216             :        _p_child_cidx is the location of link from the parent to the hole
     217             :        (or the pointer to the tree root if d is the root), validated. */
     218             : 
     219             :     /* If the hole has no left subtree (and maybe no right subtree and
     220             :        maybe no parent), fill the hole with the right subtree (or with
     221             :        nothing if no right subtree) and we are done. */
     222             : 
     223   206262432 :     if( fd_wksp_private_pinfo_idx_is_null( l ) ) {
     224    77951835 :       if( !fd_wksp_private_pinfo_idx_is_null( r ) ) pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( p );
     225    77951835 :       *_p_child_cidx = fd_wksp_private_pinfo_cidx( r );
     226    77951835 :       break;
     227    77951835 :     }
     228             : 
     229             :     /* If the hole has no right subtree but has a left subtree (and
     230             :        maybe no parent), fill the hole with the left subtree and we are
     231             :        done. */
     232             : 
     233   128310597 :     if( fd_wksp_private_pinfo_idx_is_null( r ) ) {
     234    38102523 :       pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( p );
     235    38102523 :       *_p_child_cidx = fd_wksp_private_pinfo_cidx( l );
     236    38102523 :       break;
     237    38102523 :     }
     238             : 
     239             :     /* At this point we have to push the hole down the left or right
     240             :        subtree (and we still maybe have no parent).  We use the heap
     241             :        priorities to decide such that we preserve the heap property (we
     242             :        flip a coin on equal priorities).  We can omit any link updates
     243             :        from d as d is getting removed and the above just needs the
     244             :        environment around d.  Likewise, we can omit any link updates to
     245             :        d these will be ultimately replaced with links to something other
     246             :        than d before this returns. */
     247             : 
     248    90208074 :     uint l_prio = pinfo[ l ].heap_prio;
     249    90208074 :     uint r_prio = pinfo[ r ].heap_prio;
     250    90208074 :     int promote_left = (l_prio>r_prio) | ((l_prio==r_prio) & (!((p ^ d) & 1UL)));
     251    90208074 :     if( promote_left ) {
     252             : 
     253    44187777 :       ulong t = fd_wksp_private_pinfo_idx( pinfo[ l ].right_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, l );
     254             : 
     255    44187777 :       *_p_child_cidx        = fd_wksp_private_pinfo_cidx( l ); pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( p );
     256             :     //pinfo[ l ].right_cidx = fd_wksp_private_pinfo_cidx( d ); pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( l );
     257             :     //pinfo[ d ].left_cidx  = fd_wksp_private_pinfo_cidx( t );
     258             :     //if( !fd_wksp_private_pinfo_idx_is_null( t ) ) pinfo[ t ].parent_cidx = fd_wksp_private_pinfo_cidx( d );
     259             : 
     260    44187777 :       _p_child_cidx = &pinfo[ l ].right_cidx; /* TBD next iteration */
     261             : 
     262    44187777 :       p = l;
     263    44187777 :       l = t;
     264             : 
     265    46020297 :     } else { /* This is the mirror image of the above */
     266             : 
     267    46020297 :       ulong t = fd_wksp_private_pinfo_idx( pinfo[ r ].left_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, r );
     268             : 
     269    46020297 :       *_p_child_cidx        = fd_wksp_private_pinfo_cidx( r ); pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( p );
     270             :     //pinfo[ r ].left_cidx  = fd_wksp_private_pinfo_cidx( d ); pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( r );
     271             :     //pinfo[ d ].right_cidx = fd_wksp_private_pinfo_cidx( t );
     272             :     //if( !fd_wksp_private_pinfo_idx_is_null( t ) ) pinfo[ t ].parent_cidx = fd_wksp_private_pinfo_cidx( d );
     273             : 
     274    46020297 :       _p_child_cidx = &pinfo[ r ].left_cidx; /* TBD next iteration */
     275             : 
     276    46020297 :       p = r;
     277    46020297 :       r = t;
     278             : 
     279    46020297 :     }
     280             : 
     281    90208074 :   }
     282             : 
     283   116054358 :   pinfo[ d ].in_same     = 0U;
     284   116054358 :   pinfo[ d ].left_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     285   116054358 :   pinfo[ d ].right_cidx  = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     286   116054358 :   pinfo[ d ].same_cidx   = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     287   116054358 :   pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL );
     288   116054358 :   return FD_WKSP_SUCCESS;
     289   116054358 : }
     290             : 
     291             : #undef TEST_PARENT
     292             : #undef TEST_AND_MARK
     293             : #undef TEST

Generated by: LCOV version 1.14