参考:
- https://www.jianshu.com/p/9b5...
- https://zhuanlan.zhihu.com/p/...
- https://zhuanlan.zhihu.com/p/...
- https://cloud.tencent.com/dev...
SST File Format
之前在LSM-Tree部分有提过,但当时了解的比较浅
<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1: filter block]
[meta block 2: index block]
[meta block 3: compression dictionary block]
[meta block 4: range deletion block]
[meta block 5: stats block]
...
[meta block K: future extended block] (More meta blocks may be added in the future)
[metaindex block]
[Footer] (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>
metaindex block和index block
metaindex block记录了每个meta block的偏移和长度. key是meta block的名字, value的类型是 BlockHandle, 其定义如下
class BlockHandle {
public:
BlockHandle();
BlockHandle(uint64_t offset, uint64_t size);
...
private:
uint64_t offset_;
uint64_t size_;
}
index block记录了每个data block的索引. key是一个string, 它的值大于或等于被索引的block的最后一个key, 小于下一个data block的第一个key.
value是data block对应的BlockHandle.
Footer
Footer的大小固定为48字节
metaindex_handle: char[p]; // Block handle for metaindex
index_handle: char[q]; // Block handle for index
padding: char[40-p-q]; // zeroed bytes to make fixed length
// (40==2*BlockHandle::kMaxEncodedLength)
magic: fixed64; // 0x88e241b785f4cff7 (little-endian)
padding为空白字节,用于对齐
magic number占用8个字节,是个固定数值,用于读取时校验是否跟填充时相同,不相同的话就表示此文件不是一个SSTable文件
DataBlockIndex
DataBlockIndex包含DataBlock索引信息,用于快速定位到包含特定key的DataBlock;DataBlockIndex首先是一个block,因此包含三部分KeyValue、Type(固定1字节)、CRC检验码(固定4字节);Type标识该部分数据是否采用压缩算法,CRC是KeyValue + Type的检验码;key的取值是大于等于其索引block的最大key,并且小于下一个block的最小key;value也是BlockHandle类型,由变长的offset和size组成。
key的取值
为了节省空间,key的取值并不一定为其索引block的最大key,而是选取介于该block最大key与下一个block最小key之间的值。
假设其索引的block的最大key为"acknowledge",下一个block最小的key为"apple",如果DataBlockIndex的key采用其索引block的最大key,占用长度为len("acknowledge");采用后一种方式,key值可以为"ad"("acknowledge" < "ad" < "apple"),长度仅为2,并且检索效果是一样的。
DataBlock
DataBlock是KeyValue数据存储块,跟DataBlockIndex一样包含三部分:KeyValue、Type、CRC校验;
前缀压缩
每一个KeyValue记录都是一条Entry。
每条Entry的格式为:
- shared_bytes:和前一个key相同的前缀长度。
- unshared_bytes:和前一个key不同的后缀部分的长度。
- value_length:value数据的长度。
- key_delta:和前一个key不同的后缀部分。
- value:value数据。
DataBlock中key的存储采用了前缀压缩机制,对于key的相同前缀,尽量只存储一次以节省空间。但是对于SSTable来说,它并没有对整个block的所有key进行一次性地前缀压缩,而是设置了很多区段,处于同一区段的key进行一次前缀压缩,每个区段的起点就是一个重启点。之所以设置很多区段是为了更好的支持随机读取,这样就可以在block内部对重启点进行二分,然后再在单个区段内遍历即可找到对应key值的记录,所以分段压缩就承担了block内部二级索引的功能。
在KeyValue部分的尾部用一个数组记录这些重启点的offset(固定四个字节),同时block的最后4个字节被固定用来保存重启点的个数。
Data Block默认每16个key会有一个重启点,Index Block默认每一个key都是重启点
// Number of keys between restart points for delta encoding of keys.
// This parameter can be changed dynamically. Most clients should
// leave this parameter alone. The minimum value allowed is 1. Any smaller
// value will be silently overwritten with 1.
int block_restart_interval = 16;
// Same as block_restart_interval but used for the index block.
int index_block_restart_interval = 1;
与BlockBasedTableBuilder相关的类
- BlockBasedTable, 该类封装了用于读取磁盘BlockBasedTable类型的SST表的逻辑。
- BlockBasedTableBuilder, 该类用于在磁盘上构建一个BlockBasedTable类型的SST表。
- BlockBasedTableFactory, 该类是BlockBasedTable工厂方法的实现,用于创建BlockBasedTable/BlockBasedTableBuilder。
Write Block的逻辑:
BlockBasedTableBuilder的Add逻辑
- 判断key的类型,不同类型有不同的处理方法
- 判断当前的key是否比上一个key大,保证有序
- 判断是否需要flush当前的block到文件中,并清空data block
- add到data block中(data block的变量类型为BlockBuilder)
BlockBuilder的Add逻辑
- 判断是否需要restart point
- 如果不需要restart point,将当前插入的key与前一个key比较前缀,得到可以压缩的前缀长度。
- 得到所有需要的数据后,按照一个entry的格式,append到buffer中。
当向一个block中加入了若干个kv,由r->flush_block_policy来决定是否调用BlockBasedTableBuilder的Flush方法将当前的block写入到文件中,并清空block,重新再用。
默认的flush block策略定义在FlushBlockBySizePolicy中,即根据block的已写入大小来决定刷盘,接口为Update,默认的block大小为4K。
当需要flush block时,调用Flush方法,Flush方法调用了WriteBlock方法。
WriteBlock会首先调用data_block的Finish()方法,将start points append到buffer_中,设置block的标志位finished_ = true
然后会以下格式将一个block写入目标文件中
| block_data(uint8[n]) | type(uint8) | crc(uint32)|
在data block写完之后, 会在BlockBasedTableBuilder的Finish方法中,进行write meta block
Write Meta Block的顺序
Write meta blocks, metaindex block and footer in the following order.
- [meta block: filter]
- [meta block: index]
- [meta block: compression dictionary]
- [meta block: range deletion tombstone]
- [meta block: properties]
- [metaindex block]
- Footer
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。