leveldb

LevelDb是一个持久化存储的KV系统,并非完全将数据放置于内存中,部分数据也会存储到磁盘上。

想了解这个由谷歌大神编写的经典项目.

可以从数据结构以及数据结构的处理下手,也可以从示例的某一点深入跟进系统,查看处理流程.

windows下编译leveldb  地址 leveldb 源码编译 vs版本

目前手头资料中,源码中的文档以及网络的代码分析心得如下,本文也做了参考,感谢作者.

流程类

数据分析与处理之二(Leveldb 实现原理)

[跟吉姆一起读LevelDB]0.源代码阅读环境

LevelDB入门教程十篇

结构入手类

巴山独钓的分析

sparkliang的专栏

1 arena内存池略过。 nginx内存池 stl内存池均可参考实现原理(《stl源码分析》)

2 bloomfilter相当于多重哈希,比对哈希值判断是否有相同元素插入 略过。

3 数据结构skiplist 多数操作log(n)

参考 https://segmentfault.com/a/1190000003051117

跳表的关键点在于定义和查找方法

定义如下:

SkipList的定义:
1. 一个跳表应该有几个层(level)组成;
2. 跳表的第一层包含所有的元素;
3. 每一层都是一个有序的链表;
4. 如果元素x出现在第i层,则所有比i小的层都包含x;
5. 第i层的元素通过一个down指针指向下一层拥有相同值的元素;
6. 在每一层中,-1和1两个元素都出现(分别表示INT_MIN和INT_MAX);
7. Top指针指向最高层的第一个元素。

图示:

find

查找方法为

1 起点为最高层第一个元素 若元素小于查找值 则查找该元素的后继值

2 若元素大于查找值 则降低层级再次查找

3 若该元素的后继值 为NULL或者大于该值 ,则降低层数再次查找

4 直到查找成功或者达到表的最底层且无元素可查找

图示中查找 17

起点为最高层第一个元素 6  6<17 6的下一个元素为null 则在元素6中降低层级

再次查找6的下一个元素 是25 降低层级

再次查找6的下一个元素 是9

再次查找9的下一个元素 是25 降低层级

再次查找9的下一个元素 是12

再次查找12的下一个元素 是19  此处为最低层级 则未查找到(进行插入)

insert

查找也可用于insert 注意insert 元素时候层级是随机的

leveldb 中skiplist 结构如下(内存池与原子指针等结构暂时不予理会)

 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* Next(int n) {
assert(n >= );
// Use an 'acquire load' so that we observe a fully initialized
// version of the returned Node.
return reinterpret_cast<Node*>(next_[n].Acquire_Load());
}
void SetNext(int n, Node* x) {
assert(n >= );
// 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* NoBarrier_Next(int n) {
assert(n >= );
return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
}
void NoBarrier_SetNext(int n, Node* x) {
assert(n >= );
next_[n].NoBarrier_Store(x);
} private:
// Array of length equal to the node height. next_[0] is lowest level link.
port::AtomicPointer next_[];
}; template<typename Key, class Comparator>
typename SkipList<Key,Comparator>::Node*
SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
char* mem = arena_->AllocateAligned(
sizeof(Node) + sizeof(port::AtomicPointer) * (height - ));
return new (mem) Node(key);
}

抛开内存池和多线程情况下的原子操作 定义很简单
分配 获取下一个元素 设置下一个元素
template<typename Key, class Comparator>中的 key是元素类型 Comparator是元素比较大小的策略

元素插入操作如下

 template<typename Key, class Comparator>
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];
Node* x = FindGreaterOrEqual(key, prev); assert(x == NULL || !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_ (NULL), or a new value set in
// the loop below. In the former case the reader will
// immediately drop to the next level since NULL 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 = ; 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);
}
}

插入元素的层级是随机的 并且获取当前最大层级数并未使用原子操作 因为根据逻辑并无影响 不使用原子操作也是性能上的一种考虑

元素读取操作如下

 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() - ;
while (true) {
Node* next = x->Next(level);
if (KeyIsAfterNode(key, next)) {
// Keep searching in this list
x = next;
} else {
if (prev != NULL) prev[level] = x;
if (level == ) {
return next;
} else {
// Switch to next list
level--;
}
}
}
}

find

查找方法为

1 起点为最高层第一个元素 若元素小于查找值 则查找该元素的后继值

2 若元素大于查找值 则降低层级再次查找

3 若该元素的后继值 为NULL或者大于该值 ,则降低层数再次查找

4 直到查找成功或者达到表的最底层且无元素可查找

图示中查找 17

起点为最高层第一个元素 6  6<17 6的下一个元素为null 则在元素6中降低层级

再次查找6的下一个元素 是25 降低层级

再次查找6的下一个元素 是9

再次查找9的下一个元素 是25 降低层级

再次查找9的下一个元素 是12

再次查找12的下一个元素 是19  此处为最低层级 则未查找到(进行插入)

最新文章

  1. Linux命令(2) - 查看目录和文件大小: du -sh
  2. 【linux】bash常用快捷键
  3. 通用php与mysql数据库配置文件
  4. jvm内存GC详解
  5. 用GOACCESS分析NGINX日志
  6. MVC上传相关
  7. AutoFac使用方法总结:Part II
  8. 2013~2014年度 NOIP~GDOI总结
  9. JS window对象的top、parent、opener含义介绍(转载)
  10. Vue.js-02:第二章 - 常见的指令的使用
  11. Error:Execution failed for task &#39;:app:transformResourcesWithMergeJavaResForDebug&#39;
  12. 【调试基础】Part 4 保护模式
  13. cpgf如何实现lua script binding的?
  14. FreeSWITCH IVR中lua调用并执行nodejs代码
  15. scrapy分布式
  16. Qt中printsupport的注意点和使用方法
  17. MAC版Eclipse的常用快捷键
  18. MongoDB的数据类型(四)
  19. Entityframework:启用延时加载的主意事项(只为强化记忆)
  20. JAVA 文本 TXT 操作工具类

热门文章

  1. Maya中输出alembic文件的方法
  2. 【算法和数据结构】_16_小算法_IntToStr: 将整型数据转换为字符串
  3. Browser Render Engine &amp; Javascript Engine
  4. VS2012 C# 连接MySQL数据库
  5. You Only Look Once: Unified, Real-Time Object Detection
  6. ORACLE中用户等系统信息操作
  7. Jvm的体系结构
  8. spring boot 接口用例测试
  9. Mac 日常使用tips
  10. uva-10041-水题