1 /* 2 * Copyright 2014-2015 Olivier Houchard. 3 * Copyright 2012-2015 Samy Al Bahra. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <ck_cc.h> 29 #include <ck_rhs.h> 30 #include <ck_limits.h> 31 #include <ck_md.h> 32 #include <ck_pr.h> 33 #include <ck_stdint.h> 34 #include <ck_stdbool.h> 35 #include <ck_string.h> 36 37 #include "ck_internal.h" 38 39 #ifndef CK_RHS_PROBE_L1_SHIFT 40 #define CK_RHS_PROBE_L1_SHIFT 3ULL 41 #endif /* CK_RHS_PROBE_L1_SHIFT */ 42 43 #define CK_RHS_PROBE_L1 (1 << CK_RHS_PROBE_L1_SHIFT) 44 #define CK_RHS_PROBE_L1_MASK (CK_RHS_PROBE_L1 - 1) 45 46 #ifndef CK_RHS_PROBE_L1_DEFAULT 47 #define CK_RHS_PROBE_L1_DEFAULT CK_MD_CACHELINE 48 #endif 49 50 #define CK_RHS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1)) 51 #define CK_RHS_VMA(x) \ 52 ((void *)((uintptr_t)(x) & CK_RHS_VMA_MASK)) 53 54 #define CK_RHS_EMPTY NULL 55 #define CK_RHS_G (1024) 56 #define CK_RHS_G_MASK (CK_RHS_G - 1) 57 58 #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8) 59 #define CK_RHS_WORD uint8_t 60 #define CK_RHS_WORD_MAX UINT8_MAX 61 #define CK_RHS_STORE(x, y) ck_pr_store_8(x, y) 62 #define CK_RHS_LOAD(x) ck_pr_load_8(x) 63 #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16) 64 #define CK_RHS_WORD uint16_t 65 #define CK_RHS_WORD_MAX UINT16_MAX 66 #define CK_RHS_STORE(x, y) ck_pr_store_16(x, y) 67 #define CK_RHS_LOAD(x) ck_pr_load_16(x) 68 #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32) 69 #define CK_RHS_WORD uint32_t 70 #define CK_RHS_WORD_MAX UINT32_MAX 71 #define CK_RHS_STORE(x, y) ck_pr_store_32(x, y) 72 #define CK_RHS_LOAD(x) ck_pr_load_32(x) 73 #else 74 #error "ck_rhs is not supported on your platform." 75 #endif 76 77 #define CK_RHS_MAX_WANTED 0xffff 78 79 enum ck_rhs_probe_behavior { 80 CK_RHS_PROBE = 0, /* Default behavior. */ 81 CK_RHS_PROBE_RH, /* Short-circuit if RH slot found. */ 82 CK_RHS_PROBE_INSERT, /* Short-circuit on probe bound if tombstone found. */ 83 84 CK_RHS_PROBE_ROBIN_HOOD,/* Look for the first slot available for the entry we are about to replace, only used to internally implement Robin Hood */ 85 CK_RHS_PROBE_NO_RH, /* Don't do the RH dance */ 86 }; 87 struct ck_rhs_entry_desc { 88 unsigned int probes; 89 unsigned short wanted; 90 CK_RHS_WORD probe_bound; 91 bool in_rh; 92 const void *entry; 93 } CK_CC_ALIGN(16); 94 95 struct ck_rhs_no_entry_desc { 96 unsigned int probes; 97 unsigned short wanted; 98 CK_RHS_WORD probe_bound; 99 bool in_rh; 100 } CK_CC_ALIGN(8); 101 102 typedef long ck_rhs_probe_cb_t(struct ck_rhs *hs, 103 struct ck_rhs_map *map, 104 unsigned long *n_probes, 105 long *priority, 106 unsigned long h, 107 const void *key, 108 const void **object, 109 unsigned long probe_limit, 110 enum ck_rhs_probe_behavior behavior); 111 112 struct ck_rhs_map { 113 unsigned int generation[CK_RHS_G]; 114 unsigned int probe_maximum; 115 unsigned long mask; 116 unsigned long step; 117 unsigned int probe_limit; 118 unsigned long n_entries; 119 unsigned long capacity; 120 unsigned long size; 121 unsigned long max_entries; 122 char offset_mask; 123 union { 124 struct ck_rhs_entry_desc *descs; 125 struct ck_rhs_no_entry { 126 const void **entries; 127 struct ck_rhs_no_entry_desc *descs; 128 } no_entries; 129 } entries; 130 bool read_mostly; 131 ck_rhs_probe_cb_t *probe_func; 132 }; 133 134 static CK_CC_INLINE const void * 135 ck_rhs_entry(struct ck_rhs_map *map, long offset) 136 { 137 138 if (map->read_mostly) 139 return (map->entries.no_entries.entries[offset]); 140 else 141 return (map->entries.descs[offset].entry); 142 } 143 144 static CK_CC_INLINE const void ** 145 ck_rhs_entry_addr(struct ck_rhs_map *map, long offset) 146 { 147 148 if (map->read_mostly) 149 return (&map->entries.no_entries.entries[offset]); 150 else 151 return (&map->entries.descs[offset].entry); 152 } 153 154 static CK_CC_INLINE struct ck_rhs_entry_desc * 155 ck_rhs_desc(struct ck_rhs_map *map, long offset) 156 { 157 158 if (CK_CC_UNLIKELY(map->read_mostly)) 159 return ((struct ck_rhs_entry_desc *)(void *)&map->entries.no_entries.descs[offset]); 160 else 161 return (&map->entries.descs[offset]); 162 } 163 164 static CK_CC_INLINE void 165 ck_rhs_wanted_inc(struct ck_rhs_map *map, long offset) 166 { 167 168 if (CK_CC_UNLIKELY(map->read_mostly)) 169 map->entries.no_entries.descs[offset].wanted++; 170 else 171 map->entries.descs[offset].wanted++; 172 } 173 174 static CK_CC_INLINE unsigned int 175 ck_rhs_probes(struct ck_rhs_map *map, long offset) 176 { 177 178 if (CK_CC_UNLIKELY(map->read_mostly)) 179 return (map->entries.no_entries.descs[offset].probes); 180 else 181 return (map->entries.descs[offset].probes); 182 } 183 184 static CK_CC_INLINE void 185 ck_rhs_set_probes(struct ck_rhs_map *map, long offset, unsigned int value) 186 { 187 188 if (CK_CC_UNLIKELY(map->read_mostly)) 189 map->entries.no_entries.descs[offset].probes = value; 190 else 191 map->entries.descs[offset].probes = value; 192 } 193 194 static CK_CC_INLINE CK_RHS_WORD 195 ck_rhs_probe_bound(struct ck_rhs_map *map, long offset) 196 { 197 198 if (CK_CC_UNLIKELY(map->read_mostly)) 199 return (map->entries.no_entries.descs[offset].probe_bound); 200 else 201 return (map->entries.descs[offset].probe_bound); 202 } 203 204 static CK_CC_INLINE CK_RHS_WORD * 205 ck_rhs_probe_bound_addr(struct ck_rhs_map *map, long offset) 206 { 207 208 if (CK_CC_UNLIKELY(map->read_mostly)) 209 return (&map->entries.no_entries.descs[offset].probe_bound); 210 else 211 return (&map->entries.descs[offset].probe_bound); 212 } 213 214 215 static CK_CC_INLINE bool 216 ck_rhs_in_rh(struct ck_rhs_map *map, long offset) 217 { 218 219 if (CK_CC_UNLIKELY(map->read_mostly)) 220 return (map->entries.no_entries.descs[offset].in_rh); 221 else 222 return (map->entries.descs[offset].in_rh); 223 } 224 225 static CK_CC_INLINE void 226 ck_rhs_set_rh(struct ck_rhs_map *map, long offset) 227 { 228 229 if (CK_CC_UNLIKELY(map->read_mostly)) 230 map->entries.no_entries.descs[offset].in_rh = true; 231 else 232 map->entries.descs[offset].in_rh = true; 233 } 234 235 static CK_CC_INLINE void 236 ck_rhs_unset_rh(struct ck_rhs_map *map, long offset) 237 { 238 239 if (CK_CC_UNLIKELY(map->read_mostly)) 240 map->entries.no_entries.descs[offset].in_rh = false; 241 else 242 map->entries.descs[offset].in_rh = false; 243 } 244 245 246 #define CK_RHS_DEFAULT_LOAD_FACTOR 50 247 248 static ck_rhs_probe_cb_t ck_rhs_map_probe; 249 static ck_rhs_probe_cb_t ck_rhs_map_probe_rm; 250 251 bool 252 ck_rhs_set_load_factor(struct ck_rhs *hs, unsigned int load_factor) 253 { 254 struct ck_rhs_map *map = hs->map; 255 256 if (load_factor == 0 || load_factor > 100) 257 return false; 258 259 hs->load_factor = load_factor; 260 map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100; 261 while (map->n_entries > map->max_entries) { 262 if (ck_rhs_grow(hs, map->capacity << 1) == false) 263 return false; 264 map = hs->map; 265 } 266 return true; 267 } 268 269 void 270 ck_rhs_iterator_init(struct ck_rhs_iterator *iterator) 271 { 272 273 iterator->cursor = NULL; 274 iterator->offset = 0; 275 return; 276 } 277 278 bool 279 ck_rhs_next(struct ck_rhs *hs, struct ck_rhs_iterator *i, void **key) 280 { 281 struct ck_rhs_map *map = hs->map; 282 void *value; 283 284 if (i->offset >= map->capacity) 285 return false; 286 287 do { 288 value = CK_CC_DECONST_PTR(ck_rhs_entry(map, i->offset)); 289 if (value != CK_RHS_EMPTY) { 290 #ifdef CK_RHS_PP 291 if (hs->mode & CK_RHS_MODE_OBJECT) 292 value = CK_RHS_VMA(value); 293 #endif 294 i->offset++; 295 *key = value; 296 return true; 297 } 298 } while (++i->offset < map->capacity); 299 300 return false; 301 } 302 303 void 304 ck_rhs_stat(struct ck_rhs *hs, struct ck_rhs_stat *st) 305 { 306 struct ck_rhs_map *map = hs->map; 307 308 st->n_entries = map->n_entries; 309 st->probe_maximum = map->probe_maximum; 310 return; 311 } 312 313 unsigned long 314 ck_rhs_count(struct ck_rhs *hs) 315 { 316 317 return hs->map->n_entries; 318 } 319 320 static void 321 ck_rhs_map_destroy(struct ck_malloc *m, struct ck_rhs_map *map, bool defer) 322 { 323 324 m->free(map, map->size, defer); 325 return; 326 } 327 328 void 329 ck_rhs_destroy(struct ck_rhs *hs) 330 { 331 332 ck_rhs_map_destroy(hs->m, hs->map, false); 333 return; 334 } 335 336 static struct ck_rhs_map * 337 ck_rhs_map_create(struct ck_rhs *hs, unsigned long entries) 338 { 339 struct ck_rhs_map *map; 340 unsigned long size, n_entries, limit; 341 342 n_entries = ck_internal_power_2(entries); 343 if (n_entries < CK_RHS_PROBE_L1) 344 n_entries = CK_RHS_PROBE_L1; 345 346 if (hs->mode & CK_RHS_MODE_READ_MOSTLY) 347 size = sizeof(struct ck_rhs_map) + 348 (sizeof(void *) * n_entries + 349 sizeof(struct ck_rhs_no_entry_desc) * n_entries + 350 2 * CK_MD_CACHELINE - 1); 351 else 352 size = sizeof(struct ck_rhs_map) + 353 (sizeof(struct ck_rhs_entry_desc) * n_entries + 354 CK_MD_CACHELINE - 1); 355 map = hs->m->malloc(size); 356 if (map == NULL) 357 return NULL; 358 map->read_mostly = !!(hs->mode & CK_RHS_MODE_READ_MOSTLY); 359 360 map->size = size; 361 /* We should probably use a more intelligent heuristic for default probe length. */ 362 limit = ck_internal_max(n_entries >> (CK_RHS_PROBE_L1_SHIFT + 2), CK_RHS_PROBE_L1_DEFAULT); 363 if (limit > UINT_MAX) 364 limit = UINT_MAX; 365 366 map->probe_limit = (unsigned int)limit; 367 map->probe_maximum = 0; 368 map->capacity = n_entries; 369 map->step = ck_internal_bsf(n_entries); 370 map->mask = n_entries - 1; 371 map->n_entries = 0; 372 373 map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100; 374 /* Align map allocation to cache line. */ 375 if (map->read_mostly) { 376 map->entries.no_entries.entries = (void *)(((uintptr_t)&map[1] + 377 CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); 378 map->entries.no_entries.descs = (void *)(((uintptr_t)map->entries.no_entries.entries + (sizeof(void *) * n_entries) + CK_MD_CACHELINE - 1) &~ (CK_MD_CACHELINE - 1)); 379 memset(map->entries.no_entries.entries, 0, 380 sizeof(void *) * n_entries); 381 memset(map->entries.no_entries.descs, 0, 382 sizeof(struct ck_rhs_no_entry_desc) * n_entries); 383 map->offset_mask = (CK_MD_CACHELINE / sizeof(void *)) - 1; 384 map->probe_func = ck_rhs_map_probe_rm; 385 386 } else { 387 map->entries.descs = (void *)(((uintptr_t)&map[1] + 388 CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); 389 memset(map->entries.descs, 0, sizeof(struct ck_rhs_entry_desc) * n_entries); 390 map->offset_mask = (CK_MD_CACHELINE / sizeof(struct ck_rhs_entry_desc)) - 1; 391 map->probe_func = ck_rhs_map_probe; 392 } 393 memset(map->generation, 0, sizeof map->generation); 394 395 /* Commit entries purge with respect to map publication. */ 396 ck_pr_fence_store(); 397 return map; 398 } 399 400 bool 401 ck_rhs_reset_size(struct ck_rhs *hs, unsigned long capacity) 402 { 403 struct ck_rhs_map *map, *previous; 404 405 previous = hs->map; 406 map = ck_rhs_map_create(hs, capacity); 407 if (map == NULL) 408 return false; 409 410 ck_pr_store_ptr(&hs->map, map); 411 ck_rhs_map_destroy(hs->m, previous, true); 412 return true; 413 } 414 415 bool 416 ck_rhs_reset(struct ck_rhs *hs) 417 { 418 struct ck_rhs_map *previous; 419 420 previous = hs->map; 421 return ck_rhs_reset_size(hs, previous->capacity); 422 } 423 424 static inline unsigned long 425 ck_rhs_map_probe_next(struct ck_rhs_map *map, 426 unsigned long offset, 427 unsigned long probes) 428 { 429 430 if (probes & map->offset_mask) { 431 offset = (offset &~ map->offset_mask) + 432 ((offset + 1) & map->offset_mask); 433 return offset; 434 } else 435 return (offset + probes) & map->mask; 436 } 437 438 static inline unsigned long 439 ck_rhs_map_probe_prev(struct ck_rhs_map *map, unsigned long offset, 440 unsigned long probes) 441 { 442 443 if (probes & map->offset_mask) { 444 offset = (offset &~ map->offset_mask) + ((offset - 1) & 445 map->offset_mask); 446 return offset; 447 } else 448 return ((offset - probes) & map->mask); 449 } 450 451 452 static inline void 453 ck_rhs_map_bound_set(struct ck_rhs_map *m, 454 unsigned long h, 455 unsigned long n_probes) 456 { 457 unsigned long offset = h & m->mask; 458 struct ck_rhs_entry_desc *desc; 459 460 if (n_probes > m->probe_maximum) 461 ck_pr_store_uint(&m->probe_maximum, n_probes); 462 if (!(m->read_mostly)) { 463 desc = &m->entries.descs[offset]; 464 465 if (desc->probe_bound < n_probes) { 466 if (n_probes > CK_RHS_WORD_MAX) 467 n_probes = CK_RHS_WORD_MAX; 468 469 CK_RHS_STORE(&desc->probe_bound, n_probes); 470 ck_pr_fence_store(); 471 } 472 } 473 474 return; 475 } 476 477 static inline unsigned int 478 ck_rhs_map_bound_get(struct ck_rhs_map *m, unsigned long h) 479 { 480 unsigned long offset = h & m->mask; 481 unsigned int r = CK_RHS_WORD_MAX; 482 483 if (m->read_mostly) 484 r = ck_pr_load_uint(&m->probe_maximum); 485 else { 486 r = CK_RHS_LOAD(&m->entries.descs[offset].probe_bound); 487 if (r == CK_RHS_WORD_MAX) 488 r = ck_pr_load_uint(&m->probe_maximum); 489 } 490 return r; 491 } 492 493 bool 494 ck_rhs_grow(struct ck_rhs *hs, 495 unsigned long capacity) 496 { 497 struct ck_rhs_map *map, *update; 498 const void *previous, *prev_saved; 499 unsigned long k, offset, probes; 500 501 restart: 502 map = hs->map; 503 if (map->capacity > capacity) 504 return false; 505 506 update = ck_rhs_map_create(hs, capacity); 507 if (update == NULL) 508 return false; 509 510 for (k = 0; k < map->capacity; k++) { 511 unsigned long h; 512 513 prev_saved = previous = ck_rhs_entry(map, k); 514 if (previous == CK_RHS_EMPTY) 515 continue; 516 517 #ifdef CK_RHS_PP 518 if (hs->mode & CK_RHS_MODE_OBJECT) 519 previous = CK_RHS_VMA(previous); 520 #endif 521 522 h = hs->hf(previous, hs->seed); 523 offset = h & update->mask; 524 probes = 0; 525 526 for (;;) { 527 const void **cursor = ck_rhs_entry_addr(update, offset); 528 529 if (probes++ == update->probe_limit) { 530 /* 531 * We have hit the probe limit, map needs to be even larger. 532 */ 533 ck_rhs_map_destroy(hs->m, update, false); 534 capacity <<= 1; 535 goto restart; 536 } 537 538 if (CK_CC_LIKELY(*cursor == CK_RHS_EMPTY)) { 539 *cursor = prev_saved; 540 update->n_entries++; 541 ck_rhs_set_probes(update, offset, probes); 542 ck_rhs_map_bound_set(update, h, probes); 543 break; 544 } else if (ck_rhs_probes(update, offset) < probes) { 545 const void *tmp = prev_saved; 546 unsigned int old_probes; 547 prev_saved = previous = *cursor; 548 #ifdef CK_RHS_PP 549 if (hs->mode & CK_RHS_MODE_OBJECT) 550 previous = CK_RHS_VMA(previous); 551 #endif 552 *cursor = tmp; 553 ck_rhs_map_bound_set(update, h, probes); 554 h = hs->hf(previous, hs->seed); 555 old_probes = ck_rhs_probes(update, offset); 556 ck_rhs_set_probes(update, offset, probes); 557 probes = old_probes - 1; 558 continue; 559 } 560 ck_rhs_wanted_inc(update, offset); 561 offset = ck_rhs_map_probe_next(update, offset, probes); 562 } 563 564 } 565 566 ck_pr_fence_store(); 567 ck_pr_store_ptr(&hs->map, update); 568 ck_rhs_map_destroy(hs->m, map, true); 569 return true; 570 } 571 572 bool 573 ck_rhs_rebuild(struct ck_rhs *hs) 574 { 575 576 return ck_rhs_grow(hs, hs->map->capacity); 577 } 578 579 static long 580 ck_rhs_map_probe_rm(struct ck_rhs *hs, 581 struct ck_rhs_map *map, 582 unsigned long *n_probes, 583 long *priority, 584 unsigned long h, 585 const void *key, 586 const void **object, 587 unsigned long probe_limit, 588 enum ck_rhs_probe_behavior behavior) 589 { 590 const void *k; 591 const void *compare; 592 long pr = -1; 593 unsigned long offset, probes, opl; 594 595 #ifdef CK_RHS_PP 596 /* If we are storing object pointers, then we may leverage pointer packing. */ 597 unsigned long hv = 0; 598 599 if (hs->mode & CK_RHS_MODE_OBJECT) { 600 hv = (h >> 25) & CK_RHS_KEY_MASK; 601 compare = CK_RHS_VMA(key); 602 } else { 603 compare = key; 604 } 605 #else 606 compare = key; 607 #endif 608 *object = NULL; 609 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { 610 probes = 0; 611 offset = h & map->mask; 612 } else { 613 /* Restart from the bucket we were previously in */ 614 probes = *n_probes; 615 offset = ck_rhs_map_probe_next(map, *priority, 616 probes); 617 } 618 opl = probe_limit; 619 620 for (;;) { 621 if (probes++ == probe_limit) { 622 if (probe_limit == opl || pr != -1) { 623 k = CK_RHS_EMPTY; 624 goto leave; 625 } 626 /* 627 * If no eligible slot has been found yet, continue probe 628 * sequence with original probe limit. 629 */ 630 probe_limit = opl; 631 } 632 k = ck_pr_load_ptr(&map->entries.no_entries.entries[offset]); 633 if (k == CK_RHS_EMPTY) 634 goto leave; 635 636 if (behavior != CK_RHS_PROBE_NO_RH) { 637 struct ck_rhs_entry_desc *desc = (void *)&map->entries.no_entries.descs[offset]; 638 639 if (pr == -1 && 640 desc->in_rh == false && desc->probes < probes) { 641 pr = offset; 642 *n_probes = probes; 643 644 if (behavior == CK_RHS_PROBE_RH || 645 behavior == CK_RHS_PROBE_ROBIN_HOOD) { 646 k = CK_RHS_EMPTY; 647 goto leave; 648 } 649 } 650 } 651 652 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { 653 #ifdef CK_RHS_PP 654 if (hs->mode & CK_RHS_MODE_OBJECT) { 655 if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) { 656 offset = ck_rhs_map_probe_next(map, offset, probes); 657 continue; 658 } 659 660 k = CK_RHS_VMA(k); 661 } 662 #endif 663 664 if (k == compare) 665 goto leave; 666 667 if (hs->compare == NULL) { 668 offset = ck_rhs_map_probe_next(map, offset, probes); 669 continue; 670 } 671 672 if (hs->compare(k, key) == true) 673 goto leave; 674 } 675 offset = ck_rhs_map_probe_next(map, offset, probes); 676 } 677 leave: 678 if (probes > probe_limit) { 679 offset = -1; 680 } else { 681 *object = k; 682 } 683 684 if (pr == -1) 685 *n_probes = probes; 686 687 *priority = pr; 688 return offset; 689 } 690 691 static long 692 ck_rhs_map_probe(struct ck_rhs *hs, 693 struct ck_rhs_map *map, 694 unsigned long *n_probes, 695 long *priority, 696 unsigned long h, 697 const void *key, 698 const void **object, 699 unsigned long probe_limit, 700 enum ck_rhs_probe_behavior behavior) 701 { 702 const void *k; 703 const void *compare; 704 long pr = -1; 705 unsigned long offset, probes, opl; 706 707 #ifdef CK_RHS_PP 708 /* If we are storing object pointers, then we may leverage pointer packing. */ 709 unsigned long hv = 0; 710 711 if (hs->mode & CK_RHS_MODE_OBJECT) { 712 hv = (h >> 25) & CK_RHS_KEY_MASK; 713 compare = CK_RHS_VMA(key); 714 } else { 715 compare = key; 716 } 717 #else 718 compare = key; 719 #endif 720 721 *object = NULL; 722 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { 723 probes = 0; 724 offset = h & map->mask; 725 } else { 726 /* Restart from the bucket we were previously in */ 727 probes = *n_probes; 728 offset = ck_rhs_map_probe_next(map, *priority, 729 probes); 730 } 731 opl = probe_limit; 732 if (behavior == CK_RHS_PROBE_INSERT) 733 probe_limit = ck_rhs_map_bound_get(map, h); 734 735 for (;;) { 736 if (probes++ == probe_limit) { 737 if (probe_limit == opl || pr != -1) { 738 k = CK_RHS_EMPTY; 739 goto leave; 740 } 741 /* 742 * If no eligible slot has been found yet, continue probe 743 * sequence with original probe limit. 744 */ 745 probe_limit = opl; 746 } 747 k = ck_pr_load_ptr(&map->entries.descs[offset].entry); 748 if (k == CK_RHS_EMPTY) 749 goto leave; 750 if ((behavior != CK_RHS_PROBE_NO_RH)) { 751 struct ck_rhs_entry_desc *desc = &map->entries.descs[offset]; 752 753 if (pr == -1 && 754 desc->in_rh == false && desc->probes < probes) { 755 pr = offset; 756 *n_probes = probes; 757 758 if (behavior == CK_RHS_PROBE_RH || 759 behavior == CK_RHS_PROBE_ROBIN_HOOD) { 760 k = CK_RHS_EMPTY; 761 goto leave; 762 } 763 } 764 } 765 766 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { 767 #ifdef CK_RHS_PP 768 if (hs->mode & CK_RHS_MODE_OBJECT) { 769 if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) { 770 offset = ck_rhs_map_probe_next(map, offset, probes); 771 continue; 772 } 773 774 k = CK_RHS_VMA(k); 775 } 776 #endif 777 778 if (k == compare) 779 goto leave; 780 781 if (hs->compare == NULL) { 782 offset = ck_rhs_map_probe_next(map, offset, probes); 783 continue; 784 } 785 786 if (hs->compare(k, key) == true) 787 goto leave; 788 } 789 offset = ck_rhs_map_probe_next(map, offset, probes); 790 } 791 leave: 792 if (probes > probe_limit) { 793 offset = -1; 794 } else { 795 *object = k; 796 } 797 798 if (pr == -1) 799 *n_probes = probes; 800 801 *priority = pr; 802 return offset; 803 } 804 805 static inline const void * 806 ck_rhs_marshal(unsigned int mode, const void *key, unsigned long h) 807 { 808 #ifdef CK_RHS_PP 809 const void *insert; 810 811 if (mode & CK_RHS_MODE_OBJECT) { 812 insert = (void *)((uintptr_t)CK_RHS_VMA(key) | ((h >> 25) << CK_MD_VMA_BITS)); 813 } else { 814 insert = key; 815 } 816 817 return insert; 818 #else 819 (void)mode; 820 (void)h; 821 822 return key; 823 #endif 824 } 825 826 bool 827 ck_rhs_gc(struct ck_rhs *hs) 828 { 829 unsigned long i; 830 struct ck_rhs_map *map = hs->map; 831 832 unsigned int max_probes = 0; 833 for (i = 0; i < map->capacity; i++) { 834 if (ck_rhs_probes(map, i) > max_probes) 835 max_probes = ck_rhs_probes(map, i); 836 } 837 map->probe_maximum = max_probes; 838 return true; 839 } 840 841 static void 842 ck_rhs_add_wanted(struct ck_rhs *hs, long end_offset, long old_slot, 843 unsigned long h) 844 { 845 struct ck_rhs_map *map = hs->map; 846 long offset; 847 unsigned int probes = 1; 848 bool found_slot = false; 849 struct ck_rhs_entry_desc *desc; 850 851 offset = h & map->mask; 852 853 if (old_slot == -1) 854 found_slot = true; 855 while (offset != end_offset) { 856 if (offset == old_slot) 857 found_slot = true; 858 if (found_slot) { 859 desc = ck_rhs_desc(map, offset); 860 if (desc->wanted < CK_RHS_MAX_WANTED) 861 desc->wanted++; 862 } 863 offset = ck_rhs_map_probe_next(map, offset, probes); 864 probes++; 865 } 866 } 867 868 static unsigned long 869 ck_rhs_remove_wanted(struct ck_rhs *hs, long offset, long limit) 870 { 871 struct ck_rhs_map *map = hs->map; 872 int probes = ck_rhs_probes(map, offset); 873 bool do_remove = true; 874 struct ck_rhs_entry_desc *desc; 875 876 while (probes > 1) { 877 probes--; 878 offset = ck_rhs_map_probe_prev(map, offset, probes); 879 if (offset == limit) 880 do_remove = false; 881 if (do_remove) { 882 desc = ck_rhs_desc(map, offset); 883 if (desc->wanted != CK_RHS_MAX_WANTED) 884 desc->wanted--; 885 } 886 } 887 return offset; 888 } 889 890 static long 891 ck_rhs_get_first_offset(struct ck_rhs_map *map, unsigned long offset, unsigned int probes) 892 { 893 while (probes > (unsigned long)map->offset_mask + 1) { 894 offset -= ((probes - 1) &~ map->offset_mask); 895 offset &= map->mask; 896 offset = (offset &~ map->offset_mask) + 897 ((offset - map->offset_mask) & map->offset_mask); 898 probes -= map->offset_mask + 1; 899 } 900 return ((offset &~ map->offset_mask) + ((offset - (probes - 1)) & map->offset_mask)); 901 } 902 903 #define CK_RHS_MAX_RH 512 904 905 static int 906 ck_rhs_put_robin_hood(struct ck_rhs *hs, 907 long orig_slot, struct ck_rhs_entry_desc *desc) 908 { 909 long slot, first; 910 const void *object, *insert; 911 unsigned long n_probes; 912 struct ck_rhs_map *map; 913 unsigned long h = 0; 914 long prev; 915 void *key; 916 long prevs[CK_RHS_MAX_RH]; 917 unsigned int prevs_nb = 0; 918 unsigned int i; 919 920 map = hs->map; 921 first = orig_slot; 922 n_probes = desc->probes; 923 restart: 924 key = CK_CC_DECONST_PTR(ck_rhs_entry(map, first)); 925 insert = key; 926 #ifdef CK_RHS_PP 927 if (hs->mode & CK_RHS_MODE_OBJECT) 928 key = CK_RHS_VMA(key); 929 #endif 930 orig_slot = first; 931 ck_rhs_set_rh(map, orig_slot); 932 933 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, 934 map->probe_limit, prevs_nb == CK_RHS_MAX_RH ? 935 CK_RHS_PROBE_NO_RH : CK_RHS_PROBE_ROBIN_HOOD); 936 937 if (slot == -1 && first == -1) { 938 if (ck_rhs_grow(hs, map->capacity << 1) == false) { 939 desc->in_rh = false; 940 941 for (i = 0; i < prevs_nb; i++) 942 ck_rhs_unset_rh(map, prevs[i]); 943 944 return -1; 945 } 946 947 return 1; 948 } 949 950 if (first != -1) { 951 desc = ck_rhs_desc(map, first); 952 int old_probes = desc->probes; 953 954 desc->probes = n_probes; 955 h = ck_rhs_get_first_offset(map, first, n_probes); 956 ck_rhs_map_bound_set(map, h, n_probes); 957 prev = orig_slot; 958 prevs[prevs_nb++] = prev; 959 n_probes = old_probes; 960 goto restart; 961 } else { 962 /* An empty slot was found. */ 963 h = ck_rhs_get_first_offset(map, slot, n_probes); 964 ck_rhs_map_bound_set(map, h, n_probes); 965 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); 966 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 967 ck_pr_fence_atomic_store(); 968 ck_rhs_set_probes(map, slot, n_probes); 969 desc->in_rh = 0; 970 ck_rhs_add_wanted(hs, slot, orig_slot, h); 971 } 972 while (prevs_nb > 0) { 973 prev = prevs[--prevs_nb]; 974 ck_pr_store_ptr(ck_rhs_entry_addr(map, orig_slot), 975 ck_rhs_entry(map, prev)); 976 h = ck_rhs_get_first_offset(map, orig_slot, 977 desc->probes); 978 ck_rhs_add_wanted(hs, orig_slot, prev, h); 979 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 980 ck_pr_fence_atomic_store(); 981 orig_slot = prev; 982 desc->in_rh = false; 983 desc = ck_rhs_desc(map, orig_slot); 984 } 985 return 0; 986 } 987 988 static void 989 ck_rhs_do_backward_shift_delete(struct ck_rhs *hs, long slot) 990 { 991 struct ck_rhs_map *map = hs->map; 992 struct ck_rhs_entry_desc *desc, *new_desc = NULL; 993 unsigned long h; 994 995 desc = ck_rhs_desc(map, slot); 996 h = ck_rhs_remove_wanted(hs, slot, -1); 997 while (desc->wanted > 0) { 998 unsigned long offset = 0, tmp_offset; 999 unsigned long wanted_probes = 1; 1000 unsigned int probe = 0; 1001 unsigned int max_probes; 1002 1003 /* Find a successor */ 1004 while (wanted_probes < map->probe_maximum) { 1005 probe = wanted_probes; 1006 offset = ck_rhs_map_probe_next(map, slot, probe); 1007 while (probe < map->probe_maximum) { 1008 new_desc = ck_rhs_desc(map, offset); 1009 if (new_desc->probes == probe + 1) 1010 break; 1011 probe++; 1012 offset = ck_rhs_map_probe_next(map, offset, 1013 probe); 1014 } 1015 if (probe < map->probe_maximum) 1016 break; 1017 wanted_probes++; 1018 } 1019 if (!(wanted_probes < map->probe_maximum)) { 1020 desc->wanted = 0; 1021 break; 1022 } 1023 desc->probes = wanted_probes; 1024 h = ck_rhs_remove_wanted(hs, offset, slot); 1025 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), 1026 ck_rhs_entry(map, offset)); 1027 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 1028 ck_pr_fence_atomic_store(); 1029 if (wanted_probes < CK_RHS_WORD_MAX) { 1030 struct ck_rhs_entry_desc *hdesc = ck_rhs_desc(map, h); 1031 if (hdesc->wanted == 1) 1032 CK_RHS_STORE(&hdesc->probe_bound, 1033 wanted_probes); 1034 else if (hdesc->probe_bound == CK_RHS_WORD_MAX || 1035 hdesc->probe_bound == new_desc->probes) { 1036 probe++; 1037 if (hdesc->probe_bound == CK_RHS_WORD_MAX) 1038 max_probes = map->probe_maximum; 1039 else { 1040 max_probes = hdesc->probe_bound; 1041 max_probes--; 1042 } 1043 tmp_offset = ck_rhs_map_probe_next(map, offset, 1044 probe); 1045 while (probe < max_probes) { 1046 if (h == (unsigned long)ck_rhs_get_first_offset(map, tmp_offset, probe)) 1047 break; 1048 probe++; 1049 tmp_offset = ck_rhs_map_probe_next(map, tmp_offset, probe); 1050 } 1051 if (probe == max_probes) 1052 CK_RHS_STORE(&hdesc->probe_bound, 1053 wanted_probes); 1054 } 1055 } 1056 if (desc->wanted < CK_RHS_MAX_WANTED) 1057 desc->wanted--; 1058 slot = offset; 1059 desc = new_desc; 1060 } 1061 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), CK_RHS_EMPTY); 1062 if ((desc->probes - 1) < CK_RHS_WORD_MAX) 1063 CK_RHS_STORE(ck_rhs_probe_bound_addr(map, h), 1064 desc->probes - 1); 1065 desc->probes = 0; 1066 } 1067 1068 bool 1069 ck_rhs_fas(struct ck_rhs *hs, 1070 unsigned long h, 1071 const void *key, 1072 void **previous) 1073 { 1074 long slot, first; 1075 const void *object; 1076 const void *insert; 1077 unsigned long n_probes; 1078 struct ck_rhs_map *map = hs->map; 1079 struct ck_rhs_entry_desc *desc, *desc2; 1080 1081 *previous = NULL; 1082 restart: 1083 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, 1084 ck_rhs_map_bound_get(map, h), CK_RHS_PROBE); 1085 1086 /* Replacement semantics presume existence. */ 1087 if (object == NULL) 1088 return false; 1089 1090 insert = ck_rhs_marshal(hs->mode, key, h); 1091 1092 if (first != -1) { 1093 int ret; 1094 1095 desc = ck_rhs_desc(map, slot); 1096 desc2 = ck_rhs_desc(map, first); 1097 desc->in_rh = true; 1098 ret = ck_rhs_put_robin_hood(hs, first, desc2); 1099 desc->in_rh = false; 1100 if (CK_CC_UNLIKELY(ret == 1)) 1101 goto restart; 1102 else if (CK_CC_UNLIKELY(ret != 0)) 1103 return false; 1104 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); 1105 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 1106 ck_pr_fence_atomic_store(); 1107 desc2->probes = n_probes; 1108 ck_rhs_add_wanted(hs, first, -1, h); 1109 ck_rhs_do_backward_shift_delete(hs, slot); 1110 } else { 1111 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); 1112 ck_rhs_set_probes(map, slot, n_probes); 1113 } 1114 *previous = CK_CC_DECONST_PTR(object); 1115 return true; 1116 } 1117 1118 /* 1119 * An apply function takes two arguments. The first argument is a pointer to a 1120 * pre-existing object. The second argument is a pointer to the fifth argument 1121 * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument 1122 * and the return value of the apply function is NULL, then the pre-existing 1123 * value is deleted. If the return pointer is the same as the one passed to the 1124 * apply function then no changes are made to the hash table. If the first 1125 * argument is non-NULL and the return pointer is different than that passed to 1126 * the apply function, then the pre-existing value is replaced. For 1127 * replacement, it is required that the value itself is identical to the 1128 * previous value. 1129 */ 1130 bool 1131 ck_rhs_apply(struct ck_rhs *hs, 1132 unsigned long h, 1133 const void *key, 1134 ck_rhs_apply_fn_t *fn, 1135 void *cl) 1136 { 1137 const void *insert; 1138 const void *object, *delta = false; 1139 unsigned long n_probes; 1140 long slot, first; 1141 struct ck_rhs_map *map; 1142 bool delta_set = false; 1143 1144 restart: 1145 map = hs->map; 1146 1147 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT); 1148 if (slot == -1 && first == -1) { 1149 if (ck_rhs_grow(hs, map->capacity << 1) == false) 1150 return false; 1151 1152 goto restart; 1153 } 1154 if (!delta_set) { 1155 delta = fn(CK_CC_DECONST_PTR(object), cl); 1156 delta_set = true; 1157 } 1158 1159 if (delta == NULL) { 1160 /* 1161 * The apply function has requested deletion. If the object doesn't exist, 1162 * then exit early. 1163 */ 1164 if (CK_CC_UNLIKELY(object == NULL)) 1165 return true; 1166 1167 /* Otherwise, delete it. */ 1168 ck_rhs_do_backward_shift_delete(hs, slot); 1169 return true; 1170 } 1171 1172 /* The apply function has not requested hash set modification so exit early. */ 1173 if (delta == object) 1174 return true; 1175 1176 /* A modification or insertion has been requested. */ 1177 ck_rhs_map_bound_set(map, h, n_probes); 1178 1179 insert = ck_rhs_marshal(hs->mode, delta, h); 1180 if (first != -1) { 1181 /* 1182 * This follows the same semantics as ck_hs_set, please refer to that 1183 * function for documentation. 1184 */ 1185 struct ck_rhs_entry_desc *desc = NULL, *desc2; 1186 if (slot != -1) { 1187 desc = ck_rhs_desc(map, slot); 1188 desc->in_rh = true; 1189 } 1190 desc2 = ck_rhs_desc(map, first); 1191 int ret = ck_rhs_put_robin_hood(hs, first, desc2); 1192 if (slot != -1) 1193 desc->in_rh = false; 1194 1195 if (CK_CC_UNLIKELY(ret == 1)) 1196 goto restart; 1197 if (CK_CC_UNLIKELY(ret == -1)) 1198 return false; 1199 /* If an earlier bucket was found, then store entry there. */ 1200 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); 1201 desc2->probes = n_probes; 1202 /* 1203 * If a duplicate key was found, then delete it after 1204 * signaling concurrent probes to restart. Optionally, 1205 * it is possible to install tombstone after grace 1206 * period if we can guarantee earlier position of 1207 * duplicate key. 1208 */ 1209 ck_rhs_add_wanted(hs, first, -1, h); 1210 if (object != NULL) { 1211 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 1212 ck_pr_fence_atomic_store(); 1213 ck_rhs_do_backward_shift_delete(hs, slot); 1214 } 1215 } else { 1216 /* 1217 * If we are storing into same slot, then atomic store is sufficient 1218 * for replacement. 1219 */ 1220 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); 1221 ck_rhs_set_probes(map, slot, n_probes); 1222 if (object == NULL) 1223 ck_rhs_add_wanted(hs, slot, -1, h); 1224 } 1225 1226 if (object == NULL) { 1227 map->n_entries++; 1228 if ((map->n_entries ) > map->max_entries) 1229 ck_rhs_grow(hs, map->capacity << 1); 1230 } 1231 return true; 1232 } 1233 1234 bool 1235 ck_rhs_set(struct ck_rhs *hs, 1236 unsigned long h, 1237 const void *key, 1238 void **previous) 1239 { 1240 long slot, first; 1241 const void *object; 1242 const void *insert; 1243 unsigned long n_probes; 1244 struct ck_rhs_map *map; 1245 1246 *previous = NULL; 1247 1248 restart: 1249 map = hs->map; 1250 1251 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT); 1252 if (slot == -1 && first == -1) { 1253 if (ck_rhs_grow(hs, map->capacity << 1) == false) 1254 return false; 1255 1256 goto restart; 1257 } 1258 ck_rhs_map_bound_set(map, h, n_probes); 1259 insert = ck_rhs_marshal(hs->mode, key, h); 1260 1261 if (first != -1) { 1262 struct ck_rhs_entry_desc *desc = NULL, *desc2; 1263 if (slot != -1) { 1264 desc = ck_rhs_desc(map, slot); 1265 desc->in_rh = true; 1266 } 1267 desc2 = ck_rhs_desc(map, first); 1268 int ret = ck_rhs_put_robin_hood(hs, first, desc2); 1269 if (slot != -1) 1270 desc->in_rh = false; 1271 1272 if (CK_CC_UNLIKELY(ret == 1)) 1273 goto restart; 1274 if (CK_CC_UNLIKELY(ret == -1)) 1275 return false; 1276 /* If an earlier bucket was found, then store entry there. */ 1277 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); 1278 desc2->probes = n_probes; 1279 /* 1280 * If a duplicate key was found, then delete it after 1281 * signaling concurrent probes to restart. Optionally, 1282 * it is possible to install tombstone after grace 1283 * period if we can guarantee earlier position of 1284 * duplicate key. 1285 */ 1286 ck_rhs_add_wanted(hs, first, -1, h); 1287 if (object != NULL) { 1288 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); 1289 ck_pr_fence_atomic_store(); 1290 ck_rhs_do_backward_shift_delete(hs, slot); 1291 } 1292 1293 } else { 1294 /* 1295 * If we are storing into same slot, then atomic store is sufficient 1296 * for replacement. 1297 */ 1298 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); 1299 ck_rhs_set_probes(map, slot, n_probes); 1300 if (object == NULL) 1301 ck_rhs_add_wanted(hs, slot, -1, h); 1302 } 1303 1304 if (object == NULL) { 1305 map->n_entries++; 1306 if ((map->n_entries ) > map->max_entries) 1307 ck_rhs_grow(hs, map->capacity << 1); 1308 } 1309 1310 *previous = CK_CC_DECONST_PTR(object); 1311 return true; 1312 } 1313 1314 static bool 1315 ck_rhs_put_internal(struct ck_rhs *hs, 1316 unsigned long h, 1317 const void *key, 1318 enum ck_rhs_probe_behavior behavior) 1319 { 1320 long slot, first; 1321 const void *object; 1322 const void *insert; 1323 unsigned long n_probes; 1324 struct ck_rhs_map *map; 1325 1326 restart: 1327 map = hs->map; 1328 1329 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, 1330 map->probe_limit, behavior); 1331 1332 if (slot == -1 && first == -1) { 1333 if (ck_rhs_grow(hs, map->capacity << 1) == false) 1334 return false; 1335 1336 goto restart; 1337 } 1338 1339 /* Fail operation if a match was found. */ 1340 if (object != NULL) 1341 return false; 1342 1343 ck_rhs_map_bound_set(map, h, n_probes); 1344 insert = ck_rhs_marshal(hs->mode, key, h); 1345 1346 if (first != -1) { 1347 struct ck_rhs_entry_desc *desc = ck_rhs_desc(map, first); 1348 int ret = ck_rhs_put_robin_hood(hs, first, desc); 1349 if (CK_CC_UNLIKELY(ret == 1)) 1350 return ck_rhs_put_internal(hs, h, key, behavior); 1351 else if (CK_CC_UNLIKELY(ret == -1)) 1352 return false; 1353 /* Insert key into first bucket in probe sequence. */ 1354 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); 1355 desc->probes = n_probes; 1356 ck_rhs_add_wanted(hs, first, -1, h); 1357 } else { 1358 /* An empty slot was found. */ 1359 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); 1360 ck_rhs_set_probes(map, slot, n_probes); 1361 ck_rhs_add_wanted(hs, slot, -1, h); 1362 } 1363 1364 map->n_entries++; 1365 if ((map->n_entries ) > map->max_entries) 1366 ck_rhs_grow(hs, map->capacity << 1); 1367 return true; 1368 } 1369 1370 bool 1371 ck_rhs_put(struct ck_rhs *hs, 1372 unsigned long h, 1373 const void *key) 1374 { 1375 1376 return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_INSERT); 1377 } 1378 1379 bool 1380 ck_rhs_put_unique(struct ck_rhs *hs, 1381 unsigned long h, 1382 const void *key) 1383 { 1384 1385 return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_RH); 1386 } 1387 1388 void * 1389 ck_rhs_get(struct ck_rhs *hs, 1390 unsigned long h, 1391 const void *key) 1392 { 1393 long first; 1394 const void *object; 1395 struct ck_rhs_map *map; 1396 unsigned long n_probes; 1397 unsigned int g, g_p, probe; 1398 unsigned int *generation; 1399 1400 do { 1401 map = ck_pr_load_ptr(&hs->map); 1402 generation = &map->generation[h & CK_RHS_G_MASK]; 1403 g = ck_pr_load_uint(generation); 1404 probe = ck_rhs_map_bound_get(map, h); 1405 ck_pr_fence_load(); 1406 1407 first = -1; 1408 map->probe_func(hs, map, &n_probes, &first, h, key, &object, probe, CK_RHS_PROBE_NO_RH); 1409 1410 ck_pr_fence_load(); 1411 g_p = ck_pr_load_uint(generation); 1412 } while (g != g_p); 1413 1414 return CK_CC_DECONST_PTR(object); 1415 } 1416 1417 void * 1418 ck_rhs_remove(struct ck_rhs *hs, 1419 unsigned long h, 1420 const void *key) 1421 { 1422 long slot, first; 1423 const void *object; 1424 struct ck_rhs_map *map = hs->map; 1425 unsigned long n_probes; 1426 1427 slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, 1428 ck_rhs_map_bound_get(map, h), CK_RHS_PROBE_NO_RH); 1429 if (object == NULL) 1430 return NULL; 1431 1432 map->n_entries--; 1433 ck_rhs_do_backward_shift_delete(hs, slot); 1434 return CK_CC_DECONST_PTR(object); 1435 } 1436 1437 bool 1438 ck_rhs_move(struct ck_rhs *hs, 1439 struct ck_rhs *source, 1440 ck_rhs_hash_cb_t *hf, 1441 ck_rhs_compare_cb_t *compare, 1442 struct ck_malloc *m) 1443 { 1444 1445 if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) 1446 return false; 1447 1448 hs->mode = source->mode; 1449 hs->seed = source->seed; 1450 hs->map = source->map; 1451 hs->load_factor = source->load_factor; 1452 hs->m = m; 1453 hs->hf = hf; 1454 hs->compare = compare; 1455 return true; 1456 } 1457 1458 bool 1459 ck_rhs_init(struct ck_rhs *hs, 1460 unsigned int mode, 1461 ck_rhs_hash_cb_t *hf, 1462 ck_rhs_compare_cb_t *compare, 1463 struct ck_malloc *m, 1464 unsigned long n_entries, 1465 unsigned long seed) 1466 { 1467 1468 if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) 1469 return false; 1470 1471 hs->m = m; 1472 hs->mode = mode; 1473 hs->seed = seed; 1474 hs->hf = hf; 1475 hs->compare = compare; 1476 hs->load_factor = CK_RHS_DEFAULT_LOAD_FACTOR; 1477 1478 hs->map = ck_rhs_map_create(hs, n_entries); 1479 return hs->map != NULL; 1480 } 1481