diff --git a/folly/concurrency/detail/ConcurrentHashMap-detail.h b/folly/concurrency/detail/ConcurrentHashMap-detail.h index 5a365aa3f505b33f62203218b3d2d62309b4453f..dec38dafbd514037d2569114abc0d7b9e149135f 100644 --- a/folly/concurrency/detail/ConcurrentHashMap-detail.h +++ b/folly/concurrency/detail/ConcurrentHashMap-detail.h @@ -672,6 +672,7 @@ class alignas(64) BucketTable { } prev->store(cur, std::memory_order_release); it.setNode(cur, buckets, bcount, idx); + haznode.reset_protection(cur); g.unlock(); // Release not under lock. node->release(); diff --git a/folly/concurrency/test/ConcurrentHashMapTest.cpp b/folly/concurrency/test/ConcurrentHashMapTest.cpp index 4cf3be8453834381c697446a6bb3684e90f559af..14a92dd19f86eb66a901a77c003db3087d321890 100644 --- a/folly/concurrency/test/ConcurrentHashMapTest.cpp +++ b/folly/concurrency/test/ConcurrentHashMapTest.cpp @@ -540,6 +540,29 @@ TYPED_TEST_P(ConcurrentHashMapTest, TryEmplaceEraseStressTest) { } } +TYPED_TEST_P(ConcurrentHashMapTest, InsertOrAssignStressTest) { + DeterministicSchedule sched(DeterministicSchedule::uniform(FLAGS_seed)); + std::atomic<int> iterations{10000}; + std::vector<std::thread> threads; + unsigned int num_threads = 32; + threads.reserve(num_threads); + folly::ConcurrentHashMap<int, int> map; + for (uint32_t t = 0; t < num_threads; t++) { + threads.push_back(lib::thread([&]() { + int i = 0; + while (--iterations >= 0) { + auto res = map.insert_or_assign(0, ++i); + ASSERT_TRUE(res.second); + auto v = res.first->second; + ASSERT_EQ(v, i); + } + })); + } + for (auto& t : threads) { + join; + } +} + TYPED_TEST_P(ConcurrentHashMapTest, IterateStressTest) { DeterministicSchedule sched(DeterministicSchedule::uniform(FLAGS_seed)); @@ -1015,6 +1038,7 @@ REGISTER_TYPED_TEST_CASE_P( EraseTest, ForEachLoop, TryEmplaceEraseStressTest, + InsertOrAssignStressTest, IterateStressTest, RefcountTest, UpdateStressTest,