Commit 1f6bf6c8 authored by Maged Michael's avatar Maged Michael Committed by Facebook Github Bot

ConcurrentHashMap: Make iterators movable

Summary:
To reduce unnecessary copying for user code handling ConstIterator-s.

Added move test and change UpdateStressTest to use few concurrent iterators.

Reviewed By: yfeldblum

Differential Revision: D8587056

fbshipit-source-id: d6b592a3aa40ca8a7599b258b45a1d339088c978
parent 3af92dbe
...@@ -431,12 +431,26 @@ class ConcurrentHashMap { ...@@ -431,12 +431,26 @@ class ConcurrentHashMap {
return *this; return *this;
} }
ConstIterator& operator=(ConstIterator&& o) noexcept {
if (this != &o) {
it_ = std::move(o.it_);
segment_ = std::exchange(o.segment_, uint64_t(NumShards));
parent_ = std::exchange(o.parent_, nullptr);
}
return *this;
}
ConstIterator(const ConstIterator& o) { ConstIterator(const ConstIterator& o) {
parent_ = o.parent_; parent_ = o.parent_;
it_ = o.it_; it_ = o.it_;
segment_ = o.segment_; segment_ = o.segment_;
} }
ConstIterator(ConstIterator&& o) noexcept
: it_(std::move(o.it_)),
segment_(std::exchange(o.segment_, uint64_t(NumShards))),
parent_(std::exchange(o.parent_, nullptr)) {}
ConstIterator(const ConcurrentHashMap* parent, uint64_t segment) ConstIterator(const ConcurrentHashMap* parent, uint64_t segment)
: segment_(segment), parent_(parent) {} : segment_(segment), parent_(parent) {}
......
...@@ -761,13 +761,12 @@ class alignas(64) ConcurrentHashMapSegment { ...@@ -761,13 +761,12 @@ class alignas(64) ConcurrentHashMapSegment {
bucket_count_ = o.bucket_count_; bucket_count_ = o.bucket_count_;
} }
/* implicit */ Iterator(Iterator&& o) noexcept Iterator(Iterator&& o) noexcept
: hazptrs_(std::move(o.hazptrs_)) { : hazptrs_(std::move(o.hazptrs_)),
node_ = o.node_; node_(std::exchange(o.node_, nullptr)),
buckets_ = o.buckets_; buckets_(std::exchange(o.buckets_, nullptr)),
idx_ = o.idx_; bucket_count_(std::exchange(o.bucket_count_, 0)),
bucket_count_ = o.bucket_count_; idx_(std::exchange(o.idx_, 0)) {}
}
// These are accessed directly from the functions above // These are accessed directly from the functions above
hazptr_array<3, Atom> hazptrs_; hazptr_array<3, Atom> hazptrs_;
......
...@@ -337,14 +337,18 @@ TEST(ConcurrentHashMap, UpdateStressTest) { ...@@ -337,14 +337,18 @@ TEST(ConcurrentHashMap, UpdateStressTest) {
unsigned long k = folly::hash::jenkins_rev_mix32((i + offset)); unsigned long k = folly::hash::jenkins_rev_mix32((i + offset));
k = k % (iters / num_threads) + offset; k = k % (iters / num_threads) + offset;
unsigned long val = 3; unsigned long val = 3;
{
auto res = m.find(k); auto res = m.find(k);
EXPECT_NE(res, m.cend()); EXPECT_NE(res, m.cend());
EXPECT_EQ(k, res->second); EXPECT_EQ(k, res->second);
auto r = m.assign(k, res->second); auto r = m.assign(k, res->second);
EXPECT_TRUE(r); EXPECT_TRUE(r);
res = m.find(k); }
{
auto res = m.find(k);
EXPECT_NE(res, m.cend()); EXPECT_NE(res, m.cend());
EXPECT_EQ(k, res->second); EXPECT_EQ(k, res->second);
}
// Another random insertion to force table resizes // Another random insertion to force table resizes
val = size + i + offset; val = size + i + offset;
EXPECT_TRUE(m.insert(val, val).second); EXPECT_TRUE(m.insert(val, val).second);
...@@ -722,3 +726,23 @@ TEST(ConcurrentHashMap, ForEachLoop) { ...@@ -722,3 +726,23 @@ TEST(ConcurrentHashMap, ForEachLoop) {
} }
EXPECT_EQ(iters, 1); EXPECT_EQ(iters, 1);
} }
TEST(ConcurrentHashMap, IteratorMove) {
using CHM = ConcurrentHashMap<int, int>;
using Iter = CHM::ConstIterator;
struct Foo {
Iter it;
explicit Foo(Iter&& it_) : it(std::move(it_)) {}
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
};
CHM map;
int k = 111;
int v = 999999;
map.insert(k, v);
Foo foo(map.find(k));
ASSERT_EQ(foo.it->second, v);
Foo foo2(map.find(0));
foo2 = std::move(foo);
ASSERT_EQ(foo2.it->second, v);
}
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