首先学习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 insertionassert(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); // 看是否存在,level0if (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 levelx = next;} else /* next->key 大于或者等于 key */ { if (prev != nullptr) prev[level] = x; // 于是 x 就是最后一个小于 key 的节点if (level == 0) {return next;} else {// Switch to next listlevel --;}}}
}