leveldb源代码分析系列1.5:Get实现

Get流程

这是位于零层主题memtable相关实现下的一层主题。预扩展二层主题:vset_->table_cache_->Get函数流程。

Get流程如下:首先通过ReadOptions中设置的参数得到snapshot,默认情况下即使用当前snapshot。接着依次在mem,imem和versions_->current()即当前版本的sstable集合中查找key。其中在MemTable中查找key的方法之前已经介绍过,此处不再赘述。Get接口的逻辑十分清楚,见如下代码:

leveldb源代码分析系列1.5:Get实现_第1张图片

我们这里主要分析两个部分:在当前版本的磁盘文件中查找key的流程,和什么情况下触发compaction的流程。

1.在当前版本的磁盘文件中查找key。
首先看调用函数

s = current->Get(options,lkey,value,&stats);

最后一个参数并没有输入信息,而是作为函数向外输出信息的接口,stats记录了查找过程中的一些参数,这些参数决定了是否需要compactoin以及在哪个level进行compaction。

leveldb源代码分析系列1.5:Get实现_第2张图片

stats的类型是GetStats,其只有两个成员:seek_file,seek_file_level,之后遇到的时候分析两个成员分别代表了什么含义。

进入函数Version::Get,函数的第一部分是一些准备工作,包括获取user_key和internal_key,获取比较user_key的user_comparator函数,初始化stats的成员。

这里涉及到一个类FileMetaData,这个类具有如下成员:

leveldb源代码分析系列1.5:Get实现_第3张图片

每个FileMetaData对象记录了一个sstable的信息,其中allowed_seeks记录了一个sstable还能被允许查询的次数,其被初始化为(1 << 30)。当一次Get操作没有在本sstable中找到key时则将其减一,当其被减到0时则触发本sstable的compaction。通过这种方式,较少被Get的冷数据会compaction到更低层level的sstable文件中。

接着,开始一层一层地查找key,由于leveldb的compaction策略保证了level层级越小,数据越新,因此在低level找到数据即可返回,否则在更高level中查找。

处理第0层时和其他层时不同,由于第0层的sstable之间的key可能会重合,因此需要将每个有可能含有查询key的sstable文件都进行查找。而其他level的sstable之间的key不重合,因此只需要找到可能含有查询key的一个sstable即可。
level == 0
leveldb源代码分析系列1.5:Get实现_第4张图片
需要查找的sstable存储在files指向的数组中,num_files记录了这个数组的长度,即需要查找的sstable的个数。接着遍历这个数组。

在遍历sstable数组的时候,如果在第一个sstable中就找到了答案,则stats不会被设置,否则则意味着第一个sstable中没有找到答案,stats记录本sstable。
leveldb源代码分析系列1.5:Get实现_第5张图片
具体的查找操作在vset_->table_cache_->Get函数中,这里暂且先不分析,留作下一层的扩展主题。得到查找结果后返回即可,Version::Get函数结束。

回到DBImpl::Get函数,根据stats修改其记录的sstable的allowed_seeks。(通过current->UpdateStats函数)如果这个值小于等于0,意味着stats.seek_file需要被compaction,将stats记录的信息赋予Version的成员file_to_compact_和file_to_compact_level_,接着调用MaybeScheduleCompaction函数。
leveldb源代码分析系列1.5:Get实现_第6张图片
MaybeScheduleCompaction函数是触发compaction的接口函数,Put/Delete接口也可能调用此函数触发compaction,这里暂且略过,之后专门用一个主题进行分析。

至此整个Get流程结束。

你可能感兴趣的