diff --git a/deps/oblib/src/lib/hash/ob_link_hashmap.h b/deps/oblib/src/lib/hash/ob_link_hashmap.h index 506c503368c058976e822a24d1ef31f013e8433a..a3c499904422b42cd5e43dd26a860e21ae096541 100644 --- a/deps/oblib/src/lib/hash/ob_link_hashmap.h +++ b/deps/oblib/src/lib/hash/ob_link_hashmap.h @@ -30,6 +30,12 @@ inline int32_t faa_if_positive(int32_t* addr, int32_t x) return ov; } +inline static ObQSync &get_global_link_hashmap_qsync() +{ + static ObQSync qsync; + return qsync; +} + // DO NOT use me class BaseRefHandle { public: @@ -65,42 +71,6 @@ protected: uint64_t qc_slot_; }; -// fast read, slow del, delay reclaim Value/Node -class TCRefHandle final : public BaseRefHandle { -public: - typedef RefNode Node; - explicit TCRefHandle(RetireStation& retire_station) : BaseRefHandle(retire_station) - {} - void born(Node* node) - { - UNUSED(get_tcref().born(&node->uref_)); - } - int32_t end(Node* node) - { - UNUSED(get_tcref().end(&node->uref_)); - return get_tcref().sync(&node->uref_); - } - bool inc(Node* node) - { - int32_t ref = 0; - if (TCRef::REF_LIMIT == (ref = get_tcref().inc_ref(&node->uref_))) { - ref = ATOMIC_LOAD(&node->uref_); - } - return ref > TCRef::REF_LIMIT / 2; - } - int32_t dec(Node* node) - { - return get_tcref().dec_ref(&node->uref_); - } - -private: - static TCRef& get_tcref() - { - static TCRef tcref; - return tcref; - } -}; - // balanced read/del performance, realtime reclaim Value, batch/delay reclaim Node. class RefHandle final : public BaseRefHandle { public: @@ -125,45 +95,6 @@ public: } }; -class DummyRefHandle final : public BaseRefHandle { -public: - typedef RefNode Node; - enum { BORN_REF = 1 }; - explicit DummyRefHandle(RetireStation& retire_station) : BaseRefHandle(retire_station) - {} - void enter_critical() override - {} - void leave_critical() override - {} - void retire(Node* node, HazardList& reclaim_list) override - { - reclaim_list.push(&node->retire_link_); - } - void purge(HazardList& reclaim_list) override - { - UNUSED(reclaim_list); - } - void born(Node* node) - { - UNUSED(node); - } - int32_t end(Node* node) - { - UNUSED(node); - return 0; - } - bool inc(Node* node) - { - UNUSED(node); - return true; - } - int32_t dec(Node* node) - { - UNUSED(node); - return 1; - } -}; - template , typename RefHandle = RefHandle, int64_t SHRINK_THRESHOLD = 8> class ObLinkHashMap { @@ -264,8 +195,12 @@ public: void purge() { HazardList reclaim_list; - get_retire_station().purge(reclaim_list); - reclaim_nodes(reclaim_list); + { + CriticalGuard(get_global_link_hashmap_qsync()); + get_retire_station().purge(reclaim_list); + reclaim_nodes(reclaim_list); + } + WaitQuiescent(get_global_link_hashmap_qsync()); } int64_t count() const { @@ -344,6 +279,7 @@ public: HazardList reclaim_list; HashNode* node = CONTAINER_OF(hash_link, HashNode, hash_link_); end_uref(node); + CriticalGuard(get_global_link_hashmap_qsync()); ref_handle_.retire(node, reclaim_list); reclaim_nodes(reclaim_list); count_handle_.add(-1); diff --git a/deps/oblib/unittest/lib/hash/test_link_hashmap.cpp b/deps/oblib/unittest/lib/hash/test_link_hashmap.cpp index 917b910c4817a87cc2c5cdca3fc49166cbe06ff7..10c4908eba1811f18f07d76ab12e354026bc49f9 100644 --- a/deps/oblib/unittest/lib/hash/test_link_hashmap.cpp +++ b/deps/oblib/unittest/lib/hash/test_link_hashmap.cpp @@ -66,12 +66,21 @@ static uint64_t node_free CACHE_ALIGNED; ObMemAttr attr(1001, ObNewModIds::OB_MEMSTORE); +static int64_t STEP = 0; + class TestAllocHandle { typedef LinkHashNode Node; public: - HashValue* alloc_value() + TestAllocHandle() : is_inited_(true) + {} + ~TestAllocHandle() + { + ATOMIC_STORE(&is_inited_, false); + } + HashValue *alloc_value() { + abort_unless(ATOMIC_LOAD(&is_inited_) == true); ATOMIC_INC(&value_alloc); HashValue* value = (HashValue*)ob_malloc(sizeof(HashValue), attr); new (value) HashValue(); @@ -79,12 +88,14 @@ public: } void free_value(HashValue* val) { + abort_unless(ATOMIC_LOAD(&is_inited_) == true); ATOMIC_INC(&value_free); val->~HashValue(); ob_free(val); } Node* alloc_node(HashValue* val) { + abort_unless(ATOMIC_LOAD(&is_inited_) == true); UNUSED(val); ATOMIC_INC(&node_alloc); Node* node = (Node*)ob_malloc(sizeof(Node), attr); @@ -93,10 +104,18 @@ public: } void free_node(Node* node) { + if (ATOMIC_LOAD(&STEP) == 1) { + IGNORE_RETURN ATOMIC_BCAS(&STEP, 1, 2); + usleep(1 * 1000 * 1000); + } + abort_unless(ATOMIC_LOAD(&is_inited_) == true); ATOMIC_INC(&node_free); node->~Node(); ob_free(node); } + +private: + bool is_inited_; }; class AtomicGetFunctor { @@ -118,9 +137,7 @@ static bool print(HashKey& key, HashValue* value) return true; } -// typedef ObLinkHashMap Hashmap; -typedef ObLinkHashMap Hashmap; -// typedef ObLinkHashMapWithHazardValue Hashmap; +typedef ObLinkHashMap Hashmap; TEST(TestObHashMap, Feature) { @@ -326,7 +343,37 @@ TEST(TestObHashMap, Stress) EXPECT_EQ(node_free, node_alloc); } -int main(int argc, char** argv) +TEST(TestObHashMap, Retire) +{ + std::thread *t; + { + Hashmap A; + HashKey key; + HashValue *val_ptr = nullptr; + EXPECT_EQ(OB_SUCCESS, A.init()); + key.v_ = 1; + EXPECT_EQ(OB_SUCCESS, A.create(key, val_ptr)); + A.revert(val_ptr); + EXPECT_EQ(OB_SUCCESS, A.del(key)); + ATOMIC_INC(&STEP); + t = new std::thread([&]() { + usleep(10 * 1000); + Hashmap B; + HashKey key; + EXPECT_EQ(OB_SUCCESS, B.init()); + key.v_ = 1; + EXPECT_EQ(OB_SUCCESS, B.create(key, val_ptr)); + B.revert(val_ptr); + }); + while (ATOMIC_LOAD(&STEP) != 2) + ; + // ~A() + } + t->join(); + delete t; +} + +int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); oceanbase::common::ObLogger::get_logger().set_file_name("test_link_hashmap.log", true);