// Compaction是一次compaction操作的抽象,每次compaction包含基层level+0的文件和level+1的文件,最终合并成若干level+1的文件 Compaction* PickCompaction() { level = current_version.compaction_level // 根据size触发compaction还是seek数量触发compaction,选出本次compaction的基层level if (size_compaction) { for (file : current_version.files[level]) { if (compact_pointer[level].empty() || file.largest_key > compaction_pointer[level]) { compaction.inputs[ 0 ].push_back(file) break } } } else if (seek_compaction) { compaction.inputs[ 0 ].push_back(current.files_to_compact) } // 和其他level不同,level0的文件彼此key range可能重合,需要全部找出来 if (level == 0 ) current_version.GetOverlappingInputs() // 基层level文件就绪,继续添加level+1文件 SetupOtherInputs(compaction) return compaction } SetupOtherInputs() { // 若同一个user key的若干记录刚好本两个文件分开了,那么需要把另一个文件也加进来,否则会查到旧数据,例如 // file1结尾是 user_key="alibaba", seq=101,file2开头是 user_key="alibaba", seq=100 // 若本次只合并file1到下一层,那么下次查找这个key的时候会先查到file2的旧数据 AddBoundaryInputs(inputs[ 0 ]) // 获取inputs[0]层所有文件的最小key和最大key,在level+1层中寻找有冲突的文件并加入inputs[1] GetRange(inputs[ 0 ], &smallest, &largest) GetOverlappingInputs(level + 1 , smallest, largest, &inputs[ 1 ]) // 如下操作试图扩展inputs[0],即如果level+0层的其他文件加入不会导致level+1层新增其他冲突文件,那么扩展到inputs[0] GetRange2(inputs[ 0 ], inputs[ 1 ], &all_smallest, &all_largest) GetOverlappingInputs(level, all_smallest, all_largest, &expanded0) GetRange(expanded0, &new_smallest, &new_largest) // 获取扩展后expanded0的最小key和最大key GetOverlappingInputs(level + 1 , new_smallest, new_largest, &expanded1) if (expanded0.size() > inputs[ 0 ].size() && expanded1.size() < inputs[ 1 ].size()) inputs[ 0 ] = expanded0 } BackgroundCall() { // 执行compaction BackgroundCompaction() // 一次compaction后可能导致一个level产生了过多文件,尝试再次进行compaction MaybeScheduleCompaction() } BackgroundCompaction() { // 若有immutable memtable,那么刷入磁盘文件 if (imm != nullptr) { CompactMemTable() return } // 手动compaction if (manual) { compaction = versions.CompactRange() } else { // size或者seek触发的compaction compaction = versions.PickCompaction() } // 简单compaction只要增加level到level+1即可 if (!manual && compaction.IsTrivialMove()) { compaction.edit().RemoveFile(level, file_number) compaction.edit().AddFile(level, file_number) versions.LogAndApply(compaction->edit()) } else { // 实际compaction操作 DoCompactionWork() } } DoCompactionWork() { // 获取多路归并排序中每个文件的迭代器 merge_iter = versions.MakeInputIterator(compaction) whlie (merge_iter.Valid()) { if (imm != nullptr) { CompactMemTable() } key = merge_iter.key() if (compaction.ShouldStopBefore(key)) // 条件1、若当前key range导致下层冲突过多,那么不能再追加了,产出一个sst文件 FinishCompactionOutputFile() if (key.user_key() == last_key.user_key()) { // 和上一个key拥有相同的user_key,当前key更旧不再需要了直接剔除 continue ; } else { // 启动sst文件builder if (compaction.builder == nullptr) OpenCompactionOutputFile() compaction.builder.Add(key, merge_iter.value()) // 条件2、若当前builder中存储的数据大小达到一定限制,产出一个sst文件 if (compaction.builder.FileSize() > MaxOutputFileSize()) FinishCompactionOutputFile() } } // 将最新文件信息保存到current version同时删除本次compaction的输入的旧文件 InstallCompactionResults() } |