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  此处为最低层级 则未查找到(进行插入)

leveldb 学习记录(一) skiplist的更多相关文章

  1. leveldb 学习记录(四) skiplist补与变长数字

    在leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明 这里在介绍 下skiplist的代码 里面有几个模块 template<typenam ...

  2. leveldb 学习记录(三) MemTable 与 Immutable Memtable

    前文: leveldb 学习记录(一) skiplist leveldb 学习记录(二) Slice 存储格式: leveldb数据在内存中以 Memtable存储(核心结构是skiplist 已介绍 ...

  3. leveldb 学习记录(四)Log文件

    前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...

  4. leveldb 学习记录(五)SSTable格式介绍

    本节主要记录SSTable的结构 为下一步代码阅读打好基础,考虑到已经有大量优秀博客解析透彻 就不再编写了 这里推荐 https://blog.csdn.net/tankles/article/det ...

  5. leveldb 学习记录(七) SSTable构造

    使用TableBuilder构造一个Table struct TableBuilder::Rep { // TableBuilder内部使用的结构,记录当前的一些状态等 Options options ...

  6. leveldb 学习记录(八) compact

    随着运行时间的增加,memtable会慢慢 转化成 sstable. sstable会越来越多 我们就需要进行整合 compact 代码会在写入查询key值 db写入时等多出位置调用MaybeSche ...

  7. leveldb 学习记录(二) Slice

    基本每个KV库都有一个简洁的字符串管理类 比如redis的sds  比如leveldb的slice 管理一个字符串指针和数据长度 通过对字符串指针 长度的管理实现一般的创建 判断是否为空 获取第N个位 ...

  8. leveldb 学习记录(六)SSTable:Block操作

    block结构示意图 sstable中Block 头文件如下: class Block { public: // Initialize the block with the specified con ...

  9. LevelDB学习笔记 (3): 长文解析memtable、跳表和内存池Arena

    LevelDB学习笔记 (3): 长文解析memtable.跳表和内存池Arena 1. MemTable的基本信息 我们前面说过leveldb的所有数据都会先写入memtable中,在leveldb ...

随机推荐

  1. PTA上Java问题自查与提问方法

    自查 首先请一定先看这篇文章<PTA中提交Java程序的一些套路>.该文囊括了PTA中提交Java程序的几乎所有常见问题,请仔细阅读可以少踩很多坑 题目测试方法:复制样例输入,然后打开一个 ...

  2. 【剑指offer】求一组数据中最小的K个数

    题目:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. *知识点:Java PriorityQueue 调整新插入元素 转自h ...

  3. ps-如何去水印

    现在,版权意识越来越明显了,所以加水印的图片越来越多了,但我们在一些特定的情况又不得不去使用那些图片,去水印又是问题.今天,我来说下如何去水印. 一.ps-仿制图章工具去水印 1.打开ps,打开待去水 ...

  4. 学习MeteoInfo二次开发教程(七)

    1.站点文件 12010615.syn在D:\Program Files (x86)\MeteoInfo\SampleSYNOP_Stations.csv在D:\Program Files (x86) ...

  5. Twisted网络库编程实例

    于这一周看了python的第三方网络库Twisted,英文看的头比较大,想看英文的话点击这里.如果英文很烂,可以看中文,这里.总的来说我了解到的主要包括以下三个东东:Factory.protocol和 ...

  6. python学习笔记_week26

    note 一.CMDB -采集资产 -API -后台管理 -资产列表(CURD) -业务线列表(CURD) -用户列表(CURD) -组列表(CURD) ... ===>简单<=== 公共 ...

  7. 如何使用 Visual C# .NET 处理 Excel 事件

    事件处理概述 Visual C# .NET 使用委派处理来自组件对象模型 (COM) 服务器的事件.委派是 Microsoft Visual Studio .NET 中的一个新概念.对于 COM 事件 ...

  8. hitTest,UIWindow sendEvent ,touchbegan, 响应链

    https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/using_responders_and_th ...

  9. UNITY 打包时提示sdk tools 或 sdk build tools版本低时可以直接点update 按钮进行更新

    如题.如果不更新,而选择 : use newest version installed ,打包到结尾时可能会报错,莫名其妙的java错误 而且,SDK一旦被更新后,其所在目录的 SDK MANAGER ...

  10. GDI+_Png图片浏览器

    '昨天看见有人问VB6支不支持PNG,刚好我正在研究GDI+,于是做了这个演示程序.'演示下载地址:百度网盘|'下面为设计界面和运行效果截图 ' 千万别喷界面丑. /无奈 .