leveldb源代码分析4:SkipList

skiplist思想可以具体参考这:

或者是参考我的这篇博文:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html, leveldb中的实现方式基本上和我的那篇博文中的实现方式类似。SkipList在db/skiplist.h中声明,向外界暴漏接口非常简单,如下:

  1. // Create a new SkipList object that will use "cmp" for comparing keys,  
  2. // and will allocate memory using "*arena".  Objects allocated in the arena  
  3. // must remain allocated for the lifetime of the skiplist object.  
  4. explicit SkipList(Comparator cmp, Arena* arena);  
  5.   
  6. // Insert key into the list.  
  7. // REQUIRES: nothing that compares equal to key is currently in the list.  
  8. void Insert(const Key& key);  
  9.   
  10. // Returns true iff an entry that compares equal to key is in the list.  
  11. bool Contains(const Key& key) const;  

private成员变量:
  1. // 最大的level  
  2.   enum { kMaxHeight = 12 };  
  3.   
  4.   // Immutable after construction  
  5.   Comparator const compare_;  
  6.   // 内存分配器  
  7.   Arena* const arena_;    // Arena used for allocations of nodes  
  8.   
  9.     // 指向第一个节点,构造函数中初始化  
  10.   Node* const head_;  
  11.   
  12.   // Modified only by Insert().  Read racily by readers, but stale  
  13.   // values are ok.  
  14.   port::AtomicPointer max_height_;   // Height of the entire list  
我们下面来首先分析初始化操作,如下:
  1. // 初始化:  
  2. // 1. 初始化compare_  
  3. // 2. 初始化arena_  
  4. // 3. 初始化head_,指向指针数组  
  5. // 4. 初始化max_height_  
  6. // 5. 初始化rnd_随机数的seed  
  7. // 6. 初始化head_指向的数组  
  8. template<typename Key, class Comparator>  
  9. SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)  
  10.     : compare_(cmp),  
  11.       arena_(arena),  
  12.       head_(NewNode(0 /* any key will do */, kMaxHeight)),  
  13.       max_height_(reinterpret_cast<void*>(1)),  
  14.       rnd_(0xdeadbeef) {  
  15.           // 初始化head_指向的数组  
  16.   for (int i = 0; i < kMaxHeight; i++) {  
  17.     head_->SetNext(i, NULL);  
  18.   }  
  19. }  

下面是一个插入操作的示意图:


leveldb中实现的插入代码就是按照上面的思路实现,首先查找到合适的位置,并记录查找过程中经过的路径,之后新生成一个节点,修改指针。

  1. // 插入操作  
  2. // 这里的key其实已经是经过处理的key,包含了用户指定的key和value  
  3. template<typename Key, class Comparator>  
  4. void SkipList<Key,Comparator>::Insert(const Key& key) {  
  5.   // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()  
  6.   // here since Insert() is externally synchronized.  
  7.   // prev记录的是查询路径,下面需要使用prev来修改新生成  
  8.   // 节点的指针  
  9.   Node* prev[kMaxHeight];  
  10.   Node* x = FindGreaterOrEqual(key, prev);  
  11.   
  12.   // Our data structure does not allow duplicate insertion  
  13.   // 不允许插入重复的值  
  14.   assert(x == NULL || !Equal(key, x->key));  
  15.   
  16.     // 随即生成节点高度  
  17.   int height = RandomHeight();  
  18.   // 对prev数组中未赋值的元素进行赋值  
  19.   if (height > GetMaxHeight()) {  
  20.     for (int i = GetMaxHeight(); i < height; i++) {  
  21.       prev[i] = head_;  
  22.     }  
  23.   
  24.   
  25.     // It is ok to mutate max_height_ without any synchronization  
  26.     // with concurrent readers.  A concurrent reader that observes  
  27.     // the new value of max_height_ will see either the old value of  
  28.     // new level pointers from head_ (NULL), or a new value set in  
  29.     // the loop below.  In the former case the reader will  
  30.     // immediately drop to the next level since NULL sorts after all  
  31.     // keys.  In the latter case the reader will use the new node.  
  32.     // 设置max_height变量  
  33.     max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));  
  34.   }  
  35.   
  36.     // 新生成一个节点,之后插入数据  
  37.   x = NewNode(key, height);  
  38.   for (int i = 0; i < height; i++) {  
  39.     // NoBarrier_SetNext() suffices since we will add a barrier when  
  40.     // we publish a pointer to "x" in prev[i].  
  41.     // 修改两部分的指针,一部分是需要执行新插入节点的指针  
  42.     // 另外的一部分是x节点的指针  
  43.     x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));  
  44.     prev[i]->SetNext(i, x);  
  45.   }  
  46. }  

函数FindGreaterOrEqual中完成查询操作,就是向下(level控制)和向右(x控制)移动过程,并不断经经过路径保存到参数prev中。

  1. template<typename Key, class Comparator>  
  2. typename SkipList<Key,Comparator>::Node*   
  3. <span style="white-space:pre">    </span>SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key,  
  4.                                                                                       Node** prev)  
  5.     const {  
  6.         // 从最高层开始查找  
  7.   Node* x = head_;  
  8.   int level = GetMaxHeight() - 1;  
  9.   while (true) {  
  10.     Node* next = x->Next(level);  
  11.     if (KeyIsAfterNode(key, next)) {    // 向右移动  
  12.       // Keep searching in this list  
  13.       x = next;  
  14.     }  
  15.     else    // 向下移动  
  16.     {  
  17.         // 记录查找路径  
  18.       if (prev != NULL)  
  19.         prev[level] = x;  
  20.       if (level == 0) {  
  21.         return next;  
  22.       } else {  
  23.         // Switch to next list下一层寻找  
  24.         level--;  
  25.       }  
  26.     }  
  27.   }  
  28. }  

查找操作基本上就是调用函数上面的函数FindGreaterOrEqual实现:

  1. // 查询操作  
  2. template<typename Key, class Comparator>  
  3. bool SkipList<Key,Comparator>::Contains(const Key& key) const {  
  4.   Node* x = FindGreaterOrEqual(key, NULL);  
  5.   if (x != NULL && Equal(key, x->key)) {  
  6.     return true;  
  7.   } else {  
  8.     return false;  
  9.   }  
  10. }  

上面基本上就是skiplist在leveldb中实现,leveldb中没有使用复杂的红黑树等机制去保证数据的有序性,而是使用了轻快的skiplist实现。最后需要注意skiplist中每个节点存储key是用户传递keyvalue经过变幻(变幻方法参考http://blog.csdn.net/xuqianghit/article/details/6948164)得到的。

v
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值