zoukankan      html  css  js  c++  java
  • leveldb 学习记录(四) skiplist补与变长数字

    leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明

    这里在介绍 下skiplist的代码

    里面有几个模块  

    template<typename Key, class Comparator>
    class SkipList {......}

    class Arena;(内存池模块 暂时不介绍)

    struct Node;(节点 存储key 和指向其他Node的指针)

    //Node 构造函数  KEY赋值
    // Implementation details follow
    template<typename Key, class Comparator>
    struct SkipList<Key,Comparator>::Node {
      explicit Node(const Key& k) : key(k) { }
    
      Key const key;
    
      // Accessors/mutators for links.  Wrapped in methods so we can
      // add the appropriate barriers as necessary.
      // 访问修改器使用 包装在方法中 可以使用内存屏障
      // Node指向的另一层?
      Node* Next(int n) {
        assert(n >= 0);
        // Use an 'acquire load' so that we observe a fully initialized
        // version of the returned Node.
        return reinterpret_cast<Node*>(next_[n].Acquire_Load());
      }
      //设置下层Node指向
      void SetNext(int n, Node* x) {
        assert(n >= 0);
        // Use a 'release store' so that anybody who reads through this
        // pointer observes a fully initialized version of the inserted node.
        next_[n].Release_Store(x);
      }
    
      // No-barrier variants that can be safely used in a few locations.
      // 读取本Node在N层的NODE指向  非内存屏蔽操作
      Node* NoBarrier_Next(int n) {
        assert(n >= 0);
        return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
      }
      
      //设置Node 在N层的Node指向  非内存屏蔽操作 
      void NoBarrier_SetNext(int n, Node* x) {
        assert(n >= 0);
        next_[n].NoBarrier_Store(x);
      }
    
     private:
      // Array of length equal to the node height.  next_[0] is lowest level link.
      // 原子指针数组  指向其他Node  创建时候动态确认数组长度
      port::AtomicPointer next_[1];
    };
    

      

    结构示意图如下

    其他操作可参见系列文章一

    最后附上我注释的代码

      1 #include <assert.h>
      2 #include <stdlib.h>
      3 #include "port/port.h"
      4 #include "util/arena.h"
      5 #include "util/random.h"
      6 
      7 namespace leveldb {
      8 
      9 class Arena;
     10 
     11 template<typename Key, class Comparator>
     12 class SkipList {
     13  private:
     14   struct Node;
     15 
     16  public:
     17   // Create a new SkipList object that will use "cmp" for comparing keys,
     18   // and will allocate memory using "*arena".  Objects allocated in the arena
     19   // must remain allocated for the lifetime of the skiplist object.
     20   explicit SkipList(Comparator cmp, Arena* arena);
     21 
     22   // Insert key into the list.
     23   // REQUIRES: nothing that compares equal to key is currently in the list.
     24   void Insert(const Key& key);
     25 
     26   // Returns true iff an entry that compares equal to key is in the list.
     27   bool Contains(const Key& key) const;
     28 
     29   // Iteration over the contents of a skip list
     30   class Iterator {
     31    public:
     32     // Initialize an iterator over the specified list.
     33     // The returned iterator is not valid.
     34     explicit Iterator(const SkipList* list);
     35 
     36     // Returns true iff the iterator is positioned at a valid node.
     37     bool Valid() const;
     38 
     39     // Returns the key at the current position.
     40     // REQUIRES: Valid()
     41     const Key& key() const;
     42 
     43     // Advances to the next position.
     44     // REQUIRES: Valid()
     45     void Next();
     46 
     47     // Advances to the previous position.
     48     // REQUIRES: Valid()
     49     void Prev();
     50 
     51     // Advance to the first entry with a key >= target
     52     void Seek(const Key& target);
     53 
     54     // Position at the first entry in list.
     55     // Final state of iterator is Valid() iff list is not empty.
     56     void SeekToFirst();
     57 
     58     // Position at the last entry in list.
     59     // Final state of iterator is Valid() iff list is not empty.
     60     void SeekToLast();
     61 
     62    private:
     63     const SkipList* list_;
     64     Node* node_;
     65     // Intentionally copyable
     66   };
     67 
     68  private:
     69   enum { kMaxHeight = 12 };
     70 
     71   // Immutable after construction
     72   Comparator const compare_;
     73   Arena* const arena_;    // Arena used for allocations of nodes
     74 
     75   Node* const head_;
     76 
     77   // Modified only by Insert().  Read racily by readers, but stale
     78   // values are ok.
     79   port::AtomicPointer max_height_;   // Height of the entire list
     80 
     81   inline int GetMaxHeight() const {
     82     return reinterpret_cast<intptr_t>(max_height_.NoBarrier_Load());
     83   }
     84 
     85   // Read/written only by Insert().
     86   Random rnd_;
     87 
     88   Node* NewNode(const Key& key, int height);
     89   int RandomHeight();
     90   bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }
     91 
     92   // Return true if key is greater than the data stored in "n"
     93   bool KeyIsAfterNode(const Key& key, Node* n) const;
     94 
     95   // Return the earliest node that comes at or after key.
     96   // Return NULL if there is no such node.
     97   //
     98   // If prev is non-NULL, fills prev[level] with pointer to previous
     99   // node at "level" for every level in [0..max_height_-1].
    100   Node* FindGreaterOrEqual(const Key& key, Node** prev) const;
    101 
    102   // Return the latest node with a key < key.
    103   // Return head_ if there is no such node.
    104   Node* FindLessThan(const Key& key) const;
    105 
    106   // Return the last node in the list.
    107   // Return head_ if list is empty.
    108   Node* FindLast() const;
    109 
    110   // No copying allowed
    111   SkipList(const SkipList&);
    112   void operator=(const SkipList&);
    113 };
    114 
    115 
    116 //Node 构造函数  KEY赋值
    117 // Implementation details follow
    118 template<typename Key, class Comparator>
    119 struct SkipList<Key,Comparator>::Node {
    120   explicit Node(const Key& k) : key(k) { }
    121 
    122   Key const key;
    123 
    124   // Accessors/mutators for links.  Wrapped in methods so we can
    125   // add the appropriate barriers as necessary.
    126   // 访问修改器使用 包装在方法中 可以使用内存屏障
    127   // Node指向的另一层?
    128   Node* Next(int n) {
    129     assert(n >= 0);
    130     // Use an 'acquire load' so that we observe a fully initialized
    131     // version of the returned Node.
    132     return reinterpret_cast<Node*>(next_[n].Acquire_Load());
    133   }
    134   //设置下层Node指向
    135   void SetNext(int n, Node* x) {
    136     assert(n >= 0);
    137     // Use a 'release store' so that anybody who reads through this
    138     // pointer observes a fully initialized version of the inserted node.
    139     next_[n].Release_Store(x);
    140   }
    141 
    142   // No-barrier variants that can be safely used in a few locations.
    143   // 读取本Node在N层的NODE指向  非内存屏蔽操作
    144   Node* NoBarrier_Next(int n) {
    145     assert(n >= 0);
    146     return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
    147   }
    148   
    149   //设置Node 在N层的Node指向  非内存屏蔽操作 
    150   void NoBarrier_SetNext(int n, Node* x) {
    151     assert(n >= 0);
    152     next_[n].NoBarrier_Store(x);
    153   }
    154 
    155  private:
    156   // Array of length equal to the node height.  next_[0] is lowest level link.
    157   // 原子指针数组  指向其他Node  创建时候动态确认数组长度
    158   port::AtomicPointer next_[1];
    159 };
    160 
    161 
    162 //创建一个NODE 内存池arena_分配内存  height确认该NODE的Node指向数量
    163 template<typename Key, class Comparator>
    164 typename SkipList<Key,Comparator>::Node*
    165 SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
    166   char* mem = arena_->AllocateAligned(
    167       sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1));
    168   return new (mem) Node(key);
    169 }
    170 
    171 //根据输入的SkipList指针构造一个  iterator
    172 template<typename Key, class Comparator>
    173 inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {
    174   list_ = list;
    175   node_ = NULL;
    176 }
    177 
    178 //
    179 template<typename Key, class Comparator>
    180 inline bool SkipList<Key,Comparator>::Iterator::Valid() const {
    181   return node_ != NULL;
    182 }
    183 
    184 
    185 //返回iterator指向的Node的key
    186 template<typename Key, class Comparator>
    187 inline const Key& SkipList<Key,Comparator>::Iterator::key() const {
    188   assert(Valid());
    189   return node_->key;
    190 }
    191 
    192 
    193 //获取iterator指向的下一个node  在第0层获取(Node第0层均有记录)
    194 template<typename Key, class Comparator>
    195 inline void SkipList<Key,Comparator>::Iterator::Next() {
    196   assert(Valid());
    197   node_ = node_->Next(0);
    198 }
    199 
    200 //寻找该node上一个node
    201 template<typename Key, class Comparator>
    202 inline void SkipList<Key,Comparator>::Iterator::Prev() {
    203   // Instead of using explicit "prev" links, we just search for the
    204   // last node that falls before key.
    205   assert(Valid());
    206   node_ = list_->FindLessThan(node_->key);
    207   if (node_ == list_->head_) {
    208     node_ = NULL;
    209   }
    210 }
    211 
    212 
    213 //调用 FindGreaterOrEqual 查找 
    214 template<typename Key, class Comparator>
    215 inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {
    216   node_ = list_->FindGreaterOrEqual(target, NULL);
    217 }
    218 
    219 //重置到head  Node 第0层 第一个Node
    220 template<typename Key, class Comparator>
    221 inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {
    222   node_ = list_->head_->Next(0);
    223 }
    224 
    225 //重置到last Node
    226 template<typename Key, class Comparator>
    227 inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {
    228   node_ = list_->FindLast();
    229   if (node_ == list_->head_) {
    230     node_ = NULL;
    231   }
    232 }
    233 
    234 
    235 //返回height  随机增加1
    236 template<typename Key, class Comparator>
    237 int SkipList<Key,Comparator>::RandomHeight() {
    238   // Increase height with probability 1 in kBranching
    239   static const unsigned int kBranching = 4;
    240   int height = 1;
    241   while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
    242     height++;
    243   }
    244   assert(height > 0);
    245   assert(height <= kMaxHeight);
    246   return height;
    247 }
    248 
    249 //调用 cmp 比较是大小
    250 template<typename Key, class Comparator>
    251 bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
    252   // NULL n is considered infinite
    253   return (n != NULL) && (compare_(n->key, key) < 0);
    254 }
    255 
    256 
    257 //寻找比key大或者等于的Node
    258 template<typename Key, class Comparator>
    259 typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
    260     const {
    261   Node* x = head_;
    262   int level = GetMaxHeight() - 1;
    263   //    k在Next后面 则在本level寻找 否则 在下一层level寻找
    264   while (true) {
    265     Node* next = x->(level);
    266     if (KeyIsAfterNode(key, next)) {
    267       // Keep searching in this list
    268       x = next;
    269     } else {
    270       if (prev != NULL) prev[level] = x;
    271       if (level == 0) {
    272         return next;
    273       } else {
    274         // Switch to next list
    275         level--;
    276       }
    277     }
    278   }
    279 }
    280 
    281 
    282 //寻找小于等于KEY的第一个NODE
    283 template<typename Key, class Comparator>
    284 typename SkipList<Key,Comparator>::Node*
    285 SkipList<Key,Comparator>::FindLessThan(const Key& key) const {
    286   Node* x = head_;
    287   int level = GetMaxHeight() - 1;
    288   while (true) {
    289     assert(x == head_ || compare_(x->key, key) < 0);
    290     Node* next = x->Next(level);
    291     if (next == NULL || compare_(next->key, key) >= 0) {
    292       if (level == 0) {
    293         return x;
    294       } else {
    295         // Switch to next list
    296         level--;
    297       }
    298     } else {
    299       x = next;
    300     }
    301   }
    302 }
    303 
    304 //在最高层 寻找最后一个Node
    305 template<typename Key, class Comparator>
    306 typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()
    307     const {
    308   Node* x = head_;
    309   int level = GetMaxHeight() - 1;
    310   while (true) {
    311     Node* next = x->Next(level);
    312     if (next == NULL) {
    313       if (level == 0) {
    314         return x;
    315       } else {
    316         // Switch to next list
    317         level--;
    318       }
    319     } else {
    320       x = next;
    321     }
    322   }
    323 }
    324 
    325 
    326 //构建函数 第一个head Node key是0 后继Node指针最大kMaxHeight
    327 template<typename Key, class Comparator>
    328 SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)
    329     : compare_(cmp),
    330       arena_(arena),
    331       head_(NewNode(0 /* any key will do */, kMaxHeight)),
    332       max_height_(reinterpret_cast<void*>(1)),
    333       rnd_(0xdeadbeef) {
    334   for (int i = 0; i < kMaxHeight; i++) {
    335     head_->SetNext(i, NULL);
    336   }
    337 }
    338 
    339 //insert算法
    340 template<typename Key, class Comparator>
    341 void SkipList<Key,Comparator>::Insert(const Key& key) {
    342   // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
    343   // here since Insert() is externally synchronized.
    344   Node* prev[kMaxHeight];
    345   Node* x = FindGreaterOrEqual(key, prev);
    346 
    347   // Our data structure does not allow duplicate insertion
    348   assert(x == NULL || !Equal(key, x->key));
    349 
    350   int height = RandomHeight();
    351   if (height > GetMaxHeight()) {
    352     for (int i = GetMaxHeight(); i < height; i++) {
    353       prev[i] = head_;
    354     }
    355     //fprintf(stderr, "Change height from %d to %d
    ", max_height_, height);
    356 
    357     // It is ok to mutate max_height_ without any synchronization
    358     // with concurrent readers.  A concurrent reader that observes
    359     // the new value of max_height_ will see either the old value of
    360     // new level pointers from head_ (NULL), or a new value set in
    361     // the loop below.  In the former case the reader will
    362     // immediately drop to the next level since NULL sorts after all
    363     // keys.  In the latter case the reader will use the new node.
    364     max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
    365   }
    366 
    367   x = NewNode(key, height);
    368   for (int i = 0; i < height; i++) {
    369     // NoBarrier_SetNext() suffices since we will add a barrier when
    370     // we publish a pointer to "x" in prev[i].
    371     x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
    372     prev[i]->SetNext(i, x);
    373   }
    374 }
    375 
    376 
    377 //寻找等于KEY 即可确认是否包含与KEY相等的Node
    378 template<typename Key, class Comparator>
    379 bool SkipList<Key,Comparator>::Contains(const Key& key) const {
    380   Node* x = FindGreaterOrEqual(key, NULL);
    381   if (x != NULL && Equal(key, x->key)) {
    382     return true;
    383   } else {
    384     return false;
    385   }
    386 }
    387 
    388 }
    View Code

     varint变长数

     leveldb使用了Protocol Buffers的变长字节整形编码 每个字节中使用7位来表示数字 最高位用作他处

    300的编码,编码后是两个字节:

    1010 1100 0000 0010

      它这个例子是每个字节左边是高位,可以看到每个字节的最高位是一个标识位,从左到右第一个字节是10101100,最高位是1,说明后面还有字节需要解码,然后第二个字节是00000010,最高位是0,后面没字节了。所以这两个字节就需要解码成一个整数,再往下看。

    代码
    1010 1100 0000 0010
    → 010 1100 000 0010 //每个字节去掉最高位
    → 000 0010 010 1100 //字节序转换,两个字节互换位置
    → 000 0010 ++ 010 1100 //两个字节进行链接操作(不是相加)
    → 100101100 //合并后的结果,高位位0的部分截取掉
    → 256 + 32 + 8 + 4 = 300 //每个值为1的bit位乘以以2为底的幂,得出编码后的值

    主要函数在 

    coding.h

    extern void PutFixed32(std::string* dst, uint32_t value);
    extern void PutFixed64(std::string* dst, uint64_t value);
    extern void PutVarint32(std::string* dst, uint32_t value);
    extern void PutVarint64(std::string* dst, uint64_t value);
    extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value);

    extern bool GetVarint32(Slice* input, uint32_t* value);
    extern bool GetVarint64(Slice* input, uint64_t* value);
    extern bool GetLengthPrefixedSlice(Slice* input, Slice* result);

    extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v);
    extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v);


    extern int VarintLength(uint64_t v);

    extern void EncodeFixed32(char* dst, uint32_t value);
    extern void EncodeFixed64(char* dst, uint64_t value);

    extern char* EncodeVarint32(char* dst, uint32_t value);
    extern char* EncodeVarint64(char* dst, uint64_t value);

    参考

    https://www.cnblogs.com/onlytiancai/archive/2010/10/16/1853003.html

     
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    自己写CPU第五级(5)——测试逻辑、实现移动和空指令
    ERROR: The partition with /var/lib/mysql is too full! failed!
    关于精益创业理念随想
    android使用ffmpeg
    如何让格斗游戏的横版过关(2) Cocos2d-x 2.0.4
    java两个音频进入巩固期 玩的同时类似的伴奏
    Java 反射 想
    SharePoint 2013 如何使用Silverlight
    如何才能连接到你的网站访客
    写作---英语中常见的写作错误有哪些
  • 原文地址:https://www.cnblogs.com/itdef/p/8834398.html
Copyright © 2011-2022 走看看