Line data Source code
1 : #include "fd_wksp_private.h" 2 : 3 : ulong 4 : fd_wksp_private_free_treap_query( ulong sz, 5 : fd_wksp_t * wksp, 6 230599704 : fd_wksp_private_pinfo_t * pinfo ) { 7 230599704 : if( FD_UNLIKELY( !sz ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; 8 : 9 228358131 : ulong f = FD_WKSP_PRIVATE_PINFO_IDX_NULL; 10 : 11 228358131 : ulong part_max = wksp->part_max; 12 228358131 : ulong cycle_tag = wksp->cycle_tag++; 13 : 14 228358131 : ulong i = fd_wksp_private_pinfo_idx( wksp->part_free_cidx ); 15 1380200740 : while( !fd_wksp_private_pinfo_idx_is_null( i ) ) { 16 1225222243 : if( FD_UNLIKELY( i>=part_max ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Bad index */ 17 1225222243 : if( FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Cycle detected */ 18 1225222243 : pinfo[ i ].cycle_tag = cycle_tag; /* Mark i as visited */ 19 : 20 1225222243 : ulong part_sz = fd_wksp_private_pinfo_sz( pinfo + i ); 21 1225222243 : if( sz>part_sz ) i = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); /* Partition list and left too small, go right */ 22 621961254 : else { 23 621961254 : f = i; /* If all else fails, partitions of this sz will work */ 24 621961254 : if( sz==part_sz ) break; /* Exact match (we aren't going to find anything better to our left) */ 25 548581620 : i = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx ); 26 548581620 : } 27 1225222243 : } 28 : 29 228358131 : return f; 30 228358131 : } 31 : 32 7986397780 : #define TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { /*FD_LOG_WARNING(( "FAIL: %s", #c ));*/ return FD_WKSP_ERR_CORRUPT; } } while(0) 33 : 34 3627844885 : #define TEST_AND_MARK( i ) do { \ 35 3627844885 : ulong _i = (i); \ 36 3627844885 : TEST( fd_wksp_private_pinfo_idx_is_null( _i ) | ((_i<part_max) && (pinfo[ _i ].cycle_tag!=cycle_tag)) ); \ 37 3627844885 : if( !fd_wksp_private_pinfo_idx_is_null( _i ) ) pinfo[ _i ].cycle_tag = cycle_tag; \ 38 3610091518 : } while(0) 39 : 40 3250370179 : #define TEST_PARENT( i, p ) do { \ 41 3250370179 : ulong _i = (i); \ 42 3250370179 : if( _i<part_max ) TEST( fd_wksp_private_pinfo_idx( pinfo[_i].parent_cidx )==(p) ); \ 43 3250370179 : } while(0) 44 : 45 : int 46 : fd_wksp_private_free_treap_insert( ulong n, 47 : fd_wksp_t * wksp, 48 252544947 : fd_wksp_private_pinfo_t * pinfo ) { 49 : 50 252544947 : ulong part_max = wksp->part_max; 51 252544947 : ulong cycle_tag = wksp->cycle_tag++; 52 : 53 252544947 : TEST( n<part_max ); /* Make sure valid n */ 54 252544947 : pinfo[ n ].cycle_tag = cycle_tag; /* Mark n */ 55 : 56 252544947 : ulong g0 = pinfo[ n ].gaddr_lo; 57 252544947 : ulong g1 = pinfo[ n ].gaddr_hi; 58 252544947 : ulong n_sz = g1 - g0; 59 : 60 252544947 : TEST( (wksp->gaddr_lo<=g0) & (g0<g1) & (g1<=wksp->gaddr_hi) ); /* Make sure valid range */ 61 : 62 : /* Note: non-zero tag is okay temporarily. We assume the caller 63 : will set the tag to non-zero immediately afterward to make the 64 : allocation "official". */ 65 : 66 252544947 : uint * _p_child_cidx = &wksp->part_free_cidx; 67 : 68 252544947 : ulong i = fd_wksp_private_pinfo_idx( *_p_child_cidx ); TEST_AND_MARK( i ); 69 : 70 : /* If an empty treap, make n the root and we are done */ 71 : 72 251951136 : if( FD_UNLIKELY( fd_wksp_private_pinfo_idx_is_null( i ) ) ) { /* Assume lots of free partitions typically */ 73 4267605 : pinfo[ n ].in_same = 0U; 74 4267605 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 75 4267605 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 76 4267605 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 77 4267605 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 78 4267605 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 79 4267605 : return FD_WKSP_SUCCESS; 80 4267605 : } 81 : 82 247683531 : TEST_PARENT( i, FD_WKSP_PRIVATE_PINFO_IDX_NULL ); /* Make sure good parent link */ 83 : 84 : /* Find the leaf node where we can insert n */ 85 : 86 : /* TODO: Consider pushing path down onto stack and bubble up 87 : using the stack? */ 88 : 89 1122179639 : for(;;) { 90 : 91 1122179639 : TEST( !pinfo[ i ].in_same ); 92 : 93 : /* At this point, i is a valid marked index with good parent 94 : connectivity. TODO: Consider validating ranges of visited nodes 95 : and tags of visited nodes */ 96 : 97 : /* We need to validate both left and right child links to make the 98 : bubble up phase robust (because we do that after we actually have 99 : inserted). */ 100 : 101 1122179639 : ulong l = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx ); TEST_AND_MARK( l ); TEST_PARENT( l, i ); 102 1113145085 : ulong r = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); TEST_AND_MARK( r ); TEST_PARENT( r, i ); 103 : 104 1105020083 : ulong i_sz = fd_wksp_private_pinfo_sz( pinfo + i ); 105 : 106 1105020083 : int go_left = (n_sz < i_sz); 107 1105020083 : if( go_left ) { 108 491273589 : _p_child_cidx = &pinfo[ i ].left_cidx; 109 491273589 : if( fd_wksp_private_pinfo_idx_is_null( l ) ) break; 110 424804608 : i = l; 111 424804608 : continue; 112 491273589 : } 113 : 114 613746494 : int go_right = (n_sz > i_sz); 115 613746494 : if( go_right ) { 116 526956758 : _p_child_cidx = &pinfo[ i ].right_cidx; 117 526956758 : if( fd_wksp_private_pinfo_idx_is_null( r ) ) break; 118 449691500 : i = r; 119 449691500 : continue; 120 526956758 : } 121 : 122 : /* n and i have the same size. Insert into i's same list */ 123 : 124 86789736 : # if 1 /* This doesn't validate whether or not n is already in same list. But it is O(1). */ 125 : 126 86789736 : ulong j = fd_wksp_private_pinfo_idx( pinfo[ i ].same_cidx ); TEST_AND_MARK( j ); 127 : 128 86789736 : pinfo[ n ].in_same = 1U; 129 86789736 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 130 86789736 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 131 86789736 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( j ); 132 86789736 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 133 : 134 : /**/ pinfo[ i ].same_cidx = fd_wksp_private_pinfo_cidx( n ); 135 86789736 : if( !fd_wksp_private_pinfo_idx_is_null( j ) ) pinfo[ j ].parent_cidx = fd_wksp_private_pinfo_cidx( n ); 136 : 137 : # else /* This does but it is O(same_list_length). */ 138 : 139 : ulong j = i; 140 : for(;;) { 141 : ulong k = fd_wksp_private_pinfo_idx( pinfo[ j ].same_cidx ); TEST_AND_MARK( k ); 142 : if( fd_wksp_private_pinfo_idx_is_null( k ) ) break; 143 : TEST( fd_wksp_private_pinfo_idx( pinfo[ k ].parent_cidx )==j ); /* Make sure good prev */ 144 : j = k; 145 : } 146 : 147 : pinfo[ n ].in_same = 1U; 148 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 149 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 150 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 151 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( j ); 152 : 153 : pinfo[ j ].same_cidx = fd_wksp_private_pinfo_cidx( n ); 154 : 155 : # endif 156 : 157 86789736 : return FD_WKSP_SUCCESS; 158 86789736 : } 159 : 160 : /* Make n the appropriate child of i. This might momentarily break 161 : the heap property. */ 162 : 163 143734239 : pinfo[ n ].in_same = 0U; 164 143734239 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 165 143734239 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 166 143734239 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 167 143734239 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 168 143734239 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 169 : 170 : /* Bubble n up until the heap property is restored. Note that in the 171 : traversal above, we also validated parent links for this traversal 172 : (so that we could insert without worrying about encountering 173 : unpleasantness after we changed the treap). */ 174 : 175 359801220 : while( !fd_wksp_private_pinfo_idx_is_null( i ) ) { 176 345154210 : uint n_prio = pinfo[ n ].heap_prio; 177 345154210 : uint i_prio = pinfo[ i ].heap_prio; 178 345154210 : int heap_intact = (n_prio < i_prio) | ((n_prio==i_prio) & (!((n ^ i) & 1UL))); /* Flip coin on equal priority */ 179 345154210 : if( heap_intact ) break; 180 : 181 216066981 : ulong nl = fd_wksp_private_pinfo_idx( pinfo[ n ].left_cidx ); /* Validated above */ 182 216066981 : ulong nr = fd_wksp_private_pinfo_idx( pinfo[ n ].right_cidx ); /* Validated above */ 183 216066981 : ulong il = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx ); /* Validated above */ 184 : //ulong ir = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); /* Validated above */ 185 216066981 : ulong p = fd_wksp_private_pinfo_idx( pinfo[ i ].parent_cidx ); /* Validated above */ 186 216066981 : _p_child_cidx = fd_wksp_private_pinfo_idx_is_null( p ) ? &wksp->part_free_cidx 187 216066981 : : (fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx )==i) ? &pinfo[ p ].left_cidx /* Validated above */ 188 201419971 : : &pinfo[ p ].right_cidx; 189 : 190 216066981 : int left_child = (il==n); 191 216066981 : if( left_child ) { /* 50/50 unpredictable */ 192 : 193 97504527 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( i ); pinfo[ i ].parent_cidx = fd_wksp_private_pinfo_cidx( n ); 194 97504527 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 195 : 196 97504527 : pinfo[ i ].left_cidx = fd_wksp_private_pinfo_cidx( nr ); 197 97504527 : if( !fd_wksp_private_pinfo_idx_is_null( nr ) ) pinfo[ nr ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 198 : 199 118562454 : } else { 200 : 201 118562454 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( i ); pinfo[ i ].parent_cidx = fd_wksp_private_pinfo_cidx( n ); 202 118562454 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 203 : 204 118562454 : pinfo[ i ].right_cidx = fd_wksp_private_pinfo_cidx( nl ); 205 118562454 : if( !fd_wksp_private_pinfo_idx_is_null( nl ) ) pinfo[ nl ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 206 : 207 118562454 : } 208 : 209 216066981 : i = p; 210 216066981 : } 211 : 212 143734239 : return FD_WKSP_SUCCESS; 213 247683531 : } 214 : 215 : int 216 : fd_wksp_private_free_treap_remove( ulong d, 217 : fd_wksp_t * wksp, 218 268663998 : fd_wksp_private_pinfo_t * pinfo ) { 219 : 220 268663998 : ulong part_max = wksp->part_max; 221 268663998 : ulong cycle_tag = wksp->cycle_tag++; 222 : 223 268663998 : TEST( d<part_max ); 224 268663998 : pinfo[ d ].cycle_tag = cycle_tag; /* Mark d */ 225 : 226 : /* If d is in a same list, remove it */ 227 : 228 268663998 : ulong j = fd_wksp_private_pinfo_idx( pinfo[ d ].same_cidx ); TEST_AND_MARK( j ); TEST_PARENT( j, d ); 229 : 230 268663998 : if( pinfo[ d ].in_same ) { 231 55067955 : ulong i = fd_wksp_private_pinfo_idx( pinfo[ d ].parent_cidx ); TEST_AND_MARK( i ); 232 : 233 55067955 : TEST( !fd_wksp_private_pinfo_idx_is_null( i ) ); 234 55067955 : TEST( pinfo[ i ].same_cidx==d ); 235 : 236 55067955 : if( !fd_wksp_private_pinfo_idx_is_null( j ) ) pinfo[ j ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 237 55067955 : pinfo[ i ].same_cidx = fd_wksp_private_pinfo_cidx( j ); 238 55067955 : goto done; 239 55067955 : } 240 : 241 : /* d is not in a same list. Load and validate the environment 242 : surrounding d. */ 243 : 244 213596043 : ulong l = fd_wksp_private_pinfo_idx( pinfo[ d ].left_cidx ); TEST_AND_MARK( l ); TEST_PARENT( l, d ); 245 213596043 : ulong r = fd_wksp_private_pinfo_idx( pinfo[ d ].right_cidx ); TEST_AND_MARK( r ); TEST_PARENT( r, d ); 246 213596043 : ulong p = fd_wksp_private_pinfo_idx( pinfo[ d ].parent_cidx ); TEST_AND_MARK( p ); 247 : 248 213596043 : uint * _p_child_cidx; 249 213596043 : if( fd_wksp_private_pinfo_idx_is_null( p ) ) { 250 57653015 : _p_child_cidx = &wksp->part_free_cidx; 251 57653015 : TEST( (*_p_child_cidx)==d ); 252 155943028 : } else { 253 155943028 : ulong pl = fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx ); /* One should be marked from above */ 254 155943028 : ulong pr = fd_wksp_private_pinfo_idx( pinfo[ p ].right_cidx ); /* The other should not. */ 255 155943028 : int is_left_child = (pl==d); 256 155943028 : int is_right_child = (pr==d); 257 155943028 : TEST( is_left_child!=is_right_child ); 258 155942626 : _p_child_cidx = fd_ptr_if( is_left_child, &pinfo[ p ].left_cidx, &pinfo[ p ].right_cidx ); 259 155942626 : } 260 : 261 : /* If d has non-empty same list, fill the hole made by removing d with 262 : the first partition in d's same list. This might break the heap 263 : property. Instead of doing a bunch of bubbling, since d already 264 : had a valid heap priority, we just swap the heap priorities of j 265 : with the heap priority of d. */ 266 : 267 176103780 : if( !fd_wksp_private_pinfo_idx_is_null( j ) ) { 268 28111035 : pinfo[ j ].in_same = 0U; 269 28111035 : pinfo[ j ].left_cidx = fd_wksp_private_pinfo_cidx( l ); 270 28111035 : pinfo[ j ].right_cidx = fd_wksp_private_pinfo_cidx( r ); 271 28111035 : pinfo[ j ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 272 : //pinfo[ j ].same_cidx unchanged 273 : 274 28111035 : uint j_prio = pinfo[ j ].heap_prio; 275 28111035 : uint d_prio = pinfo[ d ].heap_prio; 276 28111035 : pinfo[ j ].heap_prio = d_prio & ((1UL<<31)-1UL); /* Quell dubious compiler warning */ 277 28111035 : pinfo[ d ].heap_prio = j_prio & ((1UL<<31)-1UL); /* " */ 278 : 279 28111035 : if( !fd_wksp_private_pinfo_idx_is_null( l ) ) pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( j ); 280 28111035 : if( !fd_wksp_private_pinfo_idx_is_null( r ) ) pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( j ); 281 28111035 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( j ); 282 : 283 28111035 : goto done; 284 28111035 : } 285 : 286 236658141 : for(;;) { 287 : 288 : /* At this point, d is the only partition of its size and we have a 289 : non-trivial hole to fill. 290 : 291 : i and j are IDX_NULL as d has no same sized partitions 292 : l is the hole's left subtree (if any), validated and marked 293 : r is the hole's right subtree (if any), validated and marked 294 : p is the hole's parent (if any), if non-NULL, validated and marked 295 : 296 : _p_child_cidx is the location of link from the parent to the hole 297 : (or the pointer to the tree root if d is the root), validated. */ 298 : 299 : /* If the hole has no left subtree (and maybe no right subtree and 300 : maybe no parent), fill the hole with the right subtree (or with 301 : nothing if no right subtree) and we are done. */ 302 : 303 236658141 : if( fd_wksp_private_pinfo_idx_is_null( l ) ) { 304 99963928 : if( !fd_wksp_private_pinfo_idx_is_null( r ) ) pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 305 99963928 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( r ); 306 99963928 : break; 307 99963928 : } 308 : 309 : /* If the hole has no right subtree but has a left subtree (and 310 : maybe no parent), fill the hole with the left subtree and we are 311 : done. */ 312 : 313 136694213 : if( fd_wksp_private_pinfo_idx_is_null( r ) ) { 314 48028817 : pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 315 48028817 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( l ); 316 48028817 : break; 317 48028817 : } 318 : 319 : /* At this point, we have to push the hole down the left or right 320 : subtree (and we still maybe have no parent). We use the heap 321 : priorities to decide such that we preserve the heap property (we 322 : flip a coin on equal priorities). We ultimately can omit any 323 : link updates involving d as these will be replaced with correct 324 : links before this returns. */ 325 : 326 88665396 : uint l_prio = pinfo[ l ].heap_prio; 327 88665396 : uint r_prio = pinfo[ r ].heap_prio; 328 : 329 88665396 : int promote_left = (l_prio>r_prio) | ((l_prio==r_prio) & (!((p ^ d) & 1UL))); 330 88665396 : if( promote_left ) { 331 : 332 47986188 : ulong t = fd_wksp_private_pinfo_idx( pinfo[ l ].right_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, l ); 333 : 334 47986188 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( l ); pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 335 : //pinfo[ l ].right_cidx = fd_wksp_private_pinfo_cidx( d ); pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( l ); 336 : //pinfo[ d ].left_cidx = fd_wksp_private_pinfo_cidx( t ); 337 : //if( !fd_wksp_private_pinfo_idx_is_null( t ) ) pinfo[ t ].parent_cidx = fd_wksp_private_pinfo_cidx( d ); 338 : 339 47986188 : _p_child_cidx = &pinfo[ l ].right_cidx; /* TBD next iteration */ 340 : 341 47986188 : p = l; 342 47986188 : l = t; 343 : 344 47986188 : } else { /* This is the mirror image of the above */ 345 : 346 40679208 : ulong t = fd_wksp_private_pinfo_idx( pinfo[ r ].left_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, r ); 347 : 348 40679208 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( r ); pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 349 : //pinfo[ r ].left_cidx = fd_wksp_private_pinfo_cidx( d ); pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( r ); 350 : //pinfo[ d ].right_cidx = fd_wksp_private_pinfo_cidx( t ); 351 : //if( !fd_wksp_private_pinfo_idx_is_null( t ) ) pinfo[ t ].parent_cidx = fd_wksp_private_pinfo_cidx( d ); 352 : 353 40679208 : _p_child_cidx = &pinfo[ r ].left_cidx; /* TBD next iteration */ 354 : 355 40679208 : p = r; 356 40679208 : r = t; 357 : 358 40679208 : } 359 : 360 88665396 : } 361 : 362 231171735 : done: 363 231171735 : pinfo[ d ].in_same = 0U; 364 231171735 : pinfo[ d ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 365 231171735 : pinfo[ d ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 366 231171735 : pinfo[ d ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 367 231171735 : pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 368 231171735 : return FD_WKSP_SUCCESS; 369 147992745 : } 370 : 371 : #undef TEST_PARENT 372 : #undef TEST_AND_MARK 373 : #undef TEST