Commit

每当(1)完成一次major compaction整理内部数据或者(2)通过minorcompaction或者重启阶段的日志重放新生成一个0层文件,都会触发leveldb进行一个版本升级。

一次版本升级的过程如下:

Commit - 图1

  • 新建一个session record,记录状态变更信息;
  • 若本次版本更新的原因是由于minorcompaction或者日志replay导致新生成了一个sstable文件,则在sessionrecord中记录新增的文件信息、最新的journal编号、数据库sequencenumber以及下一个可用的文件编号;
  • 若本次版本更新的原因是由于major compaction,则在sessionrecord中记录新增、删除的文件信息、下一个可用的文件编号即可;
  • 利用当前的版本信息,加上sessionrecord的信息,创建一个全新的版本信息。相较于旧的版本信息,新的版本信息更改的内容为:(1)每一层的文件信息;(2)每一层的计分信息;
  • 将session record持久化;
  • 若这是数据库启动后的第一条sessionrecord,则新建一个manifest文件,并将完整的版本信息全部记录进sessionrecord作为该manifest的基础状态写入,同时更改current文件,将其指向新建的manifest;
  • 若数据库中已经创建了manifest文件,则将该条sessionrecord进行序列化后直接作为一条记录写入即可;
  • 将当前的version设置为刚创建的version;

注解

注意,对于leveldb来说,增减某些sstable文件需要作为一个原子性操作,状态变更前后需要保持数据库的一致性。

在整个过程中,原子性体现在:整个操作的完成标志为manifest文件中完整的写入了一条sessionrecord,在此之前,即便某些文件写入失败导致进程退出,数据库重启启动时,仍然能够恢复到崩溃之前正确的状态,而将这些无用的sstable文件删除,重新进行compaction动作。

一致性体现在:leveldb状态变更的操作都是以version更新为标记,而version更新是整个流程的最后一步,因此数据库必然都是从一个一致性的状态变更到另外一个一致性的状态。