LCOV - code coverage report
Current view: top level - src/leveldb/db - skiplist.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 90 145 62.1 %
Date: 2022-04-21 14:51:19 Functions: 19 23 82.6 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 21 36 58.3 %

           Branch data     Line data    Source code
#       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                 :   11057780 :   inline int GetMaxHeight() const {
#     105                 :   11057780 :     return max_height_.load(std::memory_order_relaxed);
#     106                 :   11057780 :   }
#     107                 :            : 
#     108                 :            :   Node* NewNode(const Key& key, int height);
#     109                 :            :   int RandomHeight();
#     110                 :     463567 :   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                 :     481710 :   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                 :  225641612 :   Node* Next(int n) {
#     154                 :  225641612 :     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                 :  225641612 :   }
#     159                 :     669388 :   void SetNext(int n, Node* x) {
#     160                 :     669388 :     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                 :     669388 :   }
#     165                 :            : 
#     166                 :            :   // No-barrier variants that can be safely used in a few locations.
#     167                 :     631468 :   Node* NoBarrier_Next(int n) {
#     168                 :     631468 :     assert(n >= 0);
#     169                 :          0 :     return next_[n].load(std::memory_order_relaxed);
#     170                 :     631468 :   }
#     171                 :     631468 :   void NoBarrier_SetNext(int n, Node* x) {
#     172                 :     631468 :     assert(n >= 0);
#     173                 :          0 :     next_[n].store(x, std::memory_order_relaxed);
#     174                 :     631468 :   }
#     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                 :     481710 :     const Key& key, int height) {
#     184                 :     481710 :   char* const node_memory = arena_->AllocateAligned(
#     185                 :     481710 :       sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1));
#     186                 :     481710 :   return new (node_memory) Node(key);
#     187                 :     481710 : }
#     188                 :            : 
#     189                 :            : template <typename Key, class Comparator>
#     190                 :   10096281 : inline SkipList<Key, Comparator>::Iterator::Iterator(const SkipList* list) {
#     191                 :   10096281 :   list_ = list;
#     192                 :   10096281 :   node_ = nullptr;
#     193                 :   10096281 : }
#     194                 :            : 
#     195                 :            : template <typename Key, class Comparator>
#     196                 :   20013866 : inline bool SkipList<Key, Comparator>::Iterator::Valid() const {
#     197                 :   20013866 :   return node_ != nullptr;
#     198                 :   20013866 : }
#     199                 :            : 
#     200                 :            : template <typename Key, class Comparator>
#     201                 :    9554523 : inline const Key& SkipList<Key, Comparator>::Iterator::key() const {
#     202                 :    9554523 :   assert(Valid());
#     203                 :          0 :   return node_->key;
#     204                 :    9554523 : }
#     205                 :            : 
#     206                 :            : template <typename Key, class Comparator>
#     207                 :     177324 : inline void SkipList<Key, Comparator>::Iterator::Next() {
#     208                 :     177324 :   assert(Valid());
#     209                 :          0 :   node_ = node_->Next(0);
#     210                 :     177324 : }
#     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                 :   10094817 : inline void SkipList<Key, Comparator>::Iterator::Seek(const Key& target) {
#     225                 :   10094817 :   node_ = list_->FindGreaterOrEqual(target, nullptr);
#     226                 :   10094817 : }
#     227                 :            : 
#     228                 :            : template <typename Key, class Comparator>
#     229                 :       1468 : inline void SkipList<Key, Comparator>::Iterator::SeekToFirst() {
#     230                 :       1468 :   node_ = list_->head_->Next(0);
#     231                 :       1468 : }
#     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                 :     478550 : int SkipList<Key, Comparator>::RandomHeight() {
#     243                 :            :   // Increase height with probability 1 in kBranching
#     244                 :     478550 :   static const unsigned int kBranching = 4;
#     245                 :     478550 :   int height = 1;
#     246 [ +  - ][ +  + ]:     631468 :   while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
#     247                 :     152918 :     height++;
#     248                 :     152918 :   }
#     249                 :     478550 :   assert(height > 0);
#     250                 :          0 :   assert(height <= kMaxHeight);
#     251                 :          0 :   return height;
#     252                 :     478550 : }
#     253                 :            : 
#     254                 :            : template <typename Key, class Comparator>
#     255                 :  225475187 : bool SkipList<Key, Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
#     256                 :            :   // null n is considered infinite
#     257 [ +  + ][ +  + ]:  225475187 :   return (n != nullptr) && (compare_(n->key, key) < 0);
#     258                 :  225475187 : }
#     259                 :            : 
#     260                 :            : template <typename Key, class Comparator>
#     261                 :            : typename SkipList<Key, Comparator>::Node*
#     262                 :            : SkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key,
#     263                 :   10573367 :                                               Node** prev) const {
#     264                 :   10573367 :   Node* x = head_;
#     265                 :   10573367 :   int level = GetMaxHeight() - 1;
#     266                 :  225475185 :   while (true) {
#     267                 :  225475185 :     Node* next = x->Next(level);
#     268         [ +  + ]:  225475185 :     if (KeyIsAfterNode(key, next)) {
#     269                 :            :       // Keep searching in this list
#     270                 :  150093760 :       x = next;
#     271                 :  150093760 :     } else {
#     272         [ +  + ]:   75381425 :       if (prev != nullptr) prev[level] = x;
#     273         [ +  + ]:   75381425 :       if (level == 0) {
#     274                 :   10573367 :         return next;
#     275                 :   64808058 :       } else {
#     276                 :            :         // Switch to next list
#     277                 :   64808058 :         level--;
#     278                 :   64808058 :       }
#     279                 :   75381425 :     }
#     280                 :  225475185 :   }
#     281                 :   10573367 : }
#     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                 :            :     : compare_(cmp),
#     327                 :            :       arena_(arena),
#     328                 :            :       head_(NewNode(0 /* any key will do */, kMaxHeight)),
#     329                 :            :       max_height_(1),
#     330                 :       3160 :       rnd_(0xdeadbeef) {
#     331         [ +  + ]:      41080 :   for (int i = 0; i < kMaxHeight; i++) {
#     332                 :      37920 :     head_->SetNext(i, nullptr);
#     333                 :      37920 :   }
#     334                 :       3160 : }
#     335                 :            : 
#     336                 :            : template <typename Key, class Comparator>
#     337                 :     478550 : 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                 :     478550 :   Node* prev[kMaxHeight];
#     341                 :     478550 :   Node* x = FindGreaterOrEqual(key, prev);
#     342                 :            : 
#     343                 :            :   // Our data structure does not allow duplicate insertion
#     344                 :     478550 :   assert(x == nullptr || !Equal(key, x->key));
#     345                 :            : 
#     346                 :          0 :   int height = RandomHeight();
#     347         [ +  + ]:     478550 :   if (height > GetMaxHeight()) {
#     348         [ +  + ]:      12721 :     for (int i = GetMaxHeight(); i < height; i++) {
#     349                 :       6858 :       prev[i] = head_;
#     350                 :       6858 :     }
#     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                 :       5863 :     max_height_.store(height, std::memory_order_relaxed);
#     359                 :       5863 :   }
#     360                 :            : 
#     361                 :     478550 :   x = NewNode(key, height);
#     362         [ +  + ]:    1110018 :   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                 :     631468 :     x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
#     366                 :     631468 :     prev[i]->SetNext(i, x);
#     367                 :     631468 :   }
#     368                 :     478550 : }
#     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_

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a