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