hash_skiplist_rep.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // Copyright (c) 2011-present, 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. #ifndef ROCKSDB_LITE
  7. #include "memtable/hash_skiplist_rep.h"
  8. #include <atomic>
  9. #include "db/memtable.h"
  10. #include "memory/arena.h"
  11. #include "memtable/skiplist.h"
  12. #include "port/port.h"
  13. #include "rocksdb/memtablerep.h"
  14. #include "rocksdb/slice.h"
  15. #include "rocksdb/slice_transform.h"
  16. #include "util/murmurhash.h"
  17. namespace ROCKSDB_NAMESPACE {
  18. namespace {
  19. class HashSkipListRep : public MemTableRep {
  20. public:
  21. HashSkipListRep(const MemTableRep::KeyComparator& compare,
  22. Allocator* allocator, const SliceTransform* transform,
  23. size_t bucket_size, int32_t skiplist_height,
  24. int32_t skiplist_branching_factor);
  25. void Insert(KeyHandle handle) override;
  26. bool Contains(const char* key) const override;
  27. size_t ApproximateMemoryUsage() override;
  28. void Get(const LookupKey& k, void* callback_args,
  29. bool (*callback_func)(void* arg, const char* entry)) override;
  30. ~HashSkipListRep() override;
  31. MemTableRep::Iterator* GetIterator(Arena* arena = nullptr) override;
  32. MemTableRep::Iterator* GetDynamicPrefixIterator(
  33. Arena* arena = nullptr) override;
  34. private:
  35. friend class DynamicIterator;
  36. typedef SkipList<const char*, const MemTableRep::KeyComparator&> Bucket;
  37. size_t bucket_size_;
  38. const int32_t skiplist_height_;
  39. const int32_t skiplist_branching_factor_;
  40. // Maps slices (which are transformed user keys) to buckets of keys sharing
  41. // the same transform.
  42. std::atomic<Bucket*>* buckets_;
  43. // The user-supplied transform whose domain is the user keys.
  44. const SliceTransform* transform_;
  45. const MemTableRep::KeyComparator& compare_;
  46. // immutable after construction
  47. Allocator* const allocator_;
  48. inline size_t GetHash(const Slice& slice) const {
  49. return MurmurHash(slice.data(), static_cast<int>(slice.size()), 0) %
  50. bucket_size_;
  51. }
  52. inline Bucket* GetBucket(size_t i) const {
  53. return buckets_[i].load(std::memory_order_acquire);
  54. }
  55. inline Bucket* GetBucket(const Slice& slice) const {
  56. return GetBucket(GetHash(slice));
  57. }
  58. // Get a bucket from buckets_. If the bucket hasn't been initialized yet,
  59. // initialize it before returning.
  60. Bucket* GetInitializedBucket(const Slice& transformed);
  61. class Iterator : public MemTableRep::Iterator {
  62. public:
  63. explicit Iterator(Bucket* list, bool own_list = true,
  64. Arena* arena = nullptr)
  65. : list_(list), iter_(list), own_list_(own_list), arena_(arena) {}
  66. ~Iterator() override {
  67. // if we own the list, we should also delete it
  68. if (own_list_) {
  69. assert(list_ != nullptr);
  70. delete list_;
  71. }
  72. }
  73. // Returns true iff the iterator is positioned at a valid node.
  74. bool Valid() const override { return list_ != nullptr && iter_.Valid(); }
  75. // Returns the key at the current position.
  76. // REQUIRES: Valid()
  77. const char* key() const override {
  78. assert(Valid());
  79. return iter_.key();
  80. }
  81. // Advances to the next position.
  82. // REQUIRES: Valid()
  83. void Next() override {
  84. assert(Valid());
  85. iter_.Next();
  86. }
  87. // Advances to the previous position.
  88. // REQUIRES: Valid()
  89. void Prev() override {
  90. assert(Valid());
  91. iter_.Prev();
  92. }
  93. // Advance to the first entry with a key >= target
  94. void Seek(const Slice& internal_key, const char* memtable_key) override {
  95. if (list_ != nullptr) {
  96. const char* encoded_key =
  97. (memtable_key != nullptr) ?
  98. memtable_key : EncodeKey(&tmp_, internal_key);
  99. iter_.Seek(encoded_key);
  100. }
  101. }
  102. // Retreat to the last entry with a key <= target
  103. void SeekForPrev(const Slice& /*internal_key*/,
  104. const char* /*memtable_key*/) override {
  105. // not supported
  106. assert(false);
  107. }
  108. // Position at the first entry in collection.
  109. // Final state of iterator is Valid() iff collection is not empty.
  110. void SeekToFirst() override {
  111. if (list_ != nullptr) {
  112. iter_.SeekToFirst();
  113. }
  114. }
  115. // Position at the last entry in collection.
  116. // Final state of iterator is Valid() iff collection is not empty.
  117. void SeekToLast() override {
  118. if (list_ != nullptr) {
  119. iter_.SeekToLast();
  120. }
  121. }
  122. protected:
  123. void Reset(Bucket* list) {
  124. if (own_list_) {
  125. assert(list_ != nullptr);
  126. delete list_;
  127. }
  128. list_ = list;
  129. iter_.SetList(list);
  130. own_list_ = false;
  131. }
  132. private:
  133. // if list_ is nullptr, we should NEVER call any methods on iter_
  134. // if list_ is nullptr, this Iterator is not Valid()
  135. Bucket* list_;
  136. Bucket::Iterator iter_;
  137. // here we track if we own list_. If we own it, we are also
  138. // responsible for it's cleaning. This is a poor man's std::shared_ptr
  139. bool own_list_;
  140. std::unique_ptr<Arena> arena_;
  141. std::string tmp_; // For passing to EncodeKey
  142. };
  143. class DynamicIterator : public HashSkipListRep::Iterator {
  144. public:
  145. explicit DynamicIterator(const HashSkipListRep& memtable_rep)
  146. : HashSkipListRep::Iterator(nullptr, false),
  147. memtable_rep_(memtable_rep) {}
  148. // Advance to the first entry with a key >= target
  149. void Seek(const Slice& k, const char* memtable_key) override {
  150. auto transformed = memtable_rep_.transform_->Transform(ExtractUserKey(k));
  151. Reset(memtable_rep_.GetBucket(transformed));
  152. HashSkipListRep::Iterator::Seek(k, memtable_key);
  153. }
  154. // Position at the first entry in collection.
  155. // Final state of iterator is Valid() iff collection is not empty.
  156. void SeekToFirst() override {
  157. // Prefix iterator does not support total order.
  158. // We simply set the iterator to invalid state
  159. Reset(nullptr);
  160. }
  161. // Position at the last entry in collection.
  162. // Final state of iterator is Valid() iff collection is not empty.
  163. void SeekToLast() override {
  164. // Prefix iterator does not support total order.
  165. // We simply set the iterator to invalid state
  166. Reset(nullptr);
  167. }
  168. private:
  169. // the underlying memtable
  170. const HashSkipListRep& memtable_rep_;
  171. };
  172. class EmptyIterator : public MemTableRep::Iterator {
  173. // This is used when there wasn't a bucket. It is cheaper than
  174. // instantiating an empty bucket over which to iterate.
  175. public:
  176. EmptyIterator() { }
  177. bool Valid() const override { return false; }
  178. const char* key() const override {
  179. assert(false);
  180. return nullptr;
  181. }
  182. void Next() override {}
  183. void Prev() override {}
  184. void Seek(const Slice& /*internal_key*/,
  185. const char* /*memtable_key*/) override {}
  186. void SeekForPrev(const Slice& /*internal_key*/,
  187. const char* /*memtable_key*/) override {}
  188. void SeekToFirst() override {}
  189. void SeekToLast() override {}
  190. private:
  191. };
  192. };
  193. HashSkipListRep::HashSkipListRep(const MemTableRep::KeyComparator& compare,
  194. Allocator* allocator,
  195. const SliceTransform* transform,
  196. size_t bucket_size, int32_t skiplist_height,
  197. int32_t skiplist_branching_factor)
  198. : MemTableRep(allocator),
  199. bucket_size_(bucket_size),
  200. skiplist_height_(skiplist_height),
  201. skiplist_branching_factor_(skiplist_branching_factor),
  202. transform_(transform),
  203. compare_(compare),
  204. allocator_(allocator) {
  205. auto mem = allocator->AllocateAligned(
  206. sizeof(std::atomic<void*>) * bucket_size);
  207. buckets_ = new (mem) std::atomic<Bucket*>[bucket_size];
  208. for (size_t i = 0; i < bucket_size_; ++i) {
  209. buckets_[i].store(nullptr, std::memory_order_relaxed);
  210. }
  211. }
  212. HashSkipListRep::~HashSkipListRep() {
  213. }
  214. HashSkipListRep::Bucket* HashSkipListRep::GetInitializedBucket(
  215. const Slice& transformed) {
  216. size_t hash = GetHash(transformed);
  217. auto bucket = GetBucket(hash);
  218. if (bucket == nullptr) {
  219. auto addr = allocator_->AllocateAligned(sizeof(Bucket));
  220. bucket = new (addr) Bucket(compare_, allocator_, skiplist_height_,
  221. skiplist_branching_factor_);
  222. buckets_[hash].store(bucket, std::memory_order_release);
  223. }
  224. return bucket;
  225. }
  226. void HashSkipListRep::Insert(KeyHandle handle) {
  227. auto* key = static_cast<char*>(handle);
  228. assert(!Contains(key));
  229. auto transformed = transform_->Transform(UserKey(key));
  230. auto bucket = GetInitializedBucket(transformed);
  231. bucket->Insert(key);
  232. }
  233. bool HashSkipListRep::Contains(const char* key) const {
  234. auto transformed = transform_->Transform(UserKey(key));
  235. auto bucket = GetBucket(transformed);
  236. if (bucket == nullptr) {
  237. return false;
  238. }
  239. return bucket->Contains(key);
  240. }
  241. size_t HashSkipListRep::ApproximateMemoryUsage() {
  242. return 0;
  243. }
  244. void HashSkipListRep::Get(const LookupKey& k, void* callback_args,
  245. bool (*callback_func)(void* arg, const char* entry)) {
  246. auto transformed = transform_->Transform(k.user_key());
  247. auto bucket = GetBucket(transformed);
  248. if (bucket != nullptr) {
  249. Bucket::Iterator iter(bucket);
  250. for (iter.Seek(k.memtable_key().data());
  251. iter.Valid() && callback_func(callback_args, iter.key());
  252. iter.Next()) {
  253. }
  254. }
  255. }
  256. MemTableRep::Iterator* HashSkipListRep::GetIterator(Arena* arena) {
  257. // allocate a new arena of similar size to the one currently in use
  258. Arena* new_arena = new Arena(allocator_->BlockSize());
  259. auto list = new Bucket(compare_, new_arena);
  260. for (size_t i = 0; i < bucket_size_; ++i) {
  261. auto bucket = GetBucket(i);
  262. if (bucket != nullptr) {
  263. Bucket::Iterator itr(bucket);
  264. for (itr.SeekToFirst(); itr.Valid(); itr.Next()) {
  265. list->Insert(itr.key());
  266. }
  267. }
  268. }
  269. if (arena == nullptr) {
  270. return new Iterator(list, true, new_arena);
  271. } else {
  272. auto mem = arena->AllocateAligned(sizeof(Iterator));
  273. return new (mem) Iterator(list, true, new_arena);
  274. }
  275. }
  276. MemTableRep::Iterator* HashSkipListRep::GetDynamicPrefixIterator(Arena* arena) {
  277. if (arena == nullptr) {
  278. return new DynamicIterator(*this);
  279. } else {
  280. auto mem = arena->AllocateAligned(sizeof(DynamicIterator));
  281. return new (mem) DynamicIterator(*this);
  282. }
  283. }
  284. } // anon namespace
  285. MemTableRep* HashSkipListRepFactory::CreateMemTableRep(
  286. const MemTableRep::KeyComparator& compare, Allocator* allocator,
  287. const SliceTransform* transform, Logger* /*logger*/) {
  288. return new HashSkipListRep(compare, allocator, transform, bucket_count_,
  289. skiplist_height_, skiplist_branching_factor_);
  290. }
  291. MemTableRepFactory* NewHashSkipListRepFactory(
  292. size_t bucket_count, int32_t skiplist_height,
  293. int32_t skiplist_branching_factor) {
  294. return new HashSkipListRepFactory(bucket_count, skiplist_height,
  295. skiplist_branching_factor);
  296. }
  297. } // namespace ROCKSDB_NAMESPACE
  298. #endif // ROCKSDB_LITE