/root/bitcoin/src/leveldb/db/skiplist.h
| Line | Count | Source | 
| 1 |  | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. | 
| 2 |  | // Use of this source code is governed by a BSD-style license that can be | 
| 3 |  | // found in the LICENSE file. See the AUTHORS file for names of contributors. | 
| 4 |  |  | 
| 5 |  | #ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ | 
| 6 |  | #define STORAGE_LEVELDB_DB_SKIPLIST_H_ | 
| 7 |  |  | 
| 8 |  | // Thread safety | 
| 9 |  | // ------------- | 
| 10 |  | // | 
| 11 |  | // Writes require external synchronization, most likely a mutex. | 
| 12 |  | // Reads require a guarantee that the SkipList will not be destroyed | 
| 13 |  | // while the read is in progress.  Apart from that, reads progress | 
| 14 |  | // without any internal locking or synchronization. | 
| 15 |  | // | 
| 16 |  | // Invariants: | 
| 17 |  | // | 
| 18 |  | // (1) Allocated nodes are never deleted until the SkipList is | 
| 19 |  | // destroyed.  This is trivially guaranteed by the code since we | 
| 20 |  | // never delete any skip list nodes. | 
| 21 |  | // | 
| 22 |  | // (2) The contents of a Node except for the next/prev pointers are | 
| 23 |  | // immutable after the Node has been linked into the SkipList. | 
| 24 |  | // Only Insert() modifies the list, and it is careful to initialize | 
| 25 |  | // a node and use release-stores to publish the nodes in one or | 
| 26 |  | // more lists. | 
| 27 |  | // | 
| 28 |  | // ... prev vs. next pointer ordering ... | 
| 29 |  |  | 
| 30 |  | #include <atomic> | 
| 31 |  | #include <cassert> | 
| 32 |  | #include <cstdlib> | 
| 33 |  |  | 
| 34 |  | #include "util/arena.h" | 
| 35 |  | #include "util/random.h" | 
| 36 |  |  | 
| 37 |  | namespace leveldb { | 
| 38 |  |  | 
| 39 |  | class Arena; | 
| 40 |  |  | 
| 41 |  | template <typename Key, class Comparator> | 
| 42 |  | class SkipList { | 
| 43 |  |  private: | 
| 44 |  |   struct Node; | 
| 45 |  |  | 
| 46 |  |  public: | 
| 47 |  |   // Create a new SkipList object that will use "cmp" for comparing keys, | 
| 48 |  |   // and will allocate memory using "*arena".  Objects allocated in the arena | 
| 49 |  |   // must remain allocated for the lifetime of the skiplist object. | 
| 50 |  |   explicit SkipList(Comparator cmp, Arena* arena); | 
| 51 |  |  | 
| 52 |  |   SkipList(const SkipList&) = delete; | 
| 53 |  |   SkipList& operator=(const SkipList&) = delete; | 
| 54 |  |  | 
| 55 |  |   // Insert key into the list. | 
| 56 |  |   // REQUIRES: nothing that compares equal to key is currently in the list. | 
| 57 |  |   void Insert(const Key& key); | 
| 58 |  |  | 
| 59 |  |   // Returns true iff an entry that compares equal to key is in the list. | 
| 60 |  |   bool Contains(const Key& key) const; | 
| 61 |  |  | 
| 62 |  |   // Iteration over the contents of a skip list | 
| 63 |  |   class Iterator { | 
| 64 |  |    public: | 
| 65 |  |     // Initialize an iterator over the specified list. | 
| 66 |  |     // The returned iterator is not valid. | 
| 67 |  |     explicit Iterator(const SkipList* list); | 
| 68 |  |  | 
| 69 |  |     // Returns true iff the iterator is positioned at a valid node. | 
| 70 |  |     bool Valid() const; | 
| 71 |  |  | 
| 72 |  |     // Returns the key at the current position. | 
| 73 |  |     // REQUIRES: Valid() | 
| 74 |  |     const Key& key() const; | 
| 75 |  |  | 
| 76 |  |     // Advances to the next position. | 
| 77 |  |     // REQUIRES: Valid() | 
| 78 |  |     void Next(); | 
| 79 |  |  | 
| 80 |  |     // Advances to the previous position. | 
| 81 |  |     // REQUIRES: Valid() | 
| 82 |  |     void Prev(); | 
| 83 |  |  | 
| 84 |  |     // Advance to the first entry with a key >= target | 
| 85 |  |     void Seek(const Key& target); | 
| 86 |  |  | 
| 87 |  |     // Position at the first entry in list. | 
| 88 |  |     // Final state of iterator is Valid() iff list is not empty. | 
| 89 |  |     void SeekToFirst(); | 
| 90 |  |  | 
| 91 |  |     // Position at the last entry in list. | 
| 92 |  |     // Final state of iterator is Valid() iff list is not empty. | 
| 93 |  |     void SeekToLast(); | 
| 94 |  |  | 
| 95 |  |    private: | 
| 96 |  |     const SkipList* list_; | 
| 97 |  |     Node* node_; | 
| 98 |  |     // Intentionally copyable | 
| 99 |  |   }; | 
| 100 |  |  | 
| 101 |  |  private: | 
| 102 |  |   enum { kMaxHeight = 12 }; | 
| 103 |  |  | 
| 104 | 0 |   inline int GetMaxHeight() const { | 
| 105 | 0 |     return max_height_.load(std::memory_order_relaxed); | 
| 106 | 0 |   } | 
| 107 |  |  | 
| 108 |  |   Node* NewNode(const Key& key, int height); | 
| 109 |  |   int RandomHeight(); | 
| 110 | 0 |   bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } | 
| 111 |  |  | 
| 112 |  |   // Return true if key is greater than the data stored in "n" | 
| 113 |  |   bool KeyIsAfterNode(const Key& key, Node* n) const; | 
| 114 |  |  | 
| 115 |  |   // Return the earliest node that comes at or after key. | 
| 116 |  |   // Return nullptr if there is no such node. | 
| 117 |  |   // | 
| 118 |  |   // If prev is non-null, fills prev[level] with pointer to previous | 
| 119 |  |   // node at "level" for every level in [0..max_height_-1]. | 
| 120 |  |   Node* FindGreaterOrEqual(const Key& key, Node** prev) const; | 
| 121 |  |  | 
| 122 |  |   // Return the latest node with a key < key. | 
| 123 |  |   // Return head_ if there is no such node. | 
| 124 |  |   Node* FindLessThan(const Key& key) const; | 
| 125 |  |  | 
| 126 |  |   // Return the last node in the list. | 
| 127 |  |   // Return head_ if list is empty. | 
| 128 |  |   Node* FindLast() const; | 
| 129 |  |  | 
| 130 |  |   // Immutable after construction | 
| 131 |  |   Comparator const compare_; | 
| 132 |  |   Arena* const arena_;  // Arena used for allocations of nodes | 
| 133 |  |  | 
| 134 |  |   Node* const head_; | 
| 135 |  |  | 
| 136 |  |   // Modified only by Insert().  Read racily by readers, but stale | 
| 137 |  |   // values are ok. | 
| 138 |  |   std::atomic<int> max_height_;  // Height of the entire list | 
| 139 |  |  | 
| 140 |  |   // Read/written only by Insert(). | 
| 141 |  |   Random rnd_; | 
| 142 |  | }; | 
| 143 |  |  | 
| 144 |  | // Implementation details follow | 
| 145 |  | template <typename Key, class Comparator> | 
| 146 |  | struct SkipList<Key, Comparator>::Node { | 
| 147 | 0 |   explicit Node(const Key& k) : key(k) {} | 
| 148 |  |  | 
| 149 |  |   Key const key; | 
| 150 |  |  | 
| 151 |  |   // Accessors/mutators for links.  Wrapped in methods so we can | 
| 152 |  |   // add the appropriate barriers as necessary. | 
| 153 | 0 |   Node* Next(int n) { | 
| 154 | 0 |     assert(n >= 0); | 
| 155 |  |     // Use an 'acquire load' so that we observe a fully initialized | 
| 156 |  |     // version of the returned Node. | 
| 157 | 0 |     return next_[n].load(std::memory_order_acquire); | 
| 158 | 0 |   } | 
| 159 | 0 |   void SetNext(int n, Node* x) { | 
| 160 | 0 |     assert(n >= 0); | 
| 161 |  |     // Use a 'release store' so that anybody who reads through this | 
| 162 |  |     // pointer observes a fully initialized version of the inserted node. | 
| 163 | 0 |     next_[n].store(x, std::memory_order_release); | 
| 164 | 0 |   } | 
| 165 |  |  | 
| 166 |  |   // No-barrier variants that can be safely used in a few locations. | 
| 167 | 0 |   Node* NoBarrier_Next(int n) { | 
| 168 | 0 |     assert(n >= 0); | 
| 169 | 0 |     return next_[n].load(std::memory_order_relaxed); | 
| 170 | 0 |   } | 
| 171 | 0 |   void NoBarrier_SetNext(int n, Node* x) { | 
| 172 | 0 |     assert(n >= 0); | 
| 173 | 0 |     next_[n].store(x, std::memory_order_relaxed); | 
| 174 | 0 |   } | 
| 175 |  |  | 
| 176 |  |  private: | 
| 177 |  |   // Array of length equal to the node height.  next_[0] is lowest level link. | 
| 178 |  |   std::atomic<Node*> next_[1]; | 
| 179 |  | }; | 
| 180 |  |  | 
| 181 |  | template <typename Key, class Comparator> | 
| 182 |  | typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::NewNode( | 
| 183 | 0 |     const Key& key, int height) { | 
| 184 | 0 |   char* const node_memory = arena_->AllocateAligned( | 
| 185 | 0 |       sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1)); | 
| 186 | 0 |   return new (node_memory) Node(key); | 
| 187 | 0 | } | 
| 188 |  |  | 
| 189 |  | template <typename Key, class Comparator> | 
| 190 | 0 | inline SkipList<Key, Comparator>::Iterator::Iterator(const SkipList* list) { | 
| 191 | 0 |   list_ = list; | 
| 192 | 0 |   node_ = nullptr; | 
| 193 | 0 | } | 
| 194 |  |  | 
| 195 |  | template <typename Key, class Comparator> | 
| 196 | 0 | inline bool SkipList<Key, Comparator>::Iterator::Valid() const { | 
| 197 | 0 |   return node_ != nullptr; | 
| 198 | 0 | } | 
| 199 |  |  | 
| 200 |  | template <typename Key, class Comparator> | 
| 201 | 0 | inline const Key& SkipList<Key, Comparator>::Iterator::key() const { | 
| 202 | 0 |   assert(Valid()); | 
| 203 | 0 |   return node_->key; | 
| 204 | 0 | } | 
| 205 |  |  | 
| 206 |  | template <typename Key, class Comparator> | 
| 207 | 0 | inline void SkipList<Key, Comparator>::Iterator::Next() { | 
| 208 | 0 |   assert(Valid()); | 
| 209 | 0 |   node_ = node_->Next(0); | 
| 210 | 0 | } | 
| 211 |  |  | 
| 212 |  | template <typename Key, class Comparator> | 
| 213 | 0 | inline void SkipList<Key, Comparator>::Iterator::Prev() { | 
| 214 |  |   // Instead of using explicit "prev" links, we just search for the | 
| 215 |  |   // last node that falls before key. | 
| 216 | 0 |   assert(Valid()); | 
| 217 | 0 |   node_ = list_->FindLessThan(node_->key); | 
| 218 | 0 |   if (node_ == list_->head_) { | 
| 219 | 0 |     node_ = nullptr; | 
| 220 | 0 |   } | 
| 221 | 0 | } | 
| 222 |  |  | 
| 223 |  | template <typename Key, class Comparator> | 
| 224 | 0 | inline void SkipList<Key, Comparator>::Iterator::Seek(const Key& target) { | 
| 225 | 0 |   node_ = list_->FindGreaterOrEqual(target, nullptr); | 
| 226 | 0 | } | 
| 227 |  |  | 
| 228 |  | template <typename Key, class Comparator> | 
| 229 | 0 | inline void SkipList<Key, Comparator>::Iterator::SeekToFirst() { | 
| 230 | 0 |   node_ = list_->head_->Next(0); | 
| 231 | 0 | } | 
| 232 |  |  | 
| 233 |  | template <typename Key, class Comparator> | 
| 234 | 0 | inline void SkipList<Key, Comparator>::Iterator::SeekToLast() { | 
| 235 | 0 |   node_ = list_->FindLast(); | 
| 236 | 0 |   if (node_ == list_->head_) { | 
| 237 | 0 |     node_ = nullptr; | 
| 238 | 0 |   } | 
| 239 | 0 | } | 
| 240 |  |  | 
| 241 |  | template <typename Key, class Comparator> | 
| 242 | 0 | int SkipList<Key, Comparator>::RandomHeight() { | 
| 243 |  |   // Increase height with probability 1 in kBranching | 
| 244 | 0 |   static const unsigned int kBranching = 4; | 
| 245 | 0 |   int height = 1; | 
| 246 | 0 |   while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { | 
| 247 | 0 |     height++; | 
| 248 | 0 |   } | 
| 249 | 0 |   assert(height > 0); | 
| 250 | 0 |   assert(height <= kMaxHeight); | 
| 251 | 0 |   return height; | 
| 252 | 0 | } | 
| 253 |  |  | 
| 254 |  | template <typename Key, class Comparator> | 
| 255 | 0 | bool SkipList<Key, Comparator>::KeyIsAfterNode(const Key& key, Node* n) const { | 
| 256 |  |   // null n is considered infinite | 
| 257 | 0 |   return (n != nullptr) && (compare_(n->key, key) < 0); | 
| 258 | 0 | } | 
| 259 |  |  | 
| 260 |  | template <typename Key, class Comparator> | 
| 261 |  | typename SkipList<Key, Comparator>::Node* | 
| 262 |  | SkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key, | 
| 263 | 0 |                                               Node** prev) const { | 
| 264 | 0 |   Node* x = head_; | 
| 265 | 0 |   int level = GetMaxHeight() - 1; | 
| 266 | 0 |   while (true) { | 
| 267 | 0 |     Node* next = x->Next(level); | 
| 268 | 0 |     if (KeyIsAfterNode(key, next)) { | 
| 269 |  |       // Keep searching in this list | 
| 270 | 0 |       x = next; | 
| 271 | 0 |     } else { | 
| 272 | 0 |       if (prev != nullptr) prev[level] = x; | 
| 273 | 0 |       if (level == 0) { | 
| 274 | 0 |         return next; | 
| 275 | 0 |       } else { | 
| 276 |  |         // Switch to next list | 
| 277 | 0 |         level--; | 
| 278 | 0 |       } | 
| 279 | 0 |     } | 
| 280 | 0 |   } | 
| 281 | 0 | } | 
| 282 |  |  | 
| 283 |  | template <typename Key, class Comparator> | 
| 284 |  | typename SkipList<Key, Comparator>::Node* | 
| 285 | 0 | SkipList<Key, Comparator>::FindLessThan(const Key& key) const { | 
| 286 | 0 |   Node* x = head_; | 
| 287 | 0 |   int level = GetMaxHeight() - 1; | 
| 288 | 0 |   while (true) { | 
| 289 | 0 |     assert(x == head_ || compare_(x->key, key) < 0); | 
| 290 | 0 |     Node* next = x->Next(level); | 
| 291 | 0 |     if (next == nullptr || compare_(next->key, key) >= 0) { | 
| 292 | 0 |       if (level == 0) { | 
| 293 | 0 |         return x; | 
| 294 | 0 |       } else { | 
| 295 |  |         // Switch to next list | 
| 296 | 0 |         level--; | 
| 297 | 0 |       } | 
| 298 | 0 |     } else { | 
| 299 | 0 |       x = next; | 
| 300 | 0 |     } | 
| 301 | 0 |   } | 
| 302 | 0 | } | 
| 303 |  |  | 
| 304 |  | template <typename Key, class Comparator> | 
| 305 |  | typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::FindLast() | 
| 306 | 0 |     const { | 
| 307 | 0 |   Node* x = head_; | 
| 308 | 0 |   int level = GetMaxHeight() - 1; | 
| 309 | 0 |   while (true) { | 
| 310 | 0 |     Node* next = x->Next(level); | 
| 311 | 0 |     if (next == nullptr) { | 
| 312 | 0 |       if (level == 0) { | 
| 313 | 0 |         return x; | 
| 314 | 0 |       } else { | 
| 315 |  |         // Switch to next list | 
| 316 | 0 |         level--; | 
| 317 | 0 |       } | 
| 318 | 0 |     } else { | 
| 319 | 0 |       x = next; | 
| 320 | 0 |     } | 
| 321 | 0 |   } | 
| 322 | 0 | } | 
| 323 |  |  | 
| 324 |  | template <typename Key, class Comparator> | 
| 325 |  | SkipList<Key, Comparator>::SkipList(Comparator cmp, Arena* arena) | 
| 326 | 0 |     : compare_(cmp), | 
| 327 | 0 |       arena_(arena), | 
| 328 | 0 |       head_(NewNode(0 /* any key will do */, kMaxHeight)), | 
| 329 | 0 |       max_height_(1), | 
| 330 | 0 |       rnd_(0xdeadbeef) { | 
| 331 | 0 |   for (int i = 0; i < kMaxHeight; i++) { | 
| 332 | 0 |     head_->SetNext(i, nullptr); | 
| 333 | 0 |   } | 
| 334 | 0 | } | 
| 335 |  |  | 
| 336 |  | template <typename Key, class Comparator> | 
| 337 | 0 | void SkipList<Key, Comparator>::Insert(const Key& key) { | 
| 338 |  |   // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() | 
| 339 |  |   // here since Insert() is externally synchronized. | 
| 340 | 0 |   Node* prev[kMaxHeight]; | 
| 341 | 0 |   Node* x = FindGreaterOrEqual(key, prev); | 
| 342 |  |  | 
| 343 |  |   // Our data structure does not allow duplicate insertion | 
| 344 | 0 |   assert(x == nullptr || !Equal(key, x->key)); | 
| 345 |  |  | 
| 346 | 0 |   int height = RandomHeight(); | 
| 347 | 0 |   if (height > GetMaxHeight()) { | 
| 348 | 0 |     for (int i = GetMaxHeight(); i < height; i++) { | 
| 349 | 0 |       prev[i] = head_; | 
| 350 | 0 |     } | 
| 351 |  |     // It is ok to mutate max_height_ without any synchronization | 
| 352 |  |     // with concurrent readers.  A concurrent reader that observes | 
| 353 |  |     // the new value of max_height_ will see either the old value of | 
| 354 |  |     // new level pointers from head_ (nullptr), or a new value set in | 
| 355 |  |     // the loop below.  In the former case the reader will | 
| 356 |  |     // immediately drop to the next level since nullptr sorts after all | 
| 357 |  |     // keys.  In the latter case the reader will use the new node. | 
| 358 | 0 |     max_height_.store(height, std::memory_order_relaxed); | 
| 359 | 0 |   } | 
| 360 |  | 
 | 
| 361 | 0 |   x = NewNode(key, height); | 
| 362 | 0 |   for (int i = 0; i < height; i++) { | 
| 363 |  |     // NoBarrier_SetNext() suffices since we will add a barrier when | 
| 364 |  |     // we publish a pointer to "x" in prev[i]. | 
| 365 | 0 |     x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); | 
| 366 | 0 |     prev[i]->SetNext(i, x); | 
| 367 | 0 |   } | 
| 368 | 0 | } | 
| 369 |  |  | 
| 370 |  | template <typename Key, class Comparator> | 
| 371 |  | bool SkipList<Key, Comparator>::Contains(const Key& key) const { | 
| 372 |  |   Node* x = FindGreaterOrEqual(key, nullptr); | 
| 373 |  |   if (x != nullptr && Equal(key, x->key)) { | 
| 374 |  |     return true; | 
| 375 |  |   } else { | 
| 376 |  |     return false; | 
| 377 |  |   } | 
| 378 |  | } | 
| 379 |  |  | 
| 380 |  | }  // namespace leveldb | 
| 381 |  |  | 
| 382 |  | #endif  // STORAGE_LEVELDB_DB_SKIPLIST_H_ |