LevelDB - 01. 内存数据库的实现:非阻塞的Skiplist
首先学习LevelDB当中比较独立的一部分,当然的,读源码的话,一个很好的入门的感觉就是先从一个独立的组件模块开始,一个比较容易的开始,SkipList
然后跳表的基本概念什么的我不太想要去过多的赘述,就像二叉树那样希望能得到log(N)的性能,而又利用概率算法更好实现,可以看leveldb-handbook:内存数据库
读写特性
在LevelDB的实现中,主要就是实现
- PUT和- GET两个接口
- 特性是它的GET 操作非阻塞的特性
- 写写冲突是需要external sync来实现,在一个时间下只有一个写可以执行来实现线程安全的机制
这样为了实现读写冲突不加锁的性质,主要实现的思想就是
- 首先在跳表的不同层高中插入节点这一个操作是原子的
- 插入的顺序是从最底层开始向上传递的
这样可以实现在GET操作中,即使在GET上方没有能找到对应的节点,但是它会向下走,到最后一层就一定会看见,即使中间没有看见
实现细节
在实现上就是有一个虚拟头节点Node* const head_; 这个节点拥有最高的层高,然后本身节点是NULL,然后为了保证"跳表的不同层高中插入节点这一个操作是原子的", 对Struct Node的实现中std::atomic<Node*> next_[1];存储next的指针是atomic的类型,对其读写使用std::memory_order_acquire, std::memory_order_release来实现原子性和防止重排序

然后,重点不是说能完全说会它的实现,然后每一个细节都不放过,没有,重点是理解跳表是如何实现它的乐观读写特性,以及实现上对atomic和std::memory_order_acquire, std::memory_order_release的使用
tips: 哦,对了,这个跳表并不支持删除,所谓的删除它还是使用Put然后插入一个空值,还没有完全地理解这个
SkipList 内部的 Node 实现
template <typename Key, class Comparator>
struct SkipList<Key, Comparator>::Node {
  explicit Node(const Key& k) : key(k) {}
  Key const key;
  Node* Next(int n) {
    assert(n >= 0);
    return next_[n].load(std::memory_order_acquire); // 1.
  }
  void SetNext(int n, Node* x) {
    assert(n >= 0);
    next[n].store(std::memory_order_release); // 2.
  }
  // No-barrier variants that can be safely used in a few locations ...
  
  private:
    std::atomic<Node*> next_[1];
};
SkipList 的 insert 方法
template <typename Key, class Comparator>
void SkipList<Key, Comparator>::Insert(const Key& key) {
  Node* prev[kMaxHeight];
  Node* x = FindGreaterOrEqual(key, prev);
  // Not allow duplicate insertion
  assert(x == nullptr || !Equal(key, x->key));
  int height = RandomeHeight();
  if (height > GetMaxHeight()) {  // 超出MaxHeight的部分使用head_
    for (int i = GetMaxHeight(); i < height; i ++) {
      prev[i] = head_;
    }
    // 对max_height的修改可以没有什么同步要求
    max_height_.store(height, std::memory_order_relaxed);
  }
  
  x = NewNode(key, height);
  for (int i = 0; i < height; i ++) {
    // 在这里使用NoBarrier读是可以的因为只有这一个在写,noBarrier写也ok
    // 因为后面对prev[i]设置的时候是会有屏障的,能保证在prev.SetNext的时候
    // x的next是设置好了的
    x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
    // 重点就是维持两种一致性:
    // (1) 保证在加入到SkipList的时候next指针已经指向后面的
    // (2) 保证如果上层看见了的话,下层一定要存在
    prev[i]->SetNext(i, x); 
  }
}
SkipList 的 Contain 方法
template<typename Key, class Comparator>
bool SkipList<Key, Comparator>::Contains(const Key& key) const {
  Node* x = FindGreaterOrEqual(key, nullptr); // 看是否存在,level0
  if (x != nullptr && Equal(key, x->key)) {
    return true;
  } else {
    return false;
  }
}
SkipList 帮助方法 FindGreaterOrEqual
template<typename Key, class Comparator>
typename SkipList<Key, Comparator>::Node* 
SkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key, Node** prev) const {
  Node* x = head_;
  int level = GetMaxHeight() - 1;
  while (true) {
    Node* next = x->Next(level);
    if (KeyIsAfterNode(key, next)) {  
      // Keep searching in this level
      x = next;
    } else /* next->key 大于或者等于 key */ {  
      if (prev != nullptr) prev[level] = x; // 于是 x 就是最后一个小于 key 的节点
      if (level == 0) {
        return next;
      } else {
        // Switch to next list
        level --;
      }
    }
  } 
}
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号