MANIFEST

概览

RocksDB与文件系统和存储介质无关。文件系统操作不是原子性的,并且在发生系统故障时容易出现不一致。 即使打开日志记录,文件系统也不能保证不干净重启时的一致性。POSIX文件系统也不支持操作的原子批处理。 因此,不可能依赖嵌入到RocksDB数据存储文件中的元数据来重建重启时RocksDB的最后一个一致状态。

RocksDB有一个内置的机制,通过保存一个名为MANIFEST的RocksDB状态更改的事务日志来克服POSIX文件系统的这些限制。 MANIFEST用于在重启时将RocksDB恢复到最新的一致状态。

术语

  • MANIFEST指的是在事务日志中跟踪RocksDB状态变化的系统
  • Manifest log 指包含RocksDB状态snapshot/edits的单个日志文件
  • CURRENT 指的是最新的清单日志

它是如何工作的?

MANIFEST是RocksDB状态更改的事务日志。MANIFEST是由 - manifest log 文件和最新的manifest文件指针组成。 Manifest logs是名为MANIFEST-(seq编号)的滚动日志文件。序号总是在增加。CURRENT是一个特殊的文件,它标识最新的manifest log文件。

在系统(re)start时,最新的manifest log包含RocksDB的一致状态。对RocksDB状态的任何后续更改都将记录到manifest log文件中。 当manifest log文件超过一定大小时,将使用RocksDB状态快照创建一个新的manifest log文件。 更新最新的manifest log指针,并同步文件系统。成功更新到当前文件后,将清除冗余manifest log。

  1. MANIFEST = { CURRENT, MANIFEST-<seq-no>* }
  2. CURRENT = File pointer to the latest manifest log
  3. MANIFEST-<seq no> = Contains snapshot of RocksDB state and subsequent modifications

版本编辑

在任何给定时间,RocksDB的特定状态都称为版本(即快照)。对版本的任何修改都被认为是版本编辑。 版本(或RocksDB状态快照)是通过连接一系列版本编辑来构建的。本质上,manifest log文件是一系列版本编辑。

  1. version-edit = Any RocksDB state change
  2. version = { version-edit* }
  3. manifest-log-file = { version, version-edit* }
  4. = { version-edit* }

版本编辑布局

Manifest log是一系列版本编辑记录。版本编辑记录类型由编辑标识号标识。 我们使用以下数据类型进行encoding/decoding

数据类型

简单数据类型

  1. VarX - Variable character encoding of intX
  2. FixedX - Fixed character encoding of intX

复杂数据类型

  1. String - Length prefixed string data
  2. +-----------+--------------------+
  3. | size (n) | content of string |
  4. +-----------+--------------------+
  5. |<- Var32 ->|<-- n -->|

版本编辑记录格式

版本编辑记录具有以下格式。解码器使用记录标识号标识记录类型

  1. +-------------+------ ......... ----------+
  2. | Record ID | Variable size record data |
  3. +-------------+------ .......... ---------+
  4. <-- Var32 --->|<-- varies by type -->

版本编辑记录类型和布局

针对RocksDB的不同状态变化,有多种编辑记录。 比较器编辑记录:

  1. Captures the comparator name
  2. +-------------+----------------+
  3. | kComparator | data |
  4. +-------------+----------------+
  5. <-- Var32 --->|<-- String -->|

日志编号编辑记录:

  1. Latest WAL log file number
  2. +-------------+----------------+
  3. | kLogNumber | log number |
  4. +-------------+----------------+
  5. <-- Var32 --->|<-- Var64 -->|

以前的文件号编辑记录:

  1. Previous manifest file number
  2. +------------------+----------------+
  3. | kPrevFileNumber | log number |
  4. +------------------+----------------+
  5. <-- Var32 --->|<-- Var64 -->|

下一个文件编号编辑记录:

  1. Next manifest file number
  2. +------------------+----------------+
  3. | kNextFileNumber | log number |
  4. +------------------+----------------+
  5. <-- Var32 --->|<-- Var64 -->|

最后序列号编辑记录:

  1. Last sequence number of RocksDB
  2. +------------------+----------------+
  3. | kLastSequence | log number |
  4. +------------------+----------------+
  5. <-- Var32 --->|<-- Var64 -->|

最大列族编辑记录:

  1. Adjust the maximum number of family columns allowed.
  2. +---------------------+----------------+
  3. | kMaxColumnFamily | log number |
  4. +---------------------+----------------+
  5. <-- Var32 --->|<-- Var32 -->|

删除文件编辑记录:

  1. Mark a file as deleted from database.
  2. +-----------------+-------------+--------------+
  3. | kDeletedFile | level | file number |
  4. +-----------------+-------------+--------------+
  5. <-- Var32 --->|<-- Var32 -->|<-- Var64 -->|

