| 408 | } |
| 409 | |
| 410 | dictAsyncRehashCtl *dictRehashAsyncStart(dict *d, int buckets) { |
| 411 | assert(d->type->asyncfree != nullptr); |
| 412 | if (!dictIsRehashing(d) || d->pauserehash != 0) return nullptr; |
| 413 | |
| 414 | d->asyncdata = new dictAsyncRehashCtl(d, d->asyncdata); |
| 415 | |
| 416 | int empty_visits = buckets*10; |
| 417 | |
| 418 | while (d->asyncdata->queue.size() < (size_t)buckets && (size_t)d->rehashidx < d->ht[0].size) { |
| 419 | dictEntry *de; |
| 420 | |
| 421 | /* Note that rehashidx can't overflow as we are sure there are more |
| 422 | * elements because ht[0].used != 0 */ |
| 423 | while(d->ht[0].table[d->rehashidx] == NULL) { |
| 424 | d->rehashidx++; |
| 425 | if (--empty_visits == 0) goto LDone; |
| 426 | if ((size_t)d->rehashidx >= d->ht[0].size) goto LDone; |
| 427 | } |
| 428 | |
| 429 | de = d->ht[0].table[d->rehashidx]; |
| 430 | // We have to queue every node in the bucket, even if we go over our target size |
| 431 | while (de != nullptr) { |
| 432 | d->asyncdata->queue.emplace_back(de); |
| 433 | de = de->next; |
| 434 | } |
| 435 | d->rehashidx++; |
| 436 | } |
| 437 | |
| 438 | LDone: |
| 439 | if (d->asyncdata->queue.empty()) { |
| 440 | // We didn't find any work to do (can happen if there is a large gap in the hash table) |
| 441 | auto asyncT = d->asyncdata; |
| 442 | d->asyncdata = d->asyncdata->next; |
| 443 | delete asyncT; |
| 444 | return nullptr; |
| 445 | } |
| 446 | return d->asyncdata; |
| 447 | } |
| 448 | |
| 449 | void dictRehashAsync(dictAsyncRehashCtl *ctl) { |
| 450 | if (ctl->abondon.load(std::memory_order_acquire)) { |
no test coverage detected