leveldb 学习记录(八) compact
随着运行时间的增加,memtable会慢慢 转化成 sstable。
sstable会越来越多 我们就需要进行整合 compact
代码会在写入查询key值 db写入时等多出位置调用MaybeScheduleCompaction ()
检测是否需要进行compact
1 void DBImpl::MaybeScheduleCompaction() { 2 mutex_.AssertHeld(); 3 if (bg_compaction_scheduled_) { 4 // Already scheduled 5 } else if (shutting_down_.Acquire_Load()) { 6 // DB is being deleted; no more background compactions 7 } else if (imm_ == NULL && 8 manual_compaction_ == NULL && 9 !versions_->NeedsCompaction()) { 10 // No work to be done 11 } else { 12 bg_compaction_scheduled_ = true; 13 env_->Schedule(&DBImpl::BGWork, this); 14 } 15 } 16 17 void DBImpl::BGWork(void* db) { 18 reinterpret_cast<DBImpl*>(db)->BackgroundCall(); 19 } 20 21 void DBImpl::BackgroundCall() { 22 MutexLock l(&mutex_); 23 assert(bg_compaction_scheduled_); 24 if (!shutting_down_.Acquire_Load()) { 25 BackgroundCompaction(); 26 } 27 bg_compaction_scheduled_ = false; 28 29 // Previous compaction may have produced too many files in a level, 30 // so reschedule another compaction if needed. 31 MaybeScheduleCompaction(); 32 bg_cv_.SignalAll(); 33 }
实际进行compact的函数是 void DBImpl::BackgroundCompaction()
1 手动触发情况下 会填写class DBImpl下的一个变量 ManualCompaction manual_compaction_
1 struct ManualCompaction { 2 int level; 3 bool done; 4 const InternalKey* begin; // NULL means beginning of key range 5 const InternalKey* end; // NULL means end of key range 6 InternalKey tmp_storage; // Used to keep track of compaction progress 7 };
为了避免外部指定的 key-range 过大,一次 compact 过多的 sstable 文件, manual_compaction 可能不会一次做完,所以有 done 来标
识是否已经全部完成, tmp_storage 保存上一次 compact 到的 end-key,即下一次的 startkey。
指定的beg end KEY会赋值到 versions_中,以便后面进行compact。 versions_->CompactRange(m->level, m->begin, m->end);
2 通过 versions_->PickCompaction() 选择需要compact的level 和 key range
1 Compaction* VersionSet::PickCompaction() { 2 Compaction* c; 3 int level; 4 5 // We prefer compactions triggered by too much data in a level over 6 // the compactions triggered by seeks. 7 const bool size_compaction = (current_->compaction_score_ >= 1); 8 const bool seek_compaction = (current_->file_to_compact_ != NULL); 9 if (size_compaction) { 10 level = current_->compaction_level_; 11 assert(level >= 0); 12 assert(level+1 < config::kNumLevels); 13 c = new Compaction(level); 14 15 // Pick the first file that comes after compact_pointer_[level] 16 for (size_t i = 0; i < current_->files_[level].size(); i++) { 17 FileMetaData* f = current_->files_[level][i]; 18 if (compact_pointer_[level].empty() || 19 icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { 20 c->inputs_[0].push_back(f); 21 break; 22 } 23 } 24 if (c->inputs_[0].empty()) { 25 // Wrap-around to the beginning of the key space 26 c->inputs_[0].push_back(current_->files_[level][0]); 27 } 28 } else if (seek_compaction) { 29 level = current_->file_to_compact_level_; 30 c = new Compaction(level); 31 c->inputs_[0].push_back(current_->file_to_compact_); 32 } else { 33 return NULL; 34 } 35 36 c->input_version_ = current_; 37 c->input_version_->Ref(); 38 39 // Files in level 0 may overlap each other, so pick up all overlapping ones 40 if (level == 0) { 41 InternalKey smallest, largest; 42 GetRange(c->inputs_[0], &smallest, &largest); 43 // Note that the next call will discard the file we placed in 44 // c->inputs_[0] earlier and replace it with an overlapping set 45 // which will include the picked file. 46 current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); 47 assert(!c->inputs_[0].empty()); 48 } 49 50 SetupOtherInputs(c); 51 52 return c; 53 }
PickCompaction函数中 根据 文件尺寸和被seek多次 来确认compact的文件
使用 c = new Compaction(level) 记录要compact的level和文件指针
todo 实际的compact操作 CompactMemTable() DoCompactionWork()
参考
《leveldb实现解析》 淘宝 那岩
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话