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 137 : fd_wksp_private_pinfo_t * pinfo ) { 7 137 : if( FD_UNLIKELY( !sz ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; 8 : 9 137 : ulong f = FD_WKSP_PRIVATE_PINFO_IDX_NULL; 10 : 11 137 : ulong part_max = wksp->part_max; 12 137 : ulong cycle_tag = wksp->cycle_tag++; 13 : 14 137 : ulong i = fd_wksp_private_pinfo_idx( wksp->part_free_cidx ); 15 661 : while( !fd_wksp_private_pinfo_idx_is_null( i ) ) { 16 524 : if( FD_UNLIKELY( i>=part_max ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Bad index */ 17 524 : if( FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) return FD_WKSP_PRIVATE_PINFO_IDX_NULL; /* Cycle detected */ 18 524 : pinfo[ i ].cycle_tag = cycle_tag; /* Mark i as visited */ 19 : 20 524 : ulong part_sz = fd_wksp_private_pinfo_sz( pinfo + i ); 21 524 : if( sz>part_sz ) i = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); /* Partition list and left too small, go right */ 22 147 : else { 23 147 : f = i; /* If all else fails, partitions of this sz will work */ 24 147 : if( sz==part_sz ) break; /* Exact match (we aren't going to find anything better to our left) */ 25 147 : i = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx ); 26 147 : } 27 524 : } 28 : 29 137 : return f; 30 137 : } 31 : 32 5035 : #define TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { /*FD_LOG_WARNING(( "FAIL: %s", #c ));*/ return FD_WKSP_ERR_CORRUPT; } } while(0) 33 : 34 2351 : #define TEST_AND_MARK( i ) do { \ 35 2351 : ulong _i = (i); \ 36 2351 : TEST( fd_wksp_private_pinfo_idx_is_null( _i ) | ((_i<part_max) && (pinfo[ _i ].cycle_tag!=cycle_tag)) ); \ 37 2351 : if( !fd_wksp_private_pinfo_idx_is_null( _i ) ) pinfo[ _i ].cycle_tag = cycle_tag; \ 38 2351 : } while(0) 39 : 40 2127 : #define TEST_PARENT( i, p ) do { \ 41 2127 : ulong _i = (i); \ 42 2127 : if( _i<part_max ) TEST( fd_wksp_private_pinfo_idx( pinfo[_i].parent_cidx )==(p) ); \ 43 2127 : } while(0) 44 : 45 : int 46 : fd_wksp_private_free_treap_insert( ulong n, 47 : fd_wksp_t * wksp, 48 217 : fd_wksp_private_pinfo_t * pinfo ) { 49 : 50 217 : ulong part_max = wksp->part_max; 51 217 : ulong cycle_tag = wksp->cycle_tag++; 52 : 53 217 : TEST( n<part_max ); /* Make sure valid n */ 54 217 : pinfo[ n ].cycle_tag = cycle_tag; /* Mark n */ 55 : 56 217 : ulong g0 = pinfo[ n ].gaddr_lo; 57 217 : ulong g1 = pinfo[ n ].gaddr_hi; 58 217 : ulong n_sz = g1 - g0; 59 : 60 217 : 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 217 : uint * _p_child_cidx = &wksp->part_free_cidx; 67 : 68 217 : 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 217 : if( FD_UNLIKELY( fd_wksp_private_pinfo_idx_is_null( i ) ) ) { /* Assume lots of free partitions typically */ 73 3 : pinfo[ n ].in_same = 0U; 74 3 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 75 3 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 76 3 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 77 3 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 78 3 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 79 3 : return FD_WKSP_SUCCESS; 80 3 : } 81 : 82 214 : 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 714 : for(;;) { 90 : 91 714 : 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 714 : ulong l = fd_wksp_private_pinfo_idx( pinfo[ i ].left_cidx ); TEST_AND_MARK( l ); TEST_PARENT( l, i ); 102 714 : ulong r = fd_wksp_private_pinfo_idx( pinfo[ i ].right_cidx ); TEST_AND_MARK( r ); TEST_PARENT( r, i ); 103 : 104 714 : ulong i_sz = fd_wksp_private_pinfo_sz( pinfo + i ); 105 : 106 714 : int go_left = (n_sz < i_sz); 107 714 : if( go_left ) { 108 93 : _p_child_cidx = &pinfo[ i ].left_cidx; 109 93 : if( fd_wksp_private_pinfo_idx_is_null( l ) ) break; 110 69 : i = l; 111 69 : continue; 112 93 : } 113 : 114 621 : int go_right = (n_sz > i_sz); 115 621 : if( go_right ) { 116 567 : _p_child_cidx = &pinfo[ i ].right_cidx; 117 567 : if( fd_wksp_private_pinfo_idx_is_null( r ) ) break; 118 431 : i = r; 119 431 : continue; 120 567 : } 121 : 122 : /* n and i have the same size. Insert into i's same list */ 123 : 124 54 : # if 1 /* This doesn't validate whether or not n is already in same list. But it is O(1). */ 125 : 126 54 : ulong j = fd_wksp_private_pinfo_idx( pinfo[ i ].same_cidx ); TEST_AND_MARK( j ); 127 : 128 54 : pinfo[ n ].in_same = 1U; 129 54 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 130 54 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 131 54 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( j ); 132 54 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 133 : 134 : /**/ pinfo[ i ].same_cidx = fd_wksp_private_pinfo_cidx( n ); 135 54 : 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 54 : return FD_WKSP_SUCCESS; 158 54 : } 159 : 160 : /* Make n the appropriate child of i. This might momentarily break 161 : the heap property. */ 162 : 163 160 : pinfo[ n ].in_same = 0U; 164 160 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 165 160 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 166 160 : pinfo[ n ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 167 160 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 168 160 : *_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 381 : while( !fd_wksp_private_pinfo_idx_is_null( i ) ) { 176 346 : uint n_prio = pinfo[ n ].heap_prio; 177 346 : uint i_prio = pinfo[ i ].heap_prio; 178 346 : int heap_intact = (n_prio < i_prio) | ((n_prio==i_prio) & (!((n ^ i) & 1UL))); /* Flip coin on equal priority */ 179 346 : if( heap_intact ) break; 180 : 181 221 : ulong nl = fd_wksp_private_pinfo_idx( pinfo[ n ].left_cidx ); /* Validated above */ 182 221 : ulong nr = fd_wksp_private_pinfo_idx( pinfo[ n ].right_cidx ); /* Validated above */ 183 221 : 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 221 : ulong p = fd_wksp_private_pinfo_idx( pinfo[ i ].parent_cidx ); /* Validated above */ 186 221 : _p_child_cidx = fd_wksp_private_pinfo_idx_is_null( p ) ? &wksp->part_free_cidx 187 221 : : (fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx )==i) ? &pinfo[ p ].left_cidx /* Validated above */ 188 186 : : &pinfo[ p ].right_cidx; 189 : 190 221 : int left_child = (il==n); 191 221 : if( left_child ) { /* 50/50 unpredictable */ 192 : 193 16 : pinfo[ n ].right_cidx = fd_wksp_private_pinfo_cidx( i ); pinfo[ i ].parent_cidx = fd_wksp_private_pinfo_cidx( n ); 194 16 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 195 : 196 16 : pinfo[ i ].left_cidx = fd_wksp_private_pinfo_cidx( nr ); 197 16 : if( !fd_wksp_private_pinfo_idx_is_null( nr ) ) pinfo[ nr ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 198 : 199 205 : } else { 200 : 201 205 : pinfo[ n ].left_cidx = fd_wksp_private_pinfo_cidx( i ); pinfo[ i ].parent_cidx = fd_wksp_private_pinfo_cidx( n ); 202 205 : pinfo[ n ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); *_p_child_cidx = fd_wksp_private_pinfo_cidx( n ); 203 : 204 205 : pinfo[ i ].right_cidx = fd_wksp_private_pinfo_cidx( nl ); 205 205 : if( !fd_wksp_private_pinfo_idx_is_null( nl ) ) pinfo[ nl ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 206 : 207 205 : } 208 : 209 221 : i = p; 210 221 : } 211 : 212 160 : return FD_WKSP_SUCCESS; 213 214 : } 214 : 215 : int 216 : fd_wksp_private_free_treap_remove( ulong d, 217 : fd_wksp_t * wksp, 218 167 : fd_wksp_private_pinfo_t * pinfo ) { 219 : 220 167 : ulong part_max = wksp->part_max; 221 167 : ulong cycle_tag = wksp->cycle_tag++; 222 : 223 167 : TEST( d<part_max ); 224 167 : pinfo[ d ].cycle_tag = cycle_tag; /* Mark d */ 225 : 226 : /* If d is in a same list, remove it */ 227 : 228 167 : ulong j = fd_wksp_private_pinfo_idx( pinfo[ d ].same_cidx ); TEST_AND_MARK( j ); TEST_PARENT( j, d ); 229 : 230 167 : if( pinfo[ d ].in_same ) { 231 10 : ulong i = fd_wksp_private_pinfo_idx( pinfo[ d ].parent_cidx ); TEST_AND_MARK( i ); 232 : 233 10 : TEST( !fd_wksp_private_pinfo_idx_is_null( i ) ); 234 10 : TEST( pinfo[ i ].same_cidx==d ); 235 : 236 10 : if( !fd_wksp_private_pinfo_idx_is_null( j ) ) pinfo[ j ].parent_cidx = fd_wksp_private_pinfo_cidx( i ); 237 10 : pinfo[ i ].same_cidx = fd_wksp_private_pinfo_cidx( j ); 238 10 : goto done; 239 10 : } 240 : 241 : /* d is not in a same list. Load and validate the environment 242 : surrounding d. */ 243 : 244 157 : ulong l = fd_wksp_private_pinfo_idx( pinfo[ d ].left_cidx ); TEST_AND_MARK( l ); TEST_PARENT( l, d ); 245 157 : ulong r = fd_wksp_private_pinfo_idx( pinfo[ d ].right_cidx ); TEST_AND_MARK( r ); TEST_PARENT( r, d ); 246 157 : ulong p = fd_wksp_private_pinfo_idx( pinfo[ d ].parent_cidx ); TEST_AND_MARK( p ); 247 : 248 157 : uint * _p_child_cidx; 249 157 : if( fd_wksp_private_pinfo_idx_is_null( p ) ) { 250 37 : _p_child_cidx = &wksp->part_free_cidx; 251 37 : TEST( (*_p_child_cidx)==d ); 252 120 : } else { 253 120 : ulong pl = fd_wksp_private_pinfo_idx( pinfo[ p ].left_cidx ); /* One should be marked from above */ 254 120 : ulong pr = fd_wksp_private_pinfo_idx( pinfo[ p ].right_cidx ); /* The other should not. */ 255 120 : int is_left_child = (pl==d); 256 120 : int is_right_child = (pr==d); 257 120 : TEST( is_left_child!=is_right_child ); 258 120 : _p_child_cidx = fd_ptr_if( is_left_child, &pinfo[ p ].left_cidx, &pinfo[ p ].right_cidx ); 259 120 : } 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 157 : if( !fd_wksp_private_pinfo_idx_is_null( j ) ) { 268 2 : pinfo[ j ].in_same = 0U; 269 2 : pinfo[ j ].left_cidx = fd_wksp_private_pinfo_cidx( l ); 270 2 : pinfo[ j ].right_cidx = fd_wksp_private_pinfo_cidx( r ); 271 2 : pinfo[ j ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 272 : //pinfo[ j ].same_cidx unchanged 273 : 274 2 : uint j_prio = pinfo[ j ].heap_prio; 275 2 : uint d_prio = pinfo[ d ].heap_prio; 276 2 : pinfo[ j ].heap_prio = d_prio & ((1UL<<31)-1UL); /* Quell dubious compiler warning */ 277 2 : pinfo[ d ].heap_prio = j_prio & ((1UL<<31)-1UL); /* " */ 278 : 279 2 : if( !fd_wksp_private_pinfo_idx_is_null( l ) ) pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( j ); 280 2 : if( !fd_wksp_private_pinfo_idx_is_null( r ) ) pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( j ); 281 2 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( j ); 282 : 283 2 : goto done; 284 2 : } 285 : 286 159 : 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 159 : if( fd_wksp_private_pinfo_idx_is_null( l ) ) { 304 71 : if( !fd_wksp_private_pinfo_idx_is_null( r ) ) pinfo[ r ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 305 71 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( r ); 306 71 : break; 307 71 : } 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 88 : if( fd_wksp_private_pinfo_idx_is_null( r ) ) { 314 84 : pinfo[ l ].parent_cidx = fd_wksp_private_pinfo_cidx( p ); 315 84 : *_p_child_cidx = fd_wksp_private_pinfo_cidx( l ); 316 84 : break; 317 84 : } 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 4 : uint l_prio = pinfo[ l ].heap_prio; 327 4 : uint r_prio = pinfo[ r ].heap_prio; 328 : 329 4 : int promote_left = (l_prio>r_prio) | ((l_prio==r_prio) & (!((p ^ d) & 1UL))); 330 4 : if( promote_left ) { 331 : 332 4 : ulong t = fd_wksp_private_pinfo_idx( pinfo[ l ].right_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, l ); 333 : 334 4 : *_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 4 : _p_child_cidx = &pinfo[ l ].right_cidx; /* TBD next iteration */ 340 : 341 4 : p = l; 342 4 : l = t; 343 : 344 4 : } else { /* This is the mirror image of the above */ 345 : 346 0 : ulong t = fd_wksp_private_pinfo_idx( pinfo[ r ].left_cidx ); TEST_AND_MARK( t ); TEST_PARENT( t, r ); 347 : 348 0 : *_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 0 : _p_child_cidx = &pinfo[ r ].left_cidx; /* TBD next iteration */ 354 : 355 0 : p = r; 356 0 : r = t; 357 : 358 0 : } 359 : 360 4 : } 361 : 362 167 : done: 363 167 : pinfo[ d ].in_same = 0U; 364 167 : pinfo[ d ].left_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 365 167 : pinfo[ d ].right_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 366 167 : pinfo[ d ].same_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 367 167 : pinfo[ d ].parent_cidx = fd_wksp_private_pinfo_cidx( FD_WKSP_PRIVATE_PINFO_IDX_NULL ); 368 167 : return FD_WKSP_SUCCESS; 369 155 : } 370 : 371 : #undef TEST_PARENT 372 : #undef TEST_AND_MARK 373 : #undef TEST