levelDB源码阅读-skiplist跳表下

levelDB中的skiplist跳表 下

前言

在跳表 上 中介绍了跳表的基本结构,接下来将要介绍跳表的迭代器和其内部实现的方法。

Iterator -跳表的迭代器

跳表的迭代器实现非常简单,调用了跳表内部的一些实现方法。

// Iteration over the contents of a skip list
  class Iterator {
   public:
    // Initialize an iterator over the specified list.
    // The returned iterator is not valid.
    explicit Iterator(const SkipList* list);

    // Returns true iff the iterator is positioned at a valid node.
    bool Valid() const;

    // Returns the key at the current position.
    // REQUIRES: Valid()
    const Key& key() const;

    // Advances to the next position.
    // REQUIRES: Valid()
    void Next();

    // Advances to the previous position.
    // REQUIRES: Valid()
    void Prev();

    // Advance to the first entry with a key >= target
    void Seek(const Key& target);

    // Position at the first entry in list.
    // Final state of iterator is Valid() iff list is not empty.
    void SeekToFirst();

    // Position at the last entry in list.
    // Final state of iterator is Valid() iff list is not empty.
    void SeekToLast();
   //私有成员
   private:
    const SkipList* list_;
    Node* node_;
    // Intentionally copyable
  };
  
  	//...
    
	//迭代器的构造函数
    template<typename Key, class Comparator>
    inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {
      list_ = list;
      node_ = nullptr;
    }
	//判断是否合法
    template<typename Key, class Comparator>
    inline bool SkipList<Key,Comparator>::Iterator::Valid() const {
      return node_ != nullptr;
    }
	//返回key
    template<typename Key, class Comparator>
    inline const Key& SkipList<Key,Comparator>::Iterator::key() const {
      assert(Valid());
      return node_->key;
    }
	//默认从最底层链路跳到next的位置
    //之前说过,第0层包含了所有的key
    template<typename Key, class Comparator>
    inline void SkipList<Key,Comparator>::Iterator::Next() {
      assert(Valid());
      node_ = node_->Next(0);
    }
	//跳到前一个Node的位置
    template<typename Key, class Comparator>
    inline void SkipList<Key,Comparator>::Iterator::Prev() {
      // Instead of using explicit "prev" links, we just search for the
      // last node that falls before key.
      assert(Valid());
      //FindLessThan是skipList的一个方法,后面会详细介绍
      node_ = list_->FindLessThan(node_->key);
      if (node_ == list_->head_) {
        node_ = nullptr;
      }
    }
	//Seek是追踪的意思
    template<typename Key, class Comparator>
    inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {
      //设置当前节点为与target的key相等或比target大的node
      //FindGreaterOrEqual也是skiplist的一个函数
      node_ = list_->FindGreaterOrEqual(target, nullptr);
    }
	//追踪到头部
    template<typename Key, class Comparator>
    inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {
      //在skiplist中有一个head_成员
      node_ = list_->head_->Next(0);
    }
    //追踪到尾部
    template<typename Key, class Comparator>
    inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {
    node_ = list_->FindLast();
    if (node_ == list_->head_) {
    node_ = nullptr;
   	 }
   }

skiplist内部方法

NewNode

template<typename Key, class Comparator>
typename SkipList<Key,Comparator>::Node*
SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
  //以对齐的方式申请内存
  //arena是leveldb的内存池,之后会讲到
  //原子指针的大小是根据高度来定的
  char* mem = arena_->AllocateAligned(
      sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1));
  //新建一个节点并且返回
  return new (mem) Node(key);
}

RandomHeight

当要插入一个Node的时候,它应该在插入在哪些高度上呢?
levelDB的实现中,就是使用了生成随机高度的方式。

template<typename Key, class Comparator>
int SkipList<Key,Comparator>::RandomHeight() {
  // Increase height with probability 1 in kBranching
  static const unsigned int kBranching = 4;
  int height = 1;
  //生成随机高度的一个方式
  //rnd_是跳表的一个内部成员
  while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
    height++;
  }
  assert(height > 0);
  assert(height <= kMaxHeight);
  return height;
}

KeyIsAfterNode
字面意思是判断当前Key值是否在Node之后,但是这样说似乎有些突兀,其本质就是比较Key的值和Nodekey值的大小(因为跳表是有序的)。

template<typename Key, class Comparator>
bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
  // null n is considered infinite
  //使用比较器
  return (n != nullptr) && (compare_(n->key, key) < 0);
}

