Commit ed6fa93c authored by Maged Michael's avatar Maged Michael Committed by Facebook GitHub Bot

ConcurrentHashMap: Rehash only when expanding

Summary:
Fixes a bug when a call to reserve leads to calling rehash with a buck_count value that is not a power of two and/or less than the current count.
The rehash algorithm depends on the bucket_count being a power of two and that the count does not decrease.

The fix: Ensure that reserve calls rehash with a power of two argument and that rehash is skipped if the new count is not greater than the old one.

Reviewed By: davidtgoldblatt

Differential Revision: D25852794

fbshipit-source-id: ae1ae6cfbcbd0659becc14c703920e9505181109
parent 3c135dba
...@@ -279,12 +279,15 @@ class alignas(64) BucketTable { ...@@ -279,12 +279,15 @@ class alignas(64) BucketTable {
// Must hold lock. // Must hold lock.
void rehash(size_t bucket_count, hazptr_obj_cohort<Atom>* cohort) { void rehash(size_t bucket_count, hazptr_obj_cohort<Atom>* cohort) {
auto oldcount = bucket_count_.load(std::memory_order_relaxed);
// bucket_count must be a power of 2
DCHECK_EQ(bucket_count & (bucket_count - 1), 0);
if (bucket_count <= oldcount) {
return; // Rehash only if expanding.
}
auto buckets = buckets_.load(std::memory_order_relaxed); auto buckets = buckets_.load(std::memory_order_relaxed);
auto newbuckets = Buckets::create(bucket_count, cohort); auto newbuckets = Buckets::create(bucket_count, cohort);
load_factor_nodes_ = bucket_count * load_factor_; load_factor_nodes_ = bucket_count * load_factor_;
auto oldcount = bucket_count_.load(std::memory_order_relaxed);
for (size_t i = 0; i < oldcount; i++) { for (size_t i = 0; i < oldcount; i++) {
auto bucket = &buckets->buckets_[i](); auto bucket = &buckets->buckets_[i]();
auto node = bucket->load(std::memory_order_relaxed); auto node = bucket->load(std::memory_order_relaxed);
...@@ -1773,7 +1776,9 @@ class alignas(64) ConcurrentHashMapSegment { ...@@ -1773,7 +1776,9 @@ class alignas(64) ConcurrentHashMapSegment {
} }
// Must hold lock. // Must hold lock.
void rehash(size_t bucket_count) { impl_.rehash(bucket_count, cohort_); } void rehash(size_t bucket_count) {
impl_.rehash(folly::nextPowTwo(bucket_count), cohort_);
}
template <typename K> template <typename K>
bool find(Iterator& res, const K& k) { bool find(Iterator& res, const K& k) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment