ckh.c (286866) | ckh.c (296221) |
---|---|
1/* 2 ******************************************************************************* 3 * Implementation of (2^1+,2) cuckoo hashing, where 2^1+ indicates that each 4 * hash bucket contains 2^n cells, for n >= 1, and 2 indicates that two hash 5 * functions are employed. The original cuckoo hashing algorithm was described 6 * in: 7 * 8 * Pagh, R., F.F. Rodler (2004) Cuckoo Hashing. Journal of Algorithms --- 85 unchanged lines hidden (view full) --- 94{ 95 ckhc_t *cell; 96 unsigned offset, i; 97 98 /* 99 * Cycle through the cells in the bucket, starting at a random position. 100 * The randomness avoids worst-case search overhead as buckets fill up. 101 */ | 1/* 2 ******************************************************************************* 3 * Implementation of (2^1+,2) cuckoo hashing, where 2^1+ indicates that each 4 * hash bucket contains 2^n cells, for n >= 1, and 2 indicates that two hash 5 * functions are employed. The original cuckoo hashing algorithm was described 6 * in: 7 * 8 * Pagh, R., F.F. Rodler (2004) Cuckoo Hashing. Journal of Algorithms --- 85 unchanged lines hidden (view full) --- 94{ 95 ckhc_t *cell; 96 unsigned offset, i; 97 98 /* 99 * Cycle through the cells in the bucket, starting at a random position. 100 * The randomness avoids worst-case search overhead as buckets fill up. 101 */ |
102 prng32(offset, LG_CKH_BUCKET_CELLS, ckh->prng_state, CKH_A, CKH_C); | 102 offset = (unsigned)prng_lg_range(&ckh->prng_state, LG_CKH_BUCKET_CELLS); |
103 for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { 104 cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + 105 ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; 106 if (cell->key == NULL) { 107 cell->key = key; 108 cell->data = data; 109 ckh->count++; 110 return (false); --- 25 unchanged lines hidden (view full) --- 136 /* 137 * Choose a random item within the bucket to evict. This is 138 * critical to correct function, because without (eventually) 139 * evicting all items within a bucket during iteration, it 140 * would be possible to get stuck in an infinite loop if there 141 * were an item for which both hashes indicated the same 142 * bucket. 143 */ | 103 for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { 104 cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + 105 ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; 106 if (cell->key == NULL) { 107 cell->key = key; 108 cell->data = data; 109 ckh->count++; 110 return (false); --- 25 unchanged lines hidden (view full) --- 136 /* 137 * Choose a random item within the bucket to evict. This is 138 * critical to correct function, because without (eventually) 139 * evicting all items within a bucket during iteration, it 140 * would be possible to get stuck in an infinite loop if there 141 * were an item for which both hashes indicated the same 142 * bucket. 143 */ |
144 prng32(i, LG_CKH_BUCKET_CELLS, ckh->prng_state, CKH_A, CKH_C); | 144 i = (unsigned)prng_lg_range(&ckh->prng_state, 145 LG_CKH_BUCKET_CELLS); |
145 cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; 146 assert(cell->key != NULL); 147 148 /* Swap cell->{key,data} and {key,data} (evict). */ 149 tkey = cell->key; tdata = cell->data; 150 cell->key = key; cell->data = data; 151 key = tkey; data = tdata; 152 --- 89 unchanged lines hidden (view full) --- 242 return (false); 243} 244 245static bool 246ckh_grow(tsd_t *tsd, ckh_t *ckh) 247{ 248 bool ret; 249 ckhc_t *tab, *ttab; | 146 cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; 147 assert(cell->key != NULL); 148 149 /* Swap cell->{key,data} and {key,data} (evict). */ 150 tkey = cell->key; tdata = cell->data; 151 cell->key = key; cell->data = data; 152 key = tkey; data = tdata; 153 --- 89 unchanged lines hidden (view full) --- 243 return (false); 244} 245 246static bool 247ckh_grow(tsd_t *tsd, ckh_t *ckh) 248{ 249 bool ret; 250 ckhc_t *tab, *ttab; |
250 size_t lg_curcells; 251 unsigned lg_prevbuckets; | 251 unsigned lg_prevbuckets, lg_curcells; |
252 253#ifdef CKH_COUNT 254 ckh->ngrows++; 255#endif 256 257 /* 258 * It is possible (though unlikely, given well behaved hashes) that the 259 * table will have to be doubled more than once in order to create a 260 * usable table. 261 */ 262 lg_prevbuckets = ckh->lg_curbuckets; 263 lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS; 264 while (true) { 265 size_t usize; 266 267 lg_curcells++; 268 usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); | 252 253#ifdef CKH_COUNT 254 ckh->ngrows++; 255#endif 256 257 /* 258 * It is possible (though unlikely, given well behaved hashes) that the 259 * table will have to be doubled more than once in order to create a 260 * usable table. 261 */ 262 lg_prevbuckets = ckh->lg_curbuckets; 263 lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS; 264 while (true) { 265 size_t usize; 266 267 lg_curcells++; 268 usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); |
269 if (usize == 0) { | 269 if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) { |
270 ret = true; 271 goto label_return; 272 } 273 tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, 274 true, NULL); 275 if (tab == NULL) { 276 ret = true; 277 goto label_return; 278 } 279 /* Swap in new table. */ 280 ttab = ckh->tab; 281 ckh->tab = tab; 282 tab = ttab; 283 ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 284 285 if (!ckh_rebuild(ckh, tab)) { | 270 ret = true; 271 goto label_return; 272 } 273 tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, 274 true, NULL); 275 if (tab == NULL) { 276 ret = true; 277 goto label_return; 278 } 279 /* Swap in new table. */ 280 ttab = ckh->tab; 281 ckh->tab = tab; 282 tab = ttab; 283 ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 284 285 if (!ckh_rebuild(ckh, tab)) { |
286 idalloctm(tsd, tab, tcache_get(tsd, false), true); | 286 idalloctm(tsd, tab, tcache_get(tsd, false), true, true); |
287 break; 288 } 289 290 /* Rebuilding failed, so back out partially rebuilt table. */ | 287 break; 288 } 289 290 /* Rebuilding failed, so back out partially rebuilt table. */ |
291 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true); | 291 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true, true); |
292 ckh->tab = tab; 293 ckh->lg_curbuckets = lg_prevbuckets; 294 } 295 296 ret = false; 297label_return: 298 return (ret); 299} 300 301static void 302ckh_shrink(tsd_t *tsd, ckh_t *ckh) 303{ 304 ckhc_t *tab, *ttab; | 292 ckh->tab = tab; 293 ckh->lg_curbuckets = lg_prevbuckets; 294 } 295 296 ret = false; 297label_return: 298 return (ret); 299} 300 301static void 302ckh_shrink(tsd_t *tsd, ckh_t *ckh) 303{ 304 ckhc_t *tab, *ttab; |
305 size_t lg_curcells, usize; 306 unsigned lg_prevbuckets; | 305 size_t usize; 306 unsigned lg_prevbuckets, lg_curcells; |
307 308 /* 309 * It is possible (though unlikely, given well behaved hashes) that the 310 * table rebuild will fail. 311 */ 312 lg_prevbuckets = ckh->lg_curbuckets; 313 lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; 314 usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); | 307 308 /* 309 * It is possible (though unlikely, given well behaved hashes) that the 310 * table rebuild will fail. 311 */ 312 lg_prevbuckets = ckh->lg_curbuckets; 313 lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; 314 usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); |
315 if (usize == 0) | 315 if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) |
316 return; 317 tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, true, 318 NULL); 319 if (tab == NULL) { 320 /* 321 * An OOM error isn't worth propagating, since it doesn't 322 * prevent this or future operations from proceeding. 323 */ 324 return; 325 } 326 /* Swap in new table. */ 327 ttab = ckh->tab; 328 ckh->tab = tab; 329 tab = ttab; 330 ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 331 332 if (!ckh_rebuild(ckh, tab)) { | 316 return; 317 tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, true, 318 NULL); 319 if (tab == NULL) { 320 /* 321 * An OOM error isn't worth propagating, since it doesn't 322 * prevent this or future operations from proceeding. 323 */ 324 return; 325 } 326 /* Swap in new table. */ 327 ttab = ckh->tab; 328 ckh->tab = tab; 329 tab = ttab; 330 ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; 331 332 if (!ckh_rebuild(ckh, tab)) { |
333 idalloctm(tsd, tab, tcache_get(tsd, false), true); | 333 idalloctm(tsd, tab, tcache_get(tsd, false), true, true); |
334#ifdef CKH_COUNT 335 ckh->nshrinks++; 336#endif 337 return; 338 } 339 340 /* Rebuilding failed, so back out partially rebuilt table. */ | 334#ifdef CKH_COUNT 335 ckh->nshrinks++; 336#endif 337 return; 338 } 339 340 /* Rebuilding failed, so back out partially rebuilt table. */ |
341 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true); | 341 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true, true); |
342 ckh->tab = tab; 343 ckh->lg_curbuckets = lg_prevbuckets; 344#ifdef CKH_COUNT 345 ckh->nshrinkfails++; 346#endif 347} 348 349bool --- 32 unchanged lines hidden (view full) --- 382 lg_mincells++) 383 ; /* Do nothing. */ 384 ckh->lg_minbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 385 ckh->lg_curbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 386 ckh->hash = hash; 387 ckh->keycomp = keycomp; 388 389 usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); | 342 ckh->tab = tab; 343 ckh->lg_curbuckets = lg_prevbuckets; 344#ifdef CKH_COUNT 345 ckh->nshrinkfails++; 346#endif 347} 348 349bool --- 32 unchanged lines hidden (view full) --- 382 lg_mincells++) 383 ; /* Do nothing. */ 384 ckh->lg_minbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 385 ckh->lg_curbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; 386 ckh->hash = hash; 387 ckh->keycomp = keycomp; 388 389 usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); |
390 if (usize == 0) { | 390 if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) { |
391 ret = true; 392 goto label_return; 393 } 394 ckh->tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, true, 395 NULL); 396 if (ckh->tab == NULL) { 397 ret = true; 398 goto label_return; --- 17 unchanged lines hidden (view full) --- 416 " nrelocs: %"FMTu64"\n", __func__, ckh, 417 (unsigned long long)ckh->ngrows, 418 (unsigned long long)ckh->nshrinks, 419 (unsigned long long)ckh->nshrinkfails, 420 (unsigned long long)ckh->ninserts, 421 (unsigned long long)ckh->nrelocs); 422#endif 423 | 391 ret = true; 392 goto label_return; 393 } 394 ckh->tab = (ckhc_t *)ipallocztm(tsd, usize, CACHELINE, true, NULL, true, 395 NULL); 396 if (ckh->tab == NULL) { 397 ret = true; 398 goto label_return; --- 17 unchanged lines hidden (view full) --- 416 " nrelocs: %"FMTu64"\n", __func__, ckh, 417 (unsigned long long)ckh->ngrows, 418 (unsigned long long)ckh->nshrinks, 419 (unsigned long long)ckh->nshrinkfails, 420 (unsigned long long)ckh->ninserts, 421 (unsigned long long)ckh->nrelocs); 422#endif 423 |
424 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true); | 424 idalloctm(tsd, ckh->tab, tcache_get(tsd, false), true, true); |
425 if (config_debug) 426 memset(ckh, 0x5a, sizeof(ckh_t)); 427} 428 429size_t 430ckh_count(ckh_t *ckh) 431{ 432 --- 136 unchanged lines hidden --- | 425 if (config_debug) 426 memset(ckh, 0x5a, sizeof(ckh_t)); 427} 428 429size_t 430ckh_count(ckh_t *ckh) 431{ 432 --- 136 unchanged lines hidden --- |