LevelDB源码分析
Intro
前两篇博客主要注重于LevelDB内部结构及Compaction的机制的分析,该篇博客主要介绍LevelDB对外提供的数个接口,及这些接口的实现,包括这些接口是如何与前述截至相互作用的。
DBImpl::Put
DBImpl::Put直接使用了DB::Put的默认实现,即直接构建一个仅有一个Put操作的WriteBatch,然后利用Write来完成操作。
DBImpl::Delete
DBImpl::Delete的实现与DBImpl::Put类似,直接构建一个仅有一个删除操作的WriteBatch,然后让Write完成其余工作。
DBImpl::Write
DBImpl::Write作为Put和Delete的实际实现,保证了WriteBatch中操作的原子性。
1 | Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { |
DBImpl::MakeRoomForWrite
该函数负责在mem_中有足够的空间来处理该写入请求,如果mem_已满则会创建新的mem_。如果该次请求是用户显式要求的,即由Compaction而来,则该请求需要立刻完成。其参数force表示是否需要将mem_写入level0,哪怕在mem_已有足够的空间。
1 | Status DBImpl::MakeRoomForWrite(bool force) { |
DBImpl::BuildBatchGroup
为了减少多次写入,LevelDB会将多个writer合并为一个,然后一次性写入,从而提升写入的效率。
1 | WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { |
DBImpl::Get
Get会从当前的数据库中查找某个键对应的值,查找过程中可能使用快照来限制查找的范围。查找时会首先查找mem_与imm_,这两个表代表了所有尚未写入不同level的信息,仅当这两张表中未查找到对应的值后才会进入文件进行查找。
1 | Status DBImpl::Get(const ReadOptions& options, |
DBImpl::GetSnapshot
创建一个新的快照仅会在LevelDB中记录该快照对应的序号,从而保证在这个序号之后的修改不会被合并和丢弃。
1 | const Snapshot* DBImpl::GetSnapshot() { |
DBImpl::ReleaseSnapshot
删除一个快照并不会直接触发所有因快照而产生的重复的值的删除,删除的过程会在之后的归并过程中进行。
1 | void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) { |
DBImpl::CompactRange
该函数用于手动触发一次Compaction。
1 | void DBImpl::CompactRange(const Slice* begin, const Slice* end) { |
DBImpl::TEST_CompactMemTable
调度compaction将mem_写入level0中。
1 | Status DBImpl::TEST_CompactMemTable() { |
DBImpl::TEST_CompactRange
该函数用于手动触发一次归并,尽量使某个键值范围内仅在一个level存在。
1 | void DBImpl::TEST_CompactRange(int level, const Slice* begin, |
总结
这三篇博客主要介绍了LevelDB的内部结构、Compaction的实现以及各个接口的实现,但未深入到文件结构等细节。这也是我第一次写博客,还是有很多地方做的不好,希望这几篇博客可以帮助到希望了解或者打算阅读LevelDB源代码的人。我过几天会找一些时间重新整理一下这几篇博客。