一些关于find的方法

如果对跳表的结构不够熟悉,这部分理解起来可能有些困难,建议画一个跳表,然后结合图片来进行分析(这里提供一个图片)。
在这里插入图片描述

//找一个key值比传入参数key大或者相等的Node并返回
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) {
    //先找到当前节点的next节点
    //比较key值和next节点的key值,如果key值大于next节点的key,就说明我们要找的节点在next之后
    //反之,就说明我们找到了该高度中我们要找的节点
    Node* next = x->Next(level);
    if (KeyIsAfterNode(key, next)) {
      // Keep searching in this list
      //继续搜索当前高度
      x = next;
    } else {
      //prev用于存放每一层中找到的节点的前一个节点
      if (prev != nullptr) prev[level] = x;
      //如果是最底层,则直接返回
      if (level == 0) {
        return next;
      } else {
        // Switch to next list
        level--;
      }
    }
  }
}
//找一个比key值比传入参数更小的节点
//如果没有就返回head
template<typename Key, class Comparator>
typename SkipList<Key,Comparator>::Node*
SkipList<Key,Comparator>::FindLessThan(const Key& key) const {
  Node* x = head_;
  int level = GetMaxHeight() - 1;
  while (true) {
    assert(x == head_ || compare_(x->key, key) < 0);
    Node* next = x->Next(level);
    //如果移动到了当前层次尾部或者next->key比传入key值大
    if (next == nullptr || compare_(next->key, key) >= 0) {
      //如果到了最底层则直接返回
      if (level == 0) {
        return x;
      } else {
        // Switch to next list
        //搜索下一个层次
        level--;
      }
    } else {
      //继续搜索当前层次
      x = next;
    }
  }
}
//找到跳表的尾部
template<typename Key, class Comparator>
typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()
    const {
  Node* x = head_;
  int level = GetMaxHeight() - 1;
  while (true) {
    Node* next = x->Next(level);
    //找到了当前层次的尾部
    if (next == nullptr) {
      //如果是最底层,则直接返回
      if (level == 0) {
        return x;
      } else {
        // Switch to next list
        level--;
      }
    } else {
      x = next;
    }
  }
}

insert
插入操作是实现中一个非常重要的部分。

void SkipList<Key,Comparator>::Insert(const Key& key) {
  // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
  // here since Insert() is externally synchronized.
  //指向前一个节点的数组
  Node* prev[kMaxHeight];
  //调用该函数,并传入参数pre
  //可以找到插入key值的节点在每一个高度中插入点的前一个位置
  Node* x = FindGreaterOrEqual(key, prev);

  // Our data structure does not allow duplicate insertion
  assert(x == nullptr || !Equal(key, x->key));
  //生成一个随机高度
  int height = RandomHeight();
  
  //如果生成的高度大于当前跳表的高度
  if (height > GetMaxHeight()) {
    //初始化高出的部分
    for (int i = GetMaxHeight(); i < height; i++) {
      prev[i] = head_;
    }
    //fprintf(stderr, "Change height from %d to %d\n", max_height_, height);

    // It is ok to mutate max_height_ without any synchronization
    // with concurrent readers.  A concurrent reader that observes
    // the new value of max_height_ will see either the old value of
    // new level pointers from head_ (nullptr), or a new value set in
    // the loop below.  In the former case the reader will
    // immediately drop to the next level since nullptr sorts after all
    // keys.  In the latter case the reader will use the new node.
    max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
  }
  //新建一个节点
  x = NewNode(key, height);
  //将该节点插入到之前找到的位置上去
  for (int i = 0; i < height; i++) {
    // NoBarrier_SetNext() suffices since we will add a barrier when
    // we publish a pointer to "x" in prev[i].
    x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
    prev[i]->SetNext(i, x);
  }
}

** Contains **
是否包含key值的Node

template<typename Key, class Comparator>
bool SkipList<Key,Comparator>::Contains(const Key& key) const {
  //调用函数
  Node* x = FindGreaterOrEqual(key, nullptr);
  //如果相等则返回true
  if (x != nullptr && Equal(key, x->key)) {
    return true;
  } else {
    return false;
  }
}

总结

以上,我们分析了在levelDB中跳表的具体实现方法,我们可以注意到里面并没有删除操作。 结合跳表的原理和结构来看,这部分也非常好理解。