本篇文章分析下leveldb写sst文件的源码,本质上就是为immemtable compaction到leveldb0文件提供接口,主要是插入。如果要理解这部分的源码,首先必须先将上篇sst文件格式搞清楚,否则,看源码会非常吃力,或者说毫无头绪。
这部分源码涉及到table文件下的block_builder.h/.cc,filter_block.h/.cc和table_builder.h/.cc。先分析下block_builder.h/.cc文件,主要功能就是用于写data block和index block。向外提供主要接口就是void BlockBuilder::Add(const Slice& key, const Slice& value) .
BlockBuilder类
首先,看这个类的类名就知道这个类是用来构造一个块的,data block和index block都是通过这个类构造出来的。来看下这个类的成员变量有哪些:
因为这个类就要是为了构造块,所以这个类首先要提供add键值对的接口,其次是要有返回这个块所有数据的接口,便于上层接口将数据写到磁盘中,所以主要接口如下:
接下来,分析每个函数的源码,构造函数如下;
发现构造函数没有什么好分析的,就最后一句。因为第一条肯定是Restart点,所以把0地址添加进restarts。
重置函数源码如下:
接下来是这个块内容大小的估计函数
这个函数主要用于判断某个块的容量是否到达上限,到达之后,要把数据刷新到磁盘,然后重新开始写下一个块。
接下来是这个类最重要的函数,add添加键值对函数,这里还是把记录格式在贴出来,方便对照:
这个函数需要注意的是,每个Restart节点的共享部分为0,,因为没有上一条记录嘛。然后按协议封装好一条完整记录添加到buffer_即可,接下来,就是finish函数做的事了。
这个函数主要是向table_builder提供返回这个块内容的接口,然后由table_builder调用函数写回磁盘。
FilterBlockBuilder类
这个类用于写Meta block,也就是创建过滤器。先来分析主要成员变量:
接下来介绍下主要函数:
开始创建Fliter条目函数
在table_builder.cc中,当一个块被刷新到磁盘时,就调用一次start_block函数,而触发块刷新的条件是,这个块的大小>=r->options.block_size=4096,所以每次都创建一个Filter,但是Filter有两个数组指向>=2的Filter条目。
创建Filer条目函数:
Filter i添加键值的函数:
表示Meta block块写结束的函数:
TableBuilder类
这个类主要功能就是创建一个sst文件,它调用了block_builder和filerblockbuilder。这个类属性有点多,需要好好记清楚了。
关键还是data_block,因为data_block要用多次,写块,刷新到磁盘,重置块等等。C++中用class代替struct,这里展示了struct用的场景之一,就是类里成员变量太多时,可以用struct封装。
接下来,主要介绍table_builder主要函数。
往data block添加一条记录函数:
刷新函数为:
刷新操作主要有以下步骤:
- 将这个块的数据刷新到磁盘。因为底层调用的是c标准io流,所以数据是先写到用户态的缓存中,然后调用flush,再刷新到磁盘。
- 在WriteBlock函数内部还在index block添加一条记录。
- 重新开启一条Filter条目。
接下来是WriteBlock函数:
这个函数主要是用于判断data block的数据是否要压缩存储,真正下操作在下面函数:
这个函数主要作用就是将数据写进用户态缓冲区,添加类型和CRC码,更新偏移量。
最后还有一个sst文件写完成函数,用于上层函数调用:
至此,一个sst文件就建好了。最后还有一个函数,用于调用table_builder来创建sst文件,在builder.h/.cc里,这个等到compaction是再分析。
leveldb将immemtable compcation到sst0就这样分析结束,接下来,就是读sst文件,读总是比写更复杂。。。