RocksDB代码分析——Compaction流程

阅读量: searchstar 2022-03-08 15:40:17
Categories: Tags:

这里从DBImpl::MaybeScheduleFlushOrCompaction开始讲起。

DBImpl::MaybeScheduleFlushOrCompaction可能会scheduleDBImpl::BGWorkFlushDBImpl::BGWorkCompaction。这里主要看Compaction。Flush部分见 RocksDB代码分析——Flush流程

DBImpl::BGWorkCompaction中调用了DBImpl::BackgroundCallCompaction

DBImpl::BackgroundCallCompaction中先锁住DBImpl::mutex_,保护DB元数据,然后调用DBImpl::BackgroundCompaction,然后调用DBImpl::MaybeScheduleFlushOrCompaction,我的理解是compaction完成之后下一层可能过大了,这样就需要做新的compaction。DBImpl::BackgroundCallCompaction返回的时候会自动把DBImpl::mutex_给释放掉。

DBImpl::BackgroundCompaction中:

调用DBImpl::PickCompactionFromQueuecompaction_queue_里取出一个ColumnFamilyData *cfd
调用cfd->PickCompaction,得到Compaction *,作为要做的任务。

ColumnFamilyData::PickCompaction调用compaction_picker_->PickCompaction
ColumnFamilyData::compaction_picker_是在ColumnFamilyData的构造函数里根据ioptions_.compaction_style赋值的。

struct AdvancedColumnFamilyOptions {
 // The compaction style. Default: kCompactionStyleLevel
 CompactionStyle compaction_style = kCompactionStyleLevel;

所以我们假设ColumnFamilyData::compaction_picker_LevelCompactionPicker,即假设ColumnFamilyData::PickCompaction调用的compaction_picker_->PickCompaction其实是LevelCompactionPicker::PickCompaction
LevelCompactionPicker::PickCompaction调用LevelCompactionBuilder::PickCompaction

选择输入文件:RocksDB代码分析——Compaction的输入文件的选择
调用LevelCompactionBuilder::GetCompaction构造Compaction对象。

将要返回的Compaction *中的score会被设置为start level的score。
Compaction的构造函数中调用Compaction::MarkFilesBeingCompacted将输入文件标记为being_compacted,防止出现一边compaction一边上面compact到输入层的情况。
调用VersionStorageInfo::ComputeCompactionScore重新计算各层的score。除了Level 0,其他层的score等于没有在compact的file的compensated_file_size除以该层的最大字节数。只有score>=1的层才会被选择作为compaction的start level,见LevelCompactionBuilder::SetupInitialFilesRocksDB代码分析——Compaction的输入文件的选择)。file的compensated_file_sizeVersionStorageInfo::ComputeCompensatedSizes中计算得到。

DBImpl::BackgroundCompaction中,取出compaction任务后:

构造CompactionJob compaction_job,其中FSDirectory* output_directory被设置成GetDataDir(c->column_family_data(), c->output_path_id())
mutex_.Unlock(),执行compaction_job.Run(),再mutex_.Lock()DBImpl::mutex_最开始是在DBImpl::BackgroundCallCompaction里锁住用来保护数据库元数据的,这里要执行耗时操作了,所以暂时把锁放开。
compaction_job.Install

CompactionJob::InstallCompactionResults

先把输入文件删掉:compaction->AddInputDeletions(edit);
再把输出文件加上:edit->AddFile

Compaction::ReleaseCompactionFiles,将输入文件的being_compacted标志清除。

CompactionJob::output_directory

它决定了compaction的结果应该放到哪个文件夹中。这里探究一下它是怎么确定的。

构造CompactionJob时,FSDirectory* output_directory被设置成GetDataDir(c->column_family_data(), c->output_path_id())

c->output_path_id()返回的是Compaction::output_path_id_。它是从Compaction的构造函数的参数来的。

假如compaction任务(Compaction)是通过cfd->PickCompaction得到的。根据前面的分析,这些compaction任务默认是由LevelCompactionBuilder::GetCompaction构造的,其中output_path_id: GetPathId(ioptions_, mutable_cf_options_, output_level_)

/*
 * Find the optimal path to place a file
 * Given a level, finds the path where levels up to it will fit in levels
 * up to and including this path
 */
uint32_t LevelCompactionBuilder::GetPathId(
    const ImmutableCFOptions& ioptions,
    const MutableCFOptions& mutable_cf_options, int level) {

大意就是检查ImmutableCFOptions::cf_paths的每个cf_path,直到找到某个path能放下要compact到的那个level。

这个ImmutableCFOptions的来源见RocksDB代码分析——各种option的传递