/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #include "gtest/gtest.h" #include "lib/hash/ob_pointer_hashmap.h" using namespace oceanbase; using namespace common; using namespace hash; struct PairValue { int64_t key_; int64_t value_; PairValue() : key_(0), value_(0) { } PairValue(const int64_t key, const int64_t value) : key_(key), value_(value) { } int64_t get_key() const { return key_; } }; template struct GetKey { K operator()(const V value) const { return value->get_key(); } }; TEST(TestObPointerHashMap, basic_test) { ObPointerHashMap hashmap; PairValue val1(1, 1); PairValue val2(2, 2); PairValue *val = NULL; ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(1, &val1)); ASSERT_EQ(OB_HASH_EXIST, hashmap.set_refactored(1, &val1)); ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(1, &val1, 1)); ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(1, &val1, 1, 1)); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(1, val)); ASSERT_EQ(1, val->value_); ASSERT_EQ(1, (*hashmap.get(1))->value_); ASSERT_EQ(1, hashmap.count()); ASSERT_EQ(1, hashmap.item_count()); ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(2, &val2)); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(2, val)); ASSERT_EQ(2, val->value_); ASSERT_EQ(2, hashmap.count()); ASSERT_EQ(2, hashmap.item_count()); ASSERT_EQ(OB_SUCCESS, hashmap.erase_refactored(2L)); ASSERT_EQ(OB_HASH_NOT_EXIST, hashmap.erase_refactored(2L)); ASSERT_EQ(OB_HASH_NOT_EXIST, hashmap.get_refactored(2, val)); ASSERT_EQ(1, hashmap.item_count()); hashmap.clear(); ASSERT_EQ(0, hashmap.count()); ASSERT_EQ(0, hashmap.item_count()); } //TODO TEST(TestObPointerHashMap, test_erase) { ObPointerHashMap hashmap; PairValue pair; pair.key_ = 1; for (int64_t i = 0; i < 11000; ++i) { pair.value_ = i; ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pair.key_, &pair)); ASSERT_EQ(OB_SUCCESS, hashmap.erase_refactored(pair.key_)); } } TEST(TestObPointerHashMap, test_erase_many) { const int64_t size_16k = 16 * 1024; const int64_t count = 1000; ObPointerHashMap hashmap; // 16K can contain 1400+ ponter for (int64_t j = 0; j < 1000; ++j) { // repeat 100 times, and will not extends PairValue *pair = new PairValue[count]; for (int64_t i = 0; i < count; ++i) { static int64_t value = 0; value++; pair[i].key_ = value; pair[i].value_ = value; ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pair[i].key_, &pair[i], 1, 1)); } for (int64_t i = 0; i < count; ++i) { ASSERT_EQ(OB_SUCCESS, hashmap.erase_refactored(pair[i].key_)); } printf("item_count=%ld, count=%ld\n", hashmap.item_count(), hashmap.count()); delete []pair; pair = NULL; } ASSERT_EQ(size_16k, hashmap.get_sub_map_mem_size()); } TEST(TestObPointerHashMap, test_two_submap) { ObPointerHashMap hashmap; PairValue *pairs = new PairValue[300000]; for (int64_t i = 0; i < 300000; ++i) { pairs[i].key_ = i; pairs[i].value_ = i; } PairValue *val = NULL; for (int64_t i = 0; i < 300000; ++i) { ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pairs[i].key_, &pairs[i])); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); ASSERT_EQ(i + 1, hashmap.count()); ASSERT_EQ(i + 1, hashmap.item_count()); } ASSERT_EQ(300000, hashmap.count()); ASSERT_EQ(300000, hashmap.item_count()); for (int64_t i = 0; i < 300000; i += 100) { ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pairs[i].key_, &pairs[i], 1)); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); } ASSERT_EQ(300000, hashmap.count()); ASSERT_EQ(300000, hashmap.item_count()); for (int64_t i = 0; i < 300000; i += 100) { ASSERT_EQ(OB_SUCCESS, hashmap.erase_refactored(pairs[i].key_)); ASSERT_EQ(OB_HASH_NOT_EXIST, hashmap.erase_refactored(pairs[i].key_)); ASSERT_EQ(OB_HASH_NOT_EXIST, hashmap.get_refactored(pairs[i].key_, val)); } ASSERT_EQ(300000, hashmap.count()); ASSERT_EQ(300000 - 3000, hashmap.item_count()); // test reuse all erased pos for (int64_t i = 0; i < 300000; i += 100) { ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pairs[i].key_, &pairs[i])); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); } ASSERT_EQ(300000, hashmap.count()); ASSERT_EQ(300000, hashmap.item_count()); hashmap.clear(); ASSERT_EQ(0, hashmap.count()); ASSERT_EQ(0, hashmap.item_count()); //reuse ok for (int64_t i = 0; i < 300000; ++i) { ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pairs[i].key_, &pairs[i])); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); ASSERT_EQ(i + 1, hashmap.count()); } ASSERT_EQ(300000, hashmap.count()); ASSERT_EQ(300000, hashmap.item_count()); //copy ObPointerHashMap hashmap_copy(hashmap); for (int64_t i = 0; i < 300000; ++i) { ASSERT_EQ(OB_SUCCESS, hashmap_copy.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); } ASSERT_EQ(300000, hashmap_copy.count()); ASSERT_EQ(300000, hashmap_copy.item_count()); delete [] pairs; } TEST(TestObPointerHashMap, test_large_pairs) { ObPointerHashMap hashmap; int64_t pair_count = 1000000; PairValue *pairs = new PairValue[pair_count]; for (int64_t i = 0; i < pair_count; ++i) { pairs[i].key_ = i; pairs[i].value_ = i; } PairValue *val = NULL; for (int64_t i = 0; i < pair_count; ++i) { ASSERT_EQ(OB_SUCCESS, hashmap.set_refactored(pairs[i].key_, &pairs[i])); ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); ASSERT_EQ(i, val->value_); ASSERT_EQ(i + 1, hashmap.count()); ASSERT_EQ(i + 1, hashmap.item_count()); } ASSERT_EQ(pair_count, hashmap.count()); ASSERT_EQ(pair_count, hashmap.item_count()); delete [] pairs; } TEST(TestObPointerHashMap, test_micro_benchmark) { ObPointerHashMap hashmap; int64_t pair_count = 250000; PairValue *pairs = new PairValue[pair_count]; for (int64_t i = 0; i < pair_count; ++i) { pairs[i].key_ = i; pairs[i].value_ = i; } int64_t start_time = ::oceanbase::common::ObTimeUtility::current_time(); for (int64_t i = 0; i < pair_count; ++i) { hashmap.set_refactored(pairs[i].key_, &pairs[i]); if (0 == i % 3) { hashmap.erase_refactored(pairs[i].key_); } } int64_t end_time = ::oceanbase::common::ObTimeUtility::current_time(); int64_t set_time = end_time - start_time; PairValue *val = NULL; start_time = ::oceanbase::common::ObTimeUtility::current_time(); for (int64_t j = 0; j < 10; ++ j) { for (int64_t i = 0; i < pair_count; ++i) { if (0 != i % 3) { ASSERT_EQ(OB_SUCCESS, hashmap.get_refactored(pairs[i].key_, val)); } else { ASSERT_EQ(OB_HASH_NOT_EXIST, hashmap.get_refactored(pairs[i].key_, val)); } } } end_time = ::oceanbase::common::ObTimeUtility::current_time(); int64_t get_time = end_time - start_time; int64_t set_count = pair_count * 4 / 3; printf("hash map set_count=%ld, set_time=%ld, set_rate=%ld, get_count=%ld, " "get_time=%ld, get_rate=%ld\n", set_count, set_time, set_count * 1000L * 1000L / set_time, pair_count * 10, get_time, pair_count * 10 * 1000L * 1000L / get_time); delete [] pairs; } int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }