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 #include "db/memtable.h"
7 #include "memory/arena.h"
8 #include "memtable/inlineskiplist.h"
9 #include "rocksdb/memtablerep.h"
10
11 namespace ROCKSDB_NAMESPACE {
12 namespace {
13 class SkipListRep : public MemTableRep {
14 InlineSkipList<const MemTableRep::KeyComparator&> skip_list_;
15 const MemTableRep::KeyComparator& cmp_;
16 const SliceTransform* transform_;
17 const size_t lookahead_;
18
19 friend class LookaheadIterator;
20 public:
SkipListRep(const MemTableRep::KeyComparator & compare,Allocator * allocator,const SliceTransform * transform,const size_t lookahead)21 explicit SkipListRep(const MemTableRep::KeyComparator& compare,
22 Allocator* allocator, const SliceTransform* transform,
23 const size_t lookahead)
24 : MemTableRep(allocator),
25 skip_list_(compare, allocator),
26 cmp_(compare),
27 transform_(transform),
28 lookahead_(lookahead) {}
29
Allocate(const size_t len,char ** buf)30 KeyHandle Allocate(const size_t len, char** buf) override {
31 *buf = skip_list_.AllocateKey(len);
32 return static_cast<KeyHandle>(*buf);
33 }
34
35 // Insert key into the list.
36 // REQUIRES: nothing that compares equal to key is currently in the list.
Insert(KeyHandle handle)37 void Insert(KeyHandle handle) override {
38 skip_list_.Insert(static_cast<char*>(handle));
39 }
40
InsertKey(KeyHandle handle)41 bool InsertKey(KeyHandle handle) override {
42 return skip_list_.Insert(static_cast<char*>(handle));
43 }
44
InsertWithHint(KeyHandle handle,void ** hint)45 void InsertWithHint(KeyHandle handle, void** hint) override {
46 skip_list_.InsertWithHint(static_cast<char*>(handle), hint);
47 }
48
InsertKeyWithHint(KeyHandle handle,void ** hint)49 bool InsertKeyWithHint(KeyHandle handle, void** hint) override {
50 return skip_list_.InsertWithHint(static_cast<char*>(handle), hint);
51 }
52
InsertWithHintConcurrently(KeyHandle handle,void ** hint)53 void InsertWithHintConcurrently(KeyHandle handle, void** hint) override {
54 skip_list_.InsertWithHintConcurrently(static_cast<char*>(handle), hint);
55 }
56
InsertKeyWithHintConcurrently(KeyHandle handle,void ** hint)57 bool InsertKeyWithHintConcurrently(KeyHandle handle, void** hint) override {
58 return skip_list_.InsertWithHintConcurrently(static_cast<char*>(handle),
59 hint);
60 }
61
InsertConcurrently(KeyHandle handle)62 void InsertConcurrently(KeyHandle handle) override {
63 skip_list_.InsertConcurrently(static_cast<char*>(handle));
64 }
65
InsertKeyConcurrently(KeyHandle handle)66 bool InsertKeyConcurrently(KeyHandle handle) override {
67 return skip_list_.InsertConcurrently(static_cast<char*>(handle));
68 }
69
70 // Returns true iff an entry that compares equal to key is in the list.
Contains(const char * key) const71 bool Contains(const char* key) const override {
72 return skip_list_.Contains(key);
73 }
74
ApproximateMemoryUsage()75 size_t ApproximateMemoryUsage() override {
76 // All memory is allocated through allocator; nothing to report here
77 return 0;
78 }
79
Get(const LookupKey & k,void * callback_args,bool (* callback_func)(void * arg,const char * entry))80 void Get(const LookupKey& k, void* callback_args,
81 bool (*callback_func)(void* arg, const char* entry)) override {
82 SkipListRep::Iterator iter(&skip_list_);
83 Slice dummy_slice;
84 for (iter.Seek(dummy_slice, k.memtable_key().data());
85 iter.Valid() && callback_func(callback_args, iter.key()); iter.Next()) {
86 }
87 }
88
ApproximateNumEntries(const Slice & start_ikey,const Slice & end_ikey)89 uint64_t ApproximateNumEntries(const Slice& start_ikey,
90 const Slice& end_ikey) override {
91 std::string tmp;
92 uint64_t start_count =
93 skip_list_.EstimateCount(EncodeKey(&tmp, start_ikey));
94 uint64_t end_count = skip_list_.EstimateCount(EncodeKey(&tmp, end_ikey));
95 return (end_count >= start_count) ? (end_count - start_count) : 0;
96 }
97
~SkipListRep()98 ~SkipListRep() override {}
99
100 // Iteration over the contents of a skip list
101 class Iterator : public MemTableRep::Iterator {
102 InlineSkipList<const MemTableRep::KeyComparator&>::Iterator iter_;
103
104 public:
105 // Initialize an iterator over the specified list.
106 // The returned iterator is not valid.
Iterator(const InlineSkipList<const MemTableRep::KeyComparator &> * list)107 explicit Iterator(
108 const InlineSkipList<const MemTableRep::KeyComparator&>* list)
109 : iter_(list) {}
110
~Iterator()111 ~Iterator() override {}
112
113 // Returns true iff the iterator is positioned at a valid node.
Valid() const114 bool Valid() const override { return iter_.Valid(); }
115
116 // Returns the key at the current position.
117 // REQUIRES: Valid()
key() const118 const char* key() const override { return iter_.key(); }
119
120 // Advances to the next position.
121 // REQUIRES: Valid()
Next()122 void Next() override { iter_.Next(); }
123
124 // Advances to the previous position.
125 // REQUIRES: Valid()
Prev()126 void Prev() override { iter_.Prev(); }
127
128 // Advance to the first entry with a key >= target
Seek(const Slice & user_key,const char * memtable_key)129 void Seek(const Slice& user_key, const char* memtable_key) override {
130 if (memtable_key != nullptr) {
131 iter_.Seek(memtable_key);
132 } else {
133 iter_.Seek(EncodeKey(&tmp_, user_key));
134 }
135 }
136
137 // Retreat to the last entry with a key <= target
SeekForPrev(const Slice & user_key,const char * memtable_key)138 void SeekForPrev(const Slice& user_key, const char* memtable_key) override {
139 if (memtable_key != nullptr) {
140 iter_.SeekForPrev(memtable_key);
141 } else {
142 iter_.SeekForPrev(EncodeKey(&tmp_, user_key));
143 }
144 }
145
146 // Position at the first entry in list.
147 // Final state of iterator is Valid() iff list is not empty.
SeekToFirst()148 void SeekToFirst() override { iter_.SeekToFirst(); }
149
150 // Position at the last entry in list.
151 // Final state of iterator is Valid() iff list is not empty.
SeekToLast()152 void SeekToLast() override { iter_.SeekToLast(); }
153
154 protected:
155 std::string tmp_; // For passing to EncodeKey
156 };
157
158 // Iterator over the contents of a skip list which also keeps track of the
159 // previously visited node. In Seek(), it examines a few nodes after it
160 // first, falling back to O(log n) search from the head of the list only if
161 // the target key hasn't been found.
162 class LookaheadIterator : public MemTableRep::Iterator {
163 public:
LookaheadIterator(const SkipListRep & rep)164 explicit LookaheadIterator(const SkipListRep& rep) :
165 rep_(rep), iter_(&rep_.skip_list_), prev_(iter_) {}
166
~LookaheadIterator()167 ~LookaheadIterator() override {}
168
Valid() const169 bool Valid() const override { return iter_.Valid(); }
170
key() const171 const char* key() const override {
172 assert(Valid());
173 return iter_.key();
174 }
175
Next()176 void Next() override {
177 assert(Valid());
178
179 bool advance_prev = true;
180 if (prev_.Valid()) {
181 auto k1 = rep_.UserKey(prev_.key());
182 auto k2 = rep_.UserKey(iter_.key());
183
184 if (k1.compare(k2) == 0) {
185 // same user key, don't move prev_
186 advance_prev = false;
187 } else if (rep_.transform_) {
188 // only advance prev_ if it has the same prefix as iter_
189 auto t1 = rep_.transform_->Transform(k1);
190 auto t2 = rep_.transform_->Transform(k2);
191 advance_prev = t1.compare(t2) == 0;
192 }
193 }
194
195 if (advance_prev) {
196 prev_ = iter_;
197 }
198 iter_.Next();
199 }
200
Prev()201 void Prev() override {
202 assert(Valid());
203 iter_.Prev();
204 prev_ = iter_;
205 }
206
Seek(const Slice & internal_key,const char * memtable_key)207 void Seek(const Slice& internal_key, const char* memtable_key) override {
208 const char *encoded_key =
209 (memtable_key != nullptr) ?
210 memtable_key : EncodeKey(&tmp_, internal_key);
211
212 if (prev_.Valid() && rep_.cmp_(encoded_key, prev_.key()) >= 0) {
213 // prev_.key() is smaller or equal to our target key; do a quick
214 // linear search (at most lookahead_ steps) starting from prev_
215 iter_ = prev_;
216
217 size_t cur = 0;
218 while (cur++ <= rep_.lookahead_ && iter_.Valid()) {
219 if (rep_.cmp_(encoded_key, iter_.key()) <= 0) {
220 return;
221 }
222 Next();
223 }
224 }
225
226 iter_.Seek(encoded_key);
227 prev_ = iter_;
228 }
229
SeekForPrev(const Slice & internal_key,const char * memtable_key)230 void SeekForPrev(const Slice& internal_key,
231 const char* memtable_key) override {
232 const char* encoded_key = (memtable_key != nullptr)
233 ? memtable_key
234 : EncodeKey(&tmp_, internal_key);
235 iter_.SeekForPrev(encoded_key);
236 prev_ = iter_;
237 }
238
SeekToFirst()239 void SeekToFirst() override {
240 iter_.SeekToFirst();
241 prev_ = iter_;
242 }
243
SeekToLast()244 void SeekToLast() override {
245 iter_.SeekToLast();
246 prev_ = iter_;
247 }
248
249 protected:
250 std::string tmp_; // For passing to EncodeKey
251
252 private:
253 const SkipListRep& rep_;
254 InlineSkipList<const MemTableRep::KeyComparator&>::Iterator iter_;
255 InlineSkipList<const MemTableRep::KeyComparator&>::Iterator prev_;
256 };
257
GetIterator(Arena * arena=nullptr)258 MemTableRep::Iterator* GetIterator(Arena* arena = nullptr) override {
259 if (lookahead_ > 0) {
260 void *mem =
261 arena ? arena->AllocateAligned(sizeof(SkipListRep::LookaheadIterator))
262 : operator new(sizeof(SkipListRep::LookaheadIterator));
263 return new (mem) SkipListRep::LookaheadIterator(*this);
264 } else {
265 void *mem =
266 arena ? arena->AllocateAligned(sizeof(SkipListRep::Iterator))
267 : operator new(sizeof(SkipListRep::Iterator));
268 return new (mem) SkipListRep::Iterator(&skip_list_);
269 }
270 }
271 };
272 }
273
CreateMemTableRep(const MemTableRep::KeyComparator & compare,Allocator * allocator,const SliceTransform * transform,Logger *)274 MemTableRep* SkipListFactory::CreateMemTableRep(
275 const MemTableRep::KeyComparator& compare, Allocator* allocator,
276 const SliceTransform* transform, Logger* /*logger*/) {
277 return new SkipListRep(compare, allocator, transform, lookahead_);
278 }
279
280 } // namespace ROCKSDB_NAMESPACE
281