版权声明:本文为博主原创文章,未经博主允许不得转载。
leveldb
作为一个 key-value
数据库,它和 redis
的区别在于不仅没有把所有的数据放在内存中,而是把大部分数据放在了磁盘中
leveldb
存数据的流程
- 先指定一块内存写数据(这块内存称为
MemTable
),当占用的内存高于阈值后,将这块内存转为只读(这块只读内存称为Immutable MemTable
) - 同时开辟一块新的内存(
MemTable
)来写数据 - 然后异步将
Immutable MemTable
的数据添加到存到磁盘中
本文将从数据怎么写入磁盘开始讲起(第 3
步中的数据存储到磁盘),数据写入磁盘时会先将数据放在一个名叫 table
的结构中,table
中包含有很多个 block
,block
是真正用来存储 key-value
的
当 table
的大小大于指定阈值时,就会把 table
中的数据写入到磁盘中
table
结构
<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1]
...
[meta block K]
[metaindex block]
[index block]
[Footer] (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>
第一眼看着不明觉厉,这是个什么鬼玩意呢
其实 table
就是用来存放多个 data block
的,那问题来了,下面一堆 meta block
/ metaindex block
/ index block
是什么鬼?
当我们在
table
里面查询一个key
,在没有索引的情况下,就需要将所有的data block
遍历一遍,如果按照这种方式找的话,十亿级的数据存储找到猴年马月才能找到,怎样才能高效的找到我们需要查询的key
呢,就靠上面所说的那堆鬼东西,这里我们按下不表,后面会详细介绍(挖坑1)
上面说了这么多,只是为了让大家有个基本的概念,本章重点要讲解的是 table
中 data block
data block
万丈高楼平地起,我们现在来介绍 Leveldb
中最基础的结构,也是真正存储 KV
的结构 data block
搞懂
data block
需要阅读如下源码文件
1 table/block.h // [非常重要|难度:3级] block的结构
2 table/block.cc
3 table/block_build.h // [非常重要|难度:3级] 用于构建 block
4 table/block_build.cc
5 include/leveldb/slice.h // [非常重要|难度:1级] leveldb 中用到的 string 都封装成了 slice
6 util/coding.h // [非常重要|难度:2级] 类型转换,编码转换
7 util/coding.cc
slice.h (简单了解后可跳过)
先介绍最简单的 slice
,实际就是把 string
封装了一下,它拥有两个私有变量和几个简单的处理函数
public:
char operator[](size_t n) const; // 符号重载[],返回第n个字符
void remove_prefix(size_t n); // 删除前n个字符
std::string ToString(); // 转成string
int compare(const Slice& b); // 比较字符串大小
bool starts_with(const Slice& x); // 将this.data_前面x.size_个字符替换成x.data_
private:
const char* data_; // 存储字符串
size_t size_; // 记录data_的长度
涉及的小知识 (专为像我这样的新手准备,请看 【Leveldb源码解析新手补充篇】)
- 符号重载
size_t
类型inline
内联函数- 函数后面
const
有啥作用