|
// 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()
}
|