1*8e33eff8Schristos /* 2*8e33eff8Schristos ******************************************************************************* 3*8e33eff8Schristos * Implementation of (2^1+,2) cuckoo hashing, where 2^1+ indicates that each 4*8e33eff8Schristos * hash bucket contains 2^n cells, for n >= 1, and 2 indicates that two hash 5*8e33eff8Schristos * functions are employed. The original cuckoo hashing algorithm was described 6*8e33eff8Schristos * in: 7*8e33eff8Schristos * 8*8e33eff8Schristos * Pagh, R., F.F. Rodler (2004) Cuckoo Hashing. Journal of Algorithms 9*8e33eff8Schristos * 51(2):122-144. 10*8e33eff8Schristos * 11*8e33eff8Schristos * Generalization of cuckoo hashing was discussed in: 12*8e33eff8Schristos * 13*8e33eff8Schristos * Erlingsson, U., M. Manasse, F. McSherry (2006) A cool and practical 14*8e33eff8Schristos * alternative to traditional hash tables. In Proceedings of the 7th 15*8e33eff8Schristos * Workshop on Distributed Data and Structures (WDAS'06), Santa Clara, CA, 16*8e33eff8Schristos * January 2006. 17*8e33eff8Schristos * 18*8e33eff8Schristos * This implementation uses precisely two hash functions because that is the 19*8e33eff8Schristos * fewest that can work, and supporting multiple hashes is an implementation 20*8e33eff8Schristos * burden. Here is a reproduction of Figure 1 from Erlingsson et al. (2006) 21*8e33eff8Schristos * that shows approximate expected maximum load factors for various 22*8e33eff8Schristos * configurations: 23*8e33eff8Schristos * 24*8e33eff8Schristos * | #cells/bucket | 25*8e33eff8Schristos * #hashes | 1 | 2 | 4 | 8 | 26*8e33eff8Schristos * --------+-------+-------+-------+-------+ 27*8e33eff8Schristos * 1 | 0.006 | 0.006 | 0.03 | 0.12 | 28*8e33eff8Schristos * 2 | 0.49 | 0.86 |>0.93< |>0.96< | 29*8e33eff8Schristos * 3 | 0.91 | 0.97 | 0.98 | 0.999 | 30*8e33eff8Schristos * 4 | 0.97 | 0.99 | 0.999 | | 31*8e33eff8Schristos * 32*8e33eff8Schristos * The number of cells per bucket is chosen such that a bucket fits in one cache 33*8e33eff8Schristos * line. So, on 32- and 64-bit systems, we use (8,2) and (4,2) cuckoo hashing, 34*8e33eff8Schristos * respectively. 35*8e33eff8Schristos * 36*8e33eff8Schristos ******************************************************************************/ 37*8e33eff8Schristos #define JEMALLOC_CKH_C_ 38*8e33eff8Schristos #include "jemalloc/internal/jemalloc_preamble.h" 39*8e33eff8Schristos 40*8e33eff8Schristos #include "jemalloc/internal/ckh.h" 41*8e33eff8Schristos 42*8e33eff8Schristos #include "jemalloc/internal/jemalloc_internal_includes.h" 43*8e33eff8Schristos 44*8e33eff8Schristos #include "jemalloc/internal/assert.h" 45*8e33eff8Schristos #include "jemalloc/internal/hash.h" 46*8e33eff8Schristos #include "jemalloc/internal/malloc_io.h" 47*8e33eff8Schristos #include "jemalloc/internal/prng.h" 48*8e33eff8Schristos #include "jemalloc/internal/util.h" 49*8e33eff8Schristos 50*8e33eff8Schristos /******************************************************************************/ 51*8e33eff8Schristos /* Function prototypes for non-inline static functions. */ 52*8e33eff8Schristos 53*8e33eff8Schristos static bool ckh_grow(tsd_t *tsd, ckh_t *ckh); 54*8e33eff8Schristos static void ckh_shrink(tsd_t *tsd, ckh_t *ckh); 55*8e33eff8Schristos 56*8e33eff8Schristos /******************************************************************************/ 57*8e33eff8Schristos 58*8e33eff8Schristos /* 59*8e33eff8Schristos * Search bucket for key and return the cell number if found; SIZE_T_MAX 60*8e33eff8Schristos * otherwise. 61*8e33eff8Schristos */ 62*8e33eff8Schristos static size_t 63*8e33eff8Schristos ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) { 64*8e33eff8Schristos ckhc_t *cell; 65*8e33eff8Schristos unsigned i; 66*8e33eff8Schristos 67*8e33eff8Schristos for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { 68*8e33eff8Schristos cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; 69*8e33eff8Schristos if (cell->key != NULL && ckh->keycomp(key, cell->key)) { 70*8e33eff8Schristos return (bucket << LG_CKH_BUCKET_CELLS) + i; 71*8e33eff8Schristos } 72*8e33eff8Schristos } 73*8e33eff8Schristos 74*8e33eff8Schristos return SIZE_T_MAX; 75*8e33eff8Schristos } 76*8e33eff8Schristos 77*8e33eff8Schristos /* 78*8e33eff8Schristos * Search table for key and return cell number if found; SIZE_T_MAX otherwise. 79*8e33eff8Schristos */ 80*8e33eff8Schristos static size_t 81*8e33eff8Schristos ckh_isearch(ckh_t *ckh, const void *key) { 82*8e33eff8Schristos size_t hashes[2], bucket, cell; 83*8e33eff8Schristos 84*8e33eff8Schristos assert(ckh != NULL); 85*8e33eff8Schristos 86*8e33eff8Schristos ckh->hash(key, hashes); 87*8e33eff8Schristos 88*8e33eff8Schristos /* Search primary bucket. */ 89*8e33eff8Schristos bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); 90*8e33eff8Schristos cell = ckh_bucket_search(ckh, bucket, key); 91*8e33eff8Schristos if (cell != SIZE_T_MAX) { 92*8e33eff8Schristos return cell; 93*8e33eff8Schristos } 94*8e33eff8Schristos 95*8e33eff8Schristos /* Search secondary bucket. */ 96*8e33eff8Schristos bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); 97*8e33eff8Schristos cell = ckh_bucket_search(ckh, bucket, key); 98*8e33eff8Schristos return cell; 99*8e33eff8Schristos } 100*8e33eff8Schristos 101*8e33eff8Schristos static bool 102*8e33eff8Schristos ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, 103*8e33eff8Schristos const void *data) { 104*8e33eff8Schristos ckhc_t *cell; 105*8e33eff8Schristos unsigned offset, i; 106*8e33eff8Schristos 107*8e33eff8Schristos /* 108*8e33eff8Schristos * Cycle through the cells in the bucket, starting at a random position. 109*8e33eff8Schristos * The randomness avoids worst-case search overhead as buckets fill up. 110*8e33eff8Schristos */ 111*8e33eff8Schristos offset = (unsigned)prng_lg_range_u64(&ckh->prng_state, 112*8e33eff8Schristos LG_CKH_BUCKET_CELLS); 113*8e33eff8Schristos for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { 114*8e33eff8Schristos cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + 115*8e33eff8Schristos ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; 116*8e33eff8Schristos if (cell->key == NULL) { 117*8e33eff8Schristos cell->key = key; 118*8e33eff8Schristos cell->data = data; 119*8e33eff8Schristos ckh->count++; 120*8e33eff8Schristos return false; 121*8e33eff8Schristos } 122*8e33eff8Schristos } 123*8e33eff8Schristos 124*8e33eff8Schristos return true; 125*8e33eff8Schristos } 126*8e33eff8Schristos 127*8e33eff8Schristos /* 128*8e33eff8Schristos * No space is available in bucket. Randomly evict an item, then try to find an 129*8e33eff8Schristos * alternate location for that item. Iteratively repeat this 130*8e33eff8Schristos * eviction/relocation procedure until either success or detection of an 131*8e33eff8Schristos * eviction/relocation bucket cycle. 132*8e33eff8Schristos */ 133*8e33eff8Schristos static bool 134*8e33eff8Schristos ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, 135*8e33eff8Schristos void const **argdata) { 136*8e33eff8Schristos const void *key, *data, *tkey, *tdata; 137*8e33eff8Schristos ckhc_t *cell; 138*8e33eff8Schristos size_t hashes[2], bucket, tbucket; 139*8e33eff8Schristos unsigned i; 140*8e33eff8Schristos 141*8e33eff8Schristos bucket = argbucket; 142*8e33eff8Schristos key = *argkey; 143*8e33eff8Schristos data = *argdata; 144*8e33eff8Schristos while (true) { 145*8e33eff8Schristos /* 146*8e33eff8Schristos * Choose a random item within the bucket to evict. This is 147*8e33eff8Schristos * critical to correct function, because without (eventually) 148*8e33eff8Schristos * evicting all items within a bucket during iteration, it 149*8e33eff8Schristos * would be possible to get stuck in an infinite loop if there 150*8e33eff8Schristos * were an item for which both hashes indicated the same 151*8e33eff8Schristos * bucket. 152*8e33eff8Schristos */ 153*8e33eff8Schristos i = (unsigned)prng_lg_range_u64(&ckh->prng_state, 154*8e33eff8Schristos LG_CKH_BUCKET_CELLS); 155*8e33eff8Schristos cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; 156*8e33eff8Schristos assert(cell->key != NULL); 157*8e33eff8Schristos 158*8e33eff8Schristos /* Swap cell->{key,data} and {key,data} (evict). */ 159*8e33eff8Schristos tkey = cell->key; tdata = cell->data; 160*8e33eff8Schristos cell->key = key; cell->data = data; 161*8e33eff8Schristos key = tkey; data = tdata; 162*8e33eff8Schristos 163*8e33eff8Schristos #ifdef CKH_COUNT 164*8e33eff8Schristos ckh->nrelocs++; 165*8e33eff8Schristos #endif 166*8e33eff8Schristos 167*8e33eff8Schristos /* Find the alternate bucket for the evicted item. */ 168*8e33eff8Schristos ckh->hash(key, hashes); 169*8e33eff8Schristos tbucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); 170*8e33eff8Schristos if (tbucket == bucket) { 171*8e33eff8Schristos tbucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) 172*8e33eff8Schristos - 1); 173*8e33eff8Schristos /* 174*8e33eff8Schristos * It may be that (tbucket == bucket) still, if the 175*8e33eff8Schristos * item's hashes both indicate this bucket. However, 176*8e33eff8Schristos * we are guaranteed to eventually escape this bucket 177*8e33eff8Schristos * during iteration, assuming pseudo-random item 178*8e33eff8Schristos * selection (true randomness would make infinite 179*8e33eff8Schristos * looping a remote possibility). The reason we can 180*8e33eff8Schristos * never get trapped forever is that there are two 181*8e33eff8Schristos * cases: 182*8e33eff8Schristos * 183*8e33eff8Schristos * 1) This bucket == argbucket, so we will quickly 184*8e33eff8Schristos * detect an eviction cycle and terminate. 185*8e33eff8Schristos * 2) An item was evicted to this bucket from another, 186*8e33eff8Schristos * which means that at least one item in this bucket 187*8e33eff8Schristos * has hashes that indicate distinct buckets. 188*8e33eff8Schristos */ 189*8e33eff8Schristos } 190*8e33eff8Schristos /* Check for a cycle. */ 191*8e33eff8Schristos if (tbucket == argbucket) { 192*8e33eff8Schristos *argkey = key; 193*8e33eff8Schristos *argdata = data; 194*8e33eff8Schristos return true; 195*8e33eff8Schristos } 196*8e33eff8Schristos 197*8e33eff8Schristos bucket = tbucket; 198*8e33eff8Schristos if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { 199*8e33eff8Schristos return false; 200*8e33eff8Schristos } 201*8e33eff8Schristos } 202*8e33eff8Schristos } 203*8e33eff8Schristos 204*8e33eff8Schristos static bool 205*8e33eff8Schristos ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) { 206*8e33eff8Schristos size_t hashes[2], bucket; 207*8e33eff8Schristos const void *key = *argkey; 208*8e33eff8Schristos const void *data = *argdata; 209*8e33eff8Schristos 210*8e33eff8Schristos ckh->hash(key, hashes); 211*8e33eff8Schristos 212*8e33eff8Schristos /* Try to insert in primary bucket. */ 213*8e33eff8Schristos bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); 214*8e33eff8Schristos if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { 215*8e33eff8Schristos return false; 216*8e33eff8Schristos } 217*8e33eff8Schristos 218*8e33eff8Schristos /* Try to insert in secondary bucket. */ 219*8e33eff8Schristos bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); 220*8e33eff8Schristos if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { 221*8e33eff8Schristos return false; 222*8e33eff8Schristos } 223*8e33eff8Schristos 224*8e33eff8Schristos /* 225*8e33eff8Schristos * Try to find a place for this item via iterative eviction/relocation. 226*8e33eff8Schristos */ 227*8e33eff8Schristos return ckh_evict_reloc_insert(ckh, bucket, argkey, argdata); 228*8e33eff8Schristos } 229*8e33eff8Schristos 230*8e33eff8Schristos /* 231*8e33eff8Schristos * Try to rebuild the hash table from scratch by inserting all items from the 232*8e33eff8Schristos * old table into the new. 233*8e33eff8Schristos */ 234*8e33eff8Schristos static bool 235*8e33eff8Schristos ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) { 236*8e33eff8Schristos size_t count, i, nins; 237*8e33eff8Schristos const void *key, *data; 238*8e33eff8Schristos 239*8e33eff8Schristos count = ckh->count; 240*8e33eff8Schristos ckh->count = 0; 241*8e33eff8Schristos for (i = nins = 0; nins < count; i++) { 242*8e33eff8Schristos if (aTab[i].key != NULL) { 243*8e33eff8Schristos key = aTab[i].key; 244*8e33eff8Schristos data = aTab[i].data; 245*8e33eff8Schristos if (ckh_try_insert(ckh, &key, &data)) { 246*8e33eff8Schristos ckh->count = count; 247*8e33eff8Schristos return true; 248*8e33eff8Schristos } 249*8e33eff8Schristos nins++; 250*8e33eff8Schristos } 251*8e33eff8Schristos } 252*8e33eff8Schristos 253*8e33eff8Schristos return false; 254*8e33eff8Schristos } 255*8e33eff8Schristos 256*8e33eff8Schristos static bool 257*8e33eff8Schristos ckh_grow(tsd_t *tsd, ckh_t *ckh) { 258*8e33eff8Schristos bool ret; 259*8e33eff8Schristos ckhc_t *tab, *ttab; 260*8e33eff8Schristos unsigned lg_prevbuckets, lg_curcells; 261*8e33eff8Schristos 262*8e33eff8Schristos #ifdef CKH_COUNT 263*8e33eff8Schristos ckh->ngrows++; 264*8e33eff8Schristos #endif 265*8e33eff8Schristos 266*8e33eff8Schristos /* 267*8e33eff8Schristos * It is possible (though unlikely, given well behaved hashes) that the 268*8e33eff8Schristos * table will have to be doubled more than once in order to create a 269*8e33eff8Schristos * usable table. 270*8e33eff8Schristos */ 271*8e33eff8Schristos lg_prevbuckets = ckh->lg_curbuckets; 272*8e33eff8Schristos lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS; 273*8e33eff8Schristos while (true) { 274*8e33eff8Schristos size_t usize; 275*8e33eff8Schristos 276*8e33eff8Schristos lg_curcells++; 277*8e33eff8Schristos usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); 278*8e33eff8Schristos if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { 279*8e33eff8Schristos ret = true; 280*8e33eff8Schristos goto label_return; 281*8e33eff8Schristos } 282*8e33eff8Schristos tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, 283*8e33eff8Schristos true, NULL, true, arena_ichoose(tsd, NULL)); 284*8e33eff8Schristos if (tab == NULL) { 285*8e33eff8Schristos ret = true; 286*8e33eff8Schristos goto label_return; 287*8e33eff8Schristos } 288*8e33eff8Schristos /* Swap in new table. */ 289*8e33eff8Schristos ttab = ckh->tab; 290*8e33eff8Schristos ckh->tab = tab; 291*8e33eff8Schristos tab = ttab; 292*8e33eff8Schristos ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 293*8e33eff8Schristos 294*8e33eff8Schristos if (!ckh_rebuild(ckh, tab)) { 295*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true); 296*8e33eff8Schristos break; 297*8e33eff8Schristos } 298*8e33eff8Schristos 299*8e33eff8Schristos /* Rebuilding failed, so back out partially rebuilt table. */ 300*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); 301*8e33eff8Schristos ckh->tab = tab; 302*8e33eff8Schristos ckh->lg_curbuckets = lg_prevbuckets; 303*8e33eff8Schristos } 304*8e33eff8Schristos 305*8e33eff8Schristos ret = false; 306*8e33eff8Schristos label_return: 307*8e33eff8Schristos return ret; 308*8e33eff8Schristos } 309*8e33eff8Schristos 310*8e33eff8Schristos static void 311*8e33eff8Schristos ckh_shrink(tsd_t *tsd, ckh_t *ckh) { 312*8e33eff8Schristos ckhc_t *tab, *ttab; 313*8e33eff8Schristos size_t usize; 314*8e33eff8Schristos unsigned lg_prevbuckets, lg_curcells; 315*8e33eff8Schristos 316*8e33eff8Schristos /* 317*8e33eff8Schristos * It is possible (though unlikely, given well behaved hashes) that the 318*8e33eff8Schristos * table rebuild will fail. 319*8e33eff8Schristos */ 320*8e33eff8Schristos lg_prevbuckets = ckh->lg_curbuckets; 321*8e33eff8Schristos lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; 322*8e33eff8Schristos usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); 323*8e33eff8Schristos if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { 324*8e33eff8Schristos return; 325*8e33eff8Schristos } 326*8e33eff8Schristos tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL, 327*8e33eff8Schristos true, arena_ichoose(tsd, NULL)); 328*8e33eff8Schristos if (tab == NULL) { 329*8e33eff8Schristos /* 330*8e33eff8Schristos * An OOM error isn't worth propagating, since it doesn't 331*8e33eff8Schristos * prevent this or future operations from proceeding. 332*8e33eff8Schristos */ 333*8e33eff8Schristos return; 334*8e33eff8Schristos } 335*8e33eff8Schristos /* Swap in new table. */ 336*8e33eff8Schristos ttab = ckh->tab; 337*8e33eff8Schristos ckh->tab = tab; 338*8e33eff8Schristos tab = ttab; 339*8e33eff8Schristos ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 340*8e33eff8Schristos 341*8e33eff8Schristos if (!ckh_rebuild(ckh, tab)) { 342*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true); 343*8e33eff8Schristos #ifdef CKH_COUNT 344*8e33eff8Schristos ckh->nshrinks++; 345*8e33eff8Schristos #endif 346*8e33eff8Schristos return; 347*8e33eff8Schristos } 348*8e33eff8Schristos 349*8e33eff8Schristos /* Rebuilding failed, so back out partially rebuilt table. */ 350*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); 351*8e33eff8Schristos ckh->tab = tab; 352*8e33eff8Schristos ckh->lg_curbuckets = lg_prevbuckets; 353*8e33eff8Schristos #ifdef CKH_COUNT 354*8e33eff8Schristos ckh->nshrinkfails++; 355*8e33eff8Schristos #endif 356*8e33eff8Schristos } 357*8e33eff8Schristos 358*8e33eff8Schristos bool 359*8e33eff8Schristos ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hashp, 360*8e33eff8Schristos ckh_keycomp_t *keycomp) { 361*8e33eff8Schristos bool ret; 362*8e33eff8Schristos size_t mincells, usize; 363*8e33eff8Schristos unsigned lg_mincells; 364*8e33eff8Schristos 365*8e33eff8Schristos assert(minitems > 0); 366*8e33eff8Schristos assert(hashp != NULL); 367*8e33eff8Schristos assert(keycomp != NULL); 368*8e33eff8Schristos 369*8e33eff8Schristos #ifdef CKH_COUNT 370*8e33eff8Schristos ckh->ngrows = 0; 371*8e33eff8Schristos ckh->nshrinks = 0; 372*8e33eff8Schristos ckh->nshrinkfails = 0; 373*8e33eff8Schristos ckh->ninserts = 0; 374*8e33eff8Schristos ckh->nrelocs = 0; 375*8e33eff8Schristos #endif 376*8e33eff8Schristos ckh->prng_state = 42; /* Value doesn't really matter. */ 377*8e33eff8Schristos ckh->count = 0; 378*8e33eff8Schristos 379*8e33eff8Schristos /* 380*8e33eff8Schristos * Find the minimum power of 2 that is large enough to fit minitems 381*8e33eff8Schristos * entries. We are using (2+,2) cuckoo hashing, which has an expected 382*8e33eff8Schristos * maximum load factor of at least ~0.86, so 0.75 is a conservative load 383*8e33eff8Schristos * factor that will typically allow mincells items to fit without ever 384*8e33eff8Schristos * growing the table. 385*8e33eff8Schristos */ 386*8e33eff8Schristos assert(LG_CKH_BUCKET_CELLS > 0); 387*8e33eff8Schristos mincells = ((minitems + (3 - (minitems % 3))) / 3) << 2; 388*8e33eff8Schristos for (lg_mincells = LG_CKH_BUCKET_CELLS; 389*8e33eff8Schristos (ZU(1) << lg_mincells) < mincells; 390*8e33eff8Schristos lg_mincells++) { 391*8e33eff8Schristos /* Do nothing. */ 392*8e33eff8Schristos } 393*8e33eff8Schristos ckh->lg_minbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 394*8e33eff8Schristos ckh->lg_curbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 395*8e33eff8Schristos ckh->hash = hashp; 396*8e33eff8Schristos ckh->keycomp = keycomp; 397*8e33eff8Schristos 398*8e33eff8Schristos usize = sz_sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); 399*8e33eff8Schristos if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { 400*8e33eff8Schristos ret = true; 401*8e33eff8Schristos goto label_return; 402*8e33eff8Schristos } 403*8e33eff8Schristos ckh->tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, 404*8e33eff8Schristos NULL, true, arena_ichoose(tsd, NULL)); 405*8e33eff8Schristos if (ckh->tab == NULL) { 406*8e33eff8Schristos ret = true; 407*8e33eff8Schristos goto label_return; 408*8e33eff8Schristos } 409*8e33eff8Schristos 410*8e33eff8Schristos ret = false; 411*8e33eff8Schristos label_return: 412*8e33eff8Schristos return ret; 413*8e33eff8Schristos } 414*8e33eff8Schristos 415*8e33eff8Schristos void 416*8e33eff8Schristos ckh_delete(tsd_t *tsd, ckh_t *ckh) { 417*8e33eff8Schristos assert(ckh != NULL); 418*8e33eff8Schristos 419*8e33eff8Schristos #ifdef CKH_VERBOSE 420*8e33eff8Schristos malloc_printf( 421*8e33eff8Schristos "%s(%p): ngrows: %"FMTu64", nshrinks: %"FMTu64"," 422*8e33eff8Schristos " nshrinkfails: %"FMTu64", ninserts: %"FMTu64"," 423*8e33eff8Schristos " nrelocs: %"FMTu64"\n", __func__, ckh, 424*8e33eff8Schristos (unsigned long long)ckh->ngrows, 425*8e33eff8Schristos (unsigned long long)ckh->nshrinks, 426*8e33eff8Schristos (unsigned long long)ckh->nshrinkfails, 427*8e33eff8Schristos (unsigned long long)ckh->ninserts, 428*8e33eff8Schristos (unsigned long long)ckh->nrelocs); 429*8e33eff8Schristos #endif 430*8e33eff8Schristos 431*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); 432*8e33eff8Schristos if (config_debug) { 433*8e33eff8Schristos memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); 434*8e33eff8Schristos } 435*8e33eff8Schristos } 436*8e33eff8Schristos 437*8e33eff8Schristos size_t 438*8e33eff8Schristos ckh_count(ckh_t *ckh) { 439*8e33eff8Schristos assert(ckh != NULL); 440*8e33eff8Schristos 441*8e33eff8Schristos return ckh->count; 442*8e33eff8Schristos } 443*8e33eff8Schristos 444*8e33eff8Schristos bool 445*8e33eff8Schristos ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) { 446*8e33eff8Schristos size_t i, ncells; 447*8e33eff8Schristos 448*8e33eff8Schristos for (i = *tabind, ncells = (ZU(1) << (ckh->lg_curbuckets + 449*8e33eff8Schristos LG_CKH_BUCKET_CELLS)); i < ncells; i++) { 450*8e33eff8Schristos if (ckh->tab[i].key != NULL) { 451*8e33eff8Schristos if (key != NULL) { 452*8e33eff8Schristos *key = (void *)__UNCONST(ckh->tab[i].key); 453*8e33eff8Schristos } 454*8e33eff8Schristos if (data != NULL) { 455*8e33eff8Schristos *data = (void *)__UNCONST(ckh->tab[i].data); 456*8e33eff8Schristos } 457*8e33eff8Schristos *tabind = i + 1; 458*8e33eff8Schristos return false; 459*8e33eff8Schristos } 460*8e33eff8Schristos } 461*8e33eff8Schristos 462*8e33eff8Schristos return true; 463*8e33eff8Schristos } 464*8e33eff8Schristos 465*8e33eff8Schristos bool 466*8e33eff8Schristos ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) { 467*8e33eff8Schristos bool ret; 468*8e33eff8Schristos 469*8e33eff8Schristos assert(ckh != NULL); 470*8e33eff8Schristos assert(ckh_search(ckh, key, NULL, NULL)); 471*8e33eff8Schristos 472*8e33eff8Schristos #ifdef CKH_COUNT 473*8e33eff8Schristos ckh->ninserts++; 474*8e33eff8Schristos #endif 475*8e33eff8Schristos 476*8e33eff8Schristos while (ckh_try_insert(ckh, &key, &data)) { 477*8e33eff8Schristos if (ckh_grow(tsd, ckh)) { 478*8e33eff8Schristos ret = true; 479*8e33eff8Schristos goto label_return; 480*8e33eff8Schristos } 481*8e33eff8Schristos } 482*8e33eff8Schristos 483*8e33eff8Schristos ret = false; 484*8e33eff8Schristos label_return: 485*8e33eff8Schristos return ret; 486*8e33eff8Schristos } 487*8e33eff8Schristos 488*8e33eff8Schristos bool 489*8e33eff8Schristos ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, 490*8e33eff8Schristos void **data) { 491*8e33eff8Schristos size_t cell; 492*8e33eff8Schristos 493*8e33eff8Schristos assert(ckh != NULL); 494*8e33eff8Schristos 495*8e33eff8Schristos cell = ckh_isearch(ckh, searchkey); 496*8e33eff8Schristos if (cell != SIZE_T_MAX) { 497*8e33eff8Schristos if (key != NULL) { 498*8e33eff8Schristos *key = (void *)__UNCONST(ckh->tab[cell].key); 499*8e33eff8Schristos } 500*8e33eff8Schristos if (data != NULL) { 501*8e33eff8Schristos *data = (void *)__UNCONST(ckh->tab[cell].data); 502*8e33eff8Schristos } 503*8e33eff8Schristos ckh->tab[cell].key = NULL; 504*8e33eff8Schristos ckh->tab[cell].data = NULL; /* Not necessary. */ 505*8e33eff8Schristos 506*8e33eff8Schristos ckh->count--; 507*8e33eff8Schristos /* Try to halve the table if it is less than 1/4 full. */ 508*8e33eff8Schristos if (ckh->count < (ZU(1) << (ckh->lg_curbuckets 509*8e33eff8Schristos + LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets 510*8e33eff8Schristos > ckh->lg_minbuckets) { 511*8e33eff8Schristos /* Ignore error due to OOM. */ 512*8e33eff8Schristos ckh_shrink(tsd, ckh); 513*8e33eff8Schristos } 514*8e33eff8Schristos 515*8e33eff8Schristos return false; 516*8e33eff8Schristos } 517*8e33eff8Schristos 518*8e33eff8Schristos return true; 519*8e33eff8Schristos } 520*8e33eff8Schristos 521*8e33eff8Schristos bool 522*8e33eff8Schristos ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) { 523*8e33eff8Schristos size_t cell; 524*8e33eff8Schristos 525*8e33eff8Schristos assert(ckh != NULL); 526*8e33eff8Schristos 527*8e33eff8Schristos cell = ckh_isearch(ckh, searchkey); 528*8e33eff8Schristos if (cell != SIZE_T_MAX) { 529*8e33eff8Schristos if (key != NULL) { 530*8e33eff8Schristos *key = (void *)__UNCONST(ckh->tab[cell].key); 531*8e33eff8Schristos } 532*8e33eff8Schristos if (data != NULL) { 533*8e33eff8Schristos *data = (void *)__UNCONST(ckh->tab[cell].data); 534*8e33eff8Schristos } 535*8e33eff8Schristos return false; 536*8e33eff8Schristos } 537*8e33eff8Schristos 538*8e33eff8Schristos return true; 539*8e33eff8Schristos } 540*8e33eff8Schristos 541*8e33eff8Schristos void 542*8e33eff8Schristos ckh_string_hash(const void *key, size_t r_hash[2]) { 543*8e33eff8Schristos hash(key, strlen((const char *)key), 0x94122f33U, r_hash); 544*8e33eff8Schristos } 545*8e33eff8Schristos 546*8e33eff8Schristos bool 547*8e33eff8Schristos ckh_string_keycomp(const void *k1, const void *k2) { 548*8e33eff8Schristos assert(k1 != NULL); 549*8e33eff8Schristos assert(k2 != NULL); 550*8e33eff8Schristos 551*8e33eff8Schristos return !strcmp((const char *)k1, (const char *)k2); 552*8e33eff8Schristos } 553*8e33eff8Schristos 554*8e33eff8Schristos void 555*8e33eff8Schristos ckh_pointer_hash(const void *key, size_t r_hash[2]) { 556*8e33eff8Schristos union { 557*8e33eff8Schristos const void *v; 558*8e33eff8Schristos size_t i; 559*8e33eff8Schristos } u; 560*8e33eff8Schristos 561*8e33eff8Schristos assert(sizeof(u.v) == sizeof(u.i)); 562*8e33eff8Schristos u.v = key; 563*8e33eff8Schristos hash(&u.i, sizeof(u.i), 0xd983396eU, r_hash); 564*8e33eff8Schristos } 565*8e33eff8Schristos 566*8e33eff8Schristos bool 567*8e33eff8Schristos ckh_pointer_keycomp(const void *k1, const void *k2) { 568*8e33eff8Schristos return (k1 == k2); 569*8e33eff8Schristos } 570