对Version注解准备分两篇来说明,Version在leveldb中的重要性值得分两篇文章去记录。
第一篇主要对Version的流程好结构进行图解说明,第二篇则是源码注释解读。通过两篇
文章的学习可以对Version有个清晰的认识。
磁盘文件结构
01代码中文件分类
02磁盘中真实文件
对于带有数字编号的文件,其格式都是xxxxxx.xx,也就是说数字编号长度是6位。
其编号都是由全局统一的编号生成器统一自增分配,也就是由类VersionSet 中的next_file_number_来全局管理分配。
注:
文件编号是从2开始的,1留给了leveldb进行recover时的Manifest文件使用。
03文件作用
- LOCK:leveldb的全局锁文件,在Recover和DestoryDB时用到。
- Current: 记录当前最新的MANIFEST清单文件。
- MANIFEST-XXXXXX: 记录了各个阶段的VersionEdit,leveldb可通过Manifest计算还原得到最新的Version。
- XXXXXX.log: 顺序记录leveldb的所有操作。
- XXXXXX.ldb: 此文件就是SSTable文件。
Version相关结构
Version
先来说说Version,Version表示了当前leveldb的版本信息,
版本信息内容包括:
- 当前每一层的SSTable文件元信息。
- 记录被Seek太多次需要Compact的文件元信息,以及文件所在的level。
- 记录所有level层中compaction score 最大的那一层及其level,
用于比较判断是否需要对此level层进行compact。
Version数据结构如下:
上文中说道了SSTable文件结构的元信息,那文件元信息是包含哪些数据呢?
这就需要讲下结构FileMetaData了。
FileMetaData
SSTable文件元信息结构由数据结构FileMetaData来表示,
保存的数据有:
- 当前文件被引用了多少次,SSTable可以在不同的Version中。
- 文件允许被Seek的次数,超过这个次数,就好把整个文件Compact掉。
- 文件编号,即文件名。
- 文件大小。
- 文件最大key和最小key。
FileMetaData的数据结构如下:
介绍完Version相关信息之后,那什么情况下回产生新的Version呢?
当SSTable文件发生变化时则会产生新的Version (* ̄︶ ̄)。
SSTable产生变化的触发条件:
- 将Immutable转为SSTable时。
- 当后台开始进行Compact时。
随着系统的运行,不断的有新的Version产生,那不同的Version之间用什么来表示呢?
即Version与Version之间的差异。这个时候就轮到VersionEdit出场了。
VersionEdit
compact过程中会有一系列改变当前Version的操作(FileNumber增加,删除一些SSTable,增加一些新的SSTable),
为了缩小Version切换的时间点,将这些操作封装成VersionEdit,待compact完成时,将VersionEdit一次应用到当前Version即可得到最新状态的Version。
工作作用过程如下:
VersionEdit存储的内容包括:
- 当前的key比较器名字comparator,
db一旦创建,排序的逻辑就必须保持兼容,不可变更。此时就用comparator做凭证。 - 当前使用的log_number。
- 其他文件编号信息。
- 每个level层的compact pointer。
- 要删除的SSTable文件。
- 要添加的SSTable文件。
VersionEdit的数据结构如下:
Leveldb运行过程中会存在很多Version的迭代,那这些Version在内存中是怎么管理的呢?
这个时候VersionSet就来了。
VersionSet
整个leveldb的当前状态被VersionSet管理着,
维护的信息如下:
- 通过循环双向链表将当前最新的Version和其它正在服务的Version维护起来,
当一个Version不在被任何引用时,会自动删除掉。 - 每个level层下一次compact要选取的start_key。
- 全局的文件编号分配。
- 当前的manifest_file_number。
- 当前manifest文件句柄及文件操作封装。
VersionSet维护Version结构关系如下图:
VersionSet本身的数据结构如下:
leveldb的这些状态信息当前都是保存在内存中的,那如果掉电了或者重启了,那这些数据怎么办呢?
为此manifest就出现了。
Manifest
为了重启leveldb后可以恢复到退出前的状态,需要将db中的状态保存下来,这些信息就保存在Manifest中。当leveldb出现异常时,为了能尽可能多的恢复,manifest中不仅保存当前的状态,也会将历史的状态也保存起来,考虑到每次状态的完全保存需要空间和耗费的时间比较多,当前采用的方式是,只在manifest开始保存完整的状态信息(通过VersionSet::WriteSnapShot()
来实现),
接下来只保存每次compact产生的VersionEdit。
Manifest的文件结构如下:
因为写manifest流程和写log流程是一样的,结构和leveldb的log结构一样,只是payload部分不一样而已。
介绍完了Version相关结构之后,接下来说说产生Version的的三个应用过程。
Version产生流程
Version产生流程可以分为三个块:
- Memtable转为新的SSTable或者进行Compact之后SSTable产生变化时调用
VersionSet::LogAndApply()
产生新的Version。 - leveldb上电还原Version过程,调用接口
VersionSet::Recover()
。 - leveldb异常损坏,修复leveldb过程,调用接口
RepairDB()
产生新的Version。
01SStable文件变化
02上电还原
看不清的,可以双击放大了看。
03修复leveldb
至此对Version相关结构就流程已经介绍完毕,下篇会对Version相关源码进行解读。
文中涉及到的参考:
【levledb实现解析.pdf】