新增文件编辑记录:

将文件标记为新添加到数据库并提供RocksDB元信息。

  • 文件编辑记录与压缩信息

    +———————+——————-+———————+——————+————————+———————+————————+————————+ | kNewFile4 | level | file number | file size | smallest_key | largest_key | smallest_seqno | largest_seq_no | +———————+——————-+———————+——————+————————+———————+————————+————————+ |<— var32 —>|<— var32 —>|<— var64 —>|<- var64 ->|<— String —>|<— String —>|<— var64 —>|<— var64 —>|

    +———————+—————————+————-+———+————————+——————————+————-+——————+ | CustomTag1 | Field 1 size n1 | field1 | … | CustomTag(m) | Field m size n(m) | field(m)| kTerminate | +———————+—————————+————-+———+————————+——————————+————-+——————+ <— var32 —>|<— var32 —>|<- n1 ->| |<— var32 - ->|<— var32 —>|<- n(m)->|<- var32 —>|

可以在其中编写几个可选的自定义字段。字段有一个特殊的位,指示是否可以安全地忽略它。这是为了兼容性。RocksDB较老版本可能会看到它无法识别的字段。 通过检查位,RocksDB知道是应该停止打开数据库,还是忽略字段。

支持几个可选的自定义字段:kneedcompression:是否应该将文件压缩到下一层。kMinLogNumberToKeepHack:这个条目之后仍然需要恢复的WAL文件号。 kPathId:文件所在的路径ID。旧版本不能忽略这一点。

  • 文件编辑记录向后兼容

    +———————+——————-+———————+——————+————————+———————+————————+————————+ | kNewFile2 | level | file number | file size | smallest_key | largest_key | smallest_seqno | largest_seq_no | +———————+——————-+———————+——————+————————+———————+————————+————————+ <— var32 —>|<— var32 —>|<— var64 —>|<- var64 ->|<— String —>|<— String —>|<— var64 —>|<— var64 —>|

  • 文件编辑记录与路径信息

    +———————+——————-+———————+——————-+——————-+————————+———————+ | kNewFile3 | level | file number | Path ID | file size | smallest_key | largest_key | +———————+——————-+———————+——————-+——————-+————————+———————+ |<— var32 —>|<— var32 —>|<— var64 —>|<— var32 —>|<— var64 —>|<— String —>|<— String —>| +————————+————————+ | smallest_seqno | largest_seq_no | +————————+————————+ <— var64 —>|<— var64 —>|

列族状态编辑记录:

  1. Note the status of column family feature (enabled/disabled)
  2. +------------------+----------------+
  3. | kColumnFamily | 0/1 |
  4. +------------------+----------------+
  5. <-- Var32 --->|<-- Var32 -->|

列族添加编辑记录:

  1. Add a column family
  2. +---------------------+----------------+
  3. | kColumnFamilyAdd | cf name |
  4. +---------------------+----------------+
  5. <-- Var32 --->|<-- String -->|

列族删除编辑记录:

  1. Drop all column family
  2. +---------------------+
  3. | kColumnFamilyDrop |
  4. +---------------------+
  5. <-- Var32 --->|

记录为原子组的一部分(因为RocksDB 5.16):

在某些情况下,”全有或全无”、多列家族版本更改是可取的。例如,原子刷新确保所有或没有一个列族被成功地刷新,多个列族外部SST摄取保证所有或没有一个列族成功地摄取SST。 由于编写多个版本的编辑不是原子性的,我们需要采取额外的措施来实现原子性(从用户的角度来看,不一定是即时的)。 因此,我们引入了一个新的记录字段kInAtomicGroup,以表明该记录是遵循“全有或全无”属性的一组版本编辑的一部分。格式如下。

  1. +-----------------+--------------------------------------------+
  2. | kInAtomicGroup | #remaining version edits in the same group |
  3. +-----------------+--------------------------------------------+
  4. |<--- Var32 ----->|<----------------- Var32 ------------------>|

在恢复期间,RocksDB缓冲原子组的版本编辑,直到从清单文件中成功解码原子组的最后版本编辑,才应用它们。然后,RocksDB应用这个原子组中的所有版本编辑。RocksDB从不应用部分原子组。

版本编辑可忽略的记录类型

我们在记录类型中保留了一个特殊的位。如果位设置好了,就可以安全地忽略它。可安全忽略的记录有标准的一般格式:

  1. +---------+----------------+----------------+
  2. | kTag | field length n | fields ... |
  3. +--------------------------+----------------+
  4. <- Var32->|<-- var32 -->|<--- n >|

这是在6.0中引入的,还没有创建定制的ignoreable记录。