hash_table_test.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (c) 2013, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. #include <stdlib.h>
  7. #include <iostream>
  8. #include <set>
  9. #include <string>
  10. #include "db/db_test_util.h"
  11. #include "memory/arena.h"
  12. #include "test_util/testharness.h"
  13. #include "util/random.h"
  14. #include "utilities/persistent_cache/hash_table.h"
  15. #include "utilities/persistent_cache/hash_table_evictable.h"
  16. #ifndef ROCKSDB_LITE
  17. namespace ROCKSDB_NAMESPACE {
  18. struct HashTableTest : public testing::Test {
  19. ~HashTableTest() override { map_.Clear(&HashTableTest::ClearNode); }
  20. struct Node {
  21. Node() {}
  22. explicit Node(const uint64_t key, const std::string& val = std::string())
  23. : key_(key), val_(val) {}
  24. uint64_t key_ = 0;
  25. std::string val_;
  26. };
  27. struct Equal {
  28. bool operator()(const Node& lhs, const Node& rhs) {
  29. return lhs.key_ == rhs.key_;
  30. }
  31. };
  32. struct Hash {
  33. uint64_t operator()(const Node& node) {
  34. return std::hash<uint64_t>()(node.key_);
  35. }
  36. };
  37. static void ClearNode(Node /*node*/) {}
  38. HashTable<Node, Hash, Equal> map_;
  39. };
  40. struct EvictableHashTableTest : public testing::Test {
  41. ~EvictableHashTableTest() override {
  42. map_.Clear(&EvictableHashTableTest::ClearNode);
  43. }
  44. struct Node : LRUElement<Node> {
  45. Node() {}
  46. explicit Node(const uint64_t key, const std::string& val = std::string())
  47. : key_(key), val_(val) {}
  48. uint64_t key_ = 0;
  49. std::string val_;
  50. std::atomic<uint32_t> refs_{0};
  51. };
  52. struct Equal {
  53. bool operator()(const Node* lhs, const Node* rhs) {
  54. return lhs->key_ == rhs->key_;
  55. }
  56. };
  57. struct Hash {
  58. uint64_t operator()(const Node* node) {
  59. return std::hash<uint64_t>()(node->key_);
  60. }
  61. };
  62. static void ClearNode(Node* /*node*/) {}
  63. EvictableHashTable<Node, Hash, Equal> map_;
  64. };
  65. TEST_F(HashTableTest, TestInsert) {
  66. const uint64_t max_keys = 1024 * 1024;
  67. // insert
  68. for (uint64_t k = 0; k < max_keys; ++k) {
  69. map_.Insert(Node(k, std::string(1000, k % 255)));
  70. }
  71. // verify
  72. for (uint64_t k = 0; k < max_keys; ++k) {
  73. Node val;
  74. port::RWMutex* rlock = nullptr;
  75. assert(map_.Find(Node(k), &val, &rlock));
  76. rlock->ReadUnlock();
  77. assert(val.val_ == std::string(1000, k % 255));
  78. }
  79. }
  80. TEST_F(HashTableTest, TestErase) {
  81. const uint64_t max_keys = 1024 * 1024;
  82. // insert
  83. for (uint64_t k = 0; k < max_keys; ++k) {
  84. map_.Insert(Node(k, std::string(1000, k % 255)));
  85. }
  86. auto rand = Random64(time(nullptr));
  87. // erase a few keys randomly
  88. std::set<uint64_t> erased;
  89. for (int i = 0; i < 1024; ++i) {
  90. uint64_t k = rand.Next() % max_keys;
  91. if (erased.find(k) != erased.end()) {
  92. continue;
  93. }
  94. assert(map_.Erase(Node(k), /*ret=*/nullptr));
  95. erased.insert(k);
  96. }
  97. // verify
  98. for (uint64_t k = 0; k < max_keys; ++k) {
  99. Node val;
  100. port::RWMutex* rlock = nullptr;
  101. bool status = map_.Find(Node(k), &val, &rlock);
  102. if (erased.find(k) == erased.end()) {
  103. assert(status);
  104. rlock->ReadUnlock();
  105. assert(val.val_ == std::string(1000, k % 255));
  106. } else {
  107. assert(!status);
  108. }
  109. }
  110. }
  111. TEST_F(EvictableHashTableTest, TestEvict) {
  112. const uint64_t max_keys = 1024 * 1024;
  113. // insert
  114. for (uint64_t k = 0; k < max_keys; ++k) {
  115. map_.Insert(new Node(k, std::string(1000, k % 255)));
  116. }
  117. // verify
  118. for (uint64_t k = 0; k < max_keys; ++k) {
  119. Node* val = map_.Evict();
  120. // unfortunately we can't predict eviction value since it is from any one of
  121. // the lock stripe
  122. assert(val);
  123. assert(val->val_ == std::string(1000, val->key_ % 255));
  124. delete val;
  125. }
  126. }
  127. } // namespace ROCKSDB_NAMESPACE
  128. #endif
  129. int main(int argc, char** argv) {
  130. ::testing::InitGoogleTest(&argc, argv);
  131. return RUN_ALL_TESTS();
  132. }