Performs N steps of incremental rehashing. Returns 1 if there are still * keys to move from the old to the new hash table, otherwise 0 is returned. * * Note that a rehashing step consists in moving a bucket (that may have more * than one key as we use chaining) from the old to the new hash table, however * since part of the hash table may be composed of empty spaces, it is not * guaranteed t
| 261 | * will visit at max N*10 empty buckets in total, otherwise the amount of |
| 262 | * work it does would be unbound and the function may block for a long time. */ |
| 263 | int HashTableRehash(dict *d, int n) { |
| 264 | int empty_visits = n*10; /* Max number of empty buckets to visit. */ |
| 265 | if (dict_can_resize == DICT_RESIZE_FORBID || !dictIsRehashing(d)) return 0; |
| 266 | if (dict_can_resize == DICT_RESIZE_AVOID && |
| 267 | (DICTHT_SIZE(d->ht_size_exp[1]) / DICTHT_SIZE(d->ht_size_exp[0]) < dict_force_resize_ratio)) |
| 268 | { |
| 269 | return 0; |
| 270 | } |
| 271 | |
| 272 | while(n-- && d->ht_used[0] != 0) { |
| 273 | dictEntry *de, *nextde; |
| 274 | |
| 275 | /* Note that rehashidx can't overflow as we are sure there are more |
| 276 | * elements because ht[0].used != 0 */ |
| 277 | assert(DICTHT_SIZE(d->ht_size_exp[0]) > (unsigned long)d->rehashidx); |
| 278 | while(d->ht_table[0][d->rehashidx] == NULL) { |
| 279 | d->rehashidx++; |
| 280 | if (--empty_visits == 0) return 1; |
| 281 | } |
| 282 | de = d->ht_table[0][d->rehashidx]; |
| 283 | /* Move all the keys in this bucket from the old to the new hash HT */ |
| 284 | while(de) { |
| 285 | uint64_t h; |
| 286 | |
| 287 | nextde = de->next; |
| 288 | /* Get the index in the new hash table */ |
| 289 | if (d->ht_size_exp[1] > d->ht_size_exp[0]) { |
| 290 | h = dictHashKey(d, de->key) & DICTHT_SIZE_MASK(d->ht_size_exp[1]); |
| 291 | } else { |
| 292 | /* We're shrinking the table. The tables sizes are powers of |
| 293 | * two, so we simply mask the bucket index in the larger table |
| 294 | * to get the bucket index in the smaller table. */ |
| 295 | h = d->rehashidx & DICTHT_SIZE_MASK(d->ht_size_exp[1]); |
| 296 | } |
| 297 | de->next = d->ht_table[1][h]; |
| 298 | d->ht_table[1][h] = de; |
| 299 | d->ht_used[0]--; |
| 300 | d->ht_used[1]++; |
| 301 | de = nextde; |
| 302 | } |
| 303 | d->ht_table[0][d->rehashidx] = NULL; |
| 304 | d->rehashidx++; |
| 305 | } |
| 306 | |
| 307 | /* Check if we already rehashed the whole table... */ |
| 308 | if (d->ht_used[0] == 0) { |
| 309 | free(d->ht_table[0]); |
| 310 | /* Copy the new ht onto the old one */ |
| 311 | d->ht_table[0] = d->ht_table[1]; |
| 312 | d->ht_used[0] = d->ht_used[1]; |
| 313 | d->ht_size_exp[0] = d->ht_size_exp[1]; |
| 314 | _dictReset(d, 1); |
| 315 | d->rehashidx = -1; |
| 316 | return 0; |
| 317 | } |
| 318 | |
| 319 | /* More to rehash... */ |
| 320 | return 1; |
no test coverage detected