概述

Rocksdb对文件系统以及存储介质保持不可预知的态度。文件系统操作不是原子的,并且在系统错误的时候容易出现不一致。即使打开了日志系统,文件系统还是不能在一个不合法的重启中保持一致。POSIX文件系统不支持原子化的批量操作。因此,无法依赖RocksDB的数据存储文件中的元数据文件来构建RocksDB重启前的最后的状态。

RocksDB有一个内建的机制来处理这些POSIX文件系统的限制,这个机制就是保存一个名为MANIFEST的ROCKSDB状态变化的事务日志文件。MANIFEST文件用于在重启的时候,恢复rocksdb到最后一个一致的一致性状态。

术语

  • MANIFEST 指通过一个事务日志,来追踪Rocksdb状态迁移的系统
  • Manifest日志 指一个独立的日志文件,它包含RocksDB的状态快照/版本
  • CURRENT 指最后的Manifest日志

如何工作?

MANIFEST是一个RocksDB状态变更的事务日志。MANIFEST由manifest日志文件以及最后的manifest文件指针组成。Manifest日志是滚动日志文件,命名方式为MANIFEST-(seq number)。seq number总是递增。CURRENT是一个特殊的文件,用于声明最新的manifest日志文件。

在系统(重新)启动的时候,最新的manifest日志文件会包含一个一致的ROCKSDB的状态。任何对RocksDB状态修改的子序列都会被记录到manifest日志文件中。当一个manifest日志超过特定的大小,一个新的manifest日志文件会更新,且保证刷盘到文件系统。成功更新CURRENT文件之后,就的manifest文件就会被删掉。

  1. MANIFEST={CURRENT, MANIFEST-<seq-no>*}
  2. CURRENT = 指向当前manifest日志的文件指针
  3. MANIFEST-<seq-no> = 包含RocksDB状态的快照以及后续的修改

版本(version)编辑

一个任何时刻的RocksDB的特定状态都指向一个版本(version)(换句话说,快照)。任何针对这个版本的修改,都被认为是一个版本编辑。一个版本(或者说一个rocksDB的状态快照)由一系列的版本编辑合并构成。本质上来说,一个manifest日志文件是一个版本编辑的序列。

  1. 版本编辑 = 任何RocksDB状态变更
  2. 版本 = {版本编辑*}
  3. manifest日志文件 = {版本,版本编辑*} = {版本编辑*}

版本编辑布局

Manifest日志是一个版本编辑记录的序列。版本编辑记录类型是通过编辑标示号码区分的。

我们使用下列数据类型来进行编码/解码。

数据类型

简单数据类型

  • VarX - 由intX编码的变长字符
  • FixedX - 由intX编码的定长字符

复杂数据类型

string - 带长度前缀的字符串数据:

  1. +-----------+--------------------+
  2. | size (n) | content of string |
  3. +-----------+--------------------+
  4. |<- Var32 ->|<-- n -->|

版本编辑记录格式

版本编辑记录使用下面的格式。解码器通过记录标示号码区分不同类别的记录

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

版本编辑记录类型以及布局

针对RocksDB不同的状态变更,有非常多样的编辑记录。

比较器编辑记录:

记录比较器的名字

  1. +-------------+----------------+
  2. | kComparator | data |
  3. +-------------+----------------+
  4. <-- Var32 --->|<-- String -->|

日志数量编辑记录: 最新的WAL日志文件数量

  1. +-------------+----------------+
  2. | kLogNumber | log number |
  3. +-------------+----------------+
  4. <-- Var32 --->|<-- Var64 -->|

上一个文件号编辑记录: 上一个manifest文件号

  1. +------------------+----------------+
  2. | kPrevFileNumber | log number |
  3. +------------------+----------------+
  4. <-- Var32 --->|<-- Var64 -->|

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

  1. +------------------+----------------+
  2. | kNextFileNumber | log number |
  3. +------------------+----------------+
  4. <-- Var32 --->|<-- Var64 -->|

最新的seq number编辑记录:

rocksdb最新的seq number

  1. +------------------+----------------+
  2. | kLastSequence | log number |
  3. +------------------+----------------+
  4. <-- Var32 --->|<-- Var64 -->|

最大的列族编辑记录:

调整允许使用的最大列族数

  1. +---------------------+----------------+
  2. | kMaxColumnFamily | log number |
  3. +---------------------+----------------+
  4. <-- Var32 --->|<-- Var32 -->|

删除文件编辑记录: 把一个文件标记为从数据库中删除

  1. +-----------------+-------------+--------------+
  2. | kDeletedFile | level | file number |
  3. +-----------------+-------------+--------------+
  4. <-- Var32 --->|<-- Var32 -->|<-- Var64 -->|

新文件编辑记录: 把一个文件标记为新加入数据库,并且提供必要的元数据给ROCKSDB

  • 文件编辑记录与压缩信息
  1. +--------------+-------------+--------------+------------+----------------+--------------+----------------+----------------+
  2. | kNewFile4 | level | file number | file size | smallest_key | largest_key | smallest_seqno | largest_seq_no |
  3. +--------------+-------------+--------------+------------+----------------+--------------+----------------+----------------+
  4. |<-- var32 -->|<-- var32 -->|<-- var64 -->|<- var64 ->|<-- String -->|<-- String -->|<-- var64 -->|<-- var64 -->|
  5. +-----------+---------------+-------+------------------+-------+--------------+
  6. |kPathID ---| Path size(n) | path | kNeedCompaction | 1 | value (0/1) |
  7. +-----------+---------------+-------+------------------+-------+--------------+
  8. <- var32 ->|<-- var32 -->|<- n ->|<-- var32 -->|<- 1 ->|<-- 1 -->|
  • 文件编辑记录向后兼容
  1. +--------------+-------------+--------------+------------+----------------+--------------+----------------+----------------+
  2. | kNewFile2 | level | file number | file size | smallest_key | largest_key | smallest_seqno | largest_seq_no |
  3. +--------------+-------------+--------------+------------+----------------+--------------+----------------+----------------+
  4. <-- var32 -->|<-- var32 -->|<-- var64 -->|<- var64 ->|<-- String -->|<-- String -->|<-- var64 -->|<-- var64 -->|
  • 文件编辑记录与路径信息
  1. +--------------+-------------+--------------+-------------+-------------+----------------+--------------+
  2. | kNewFile3 | level | file number | Path ID | file size | smallest_key | largest_key |
  3. +--------------+-------------+--------------+-------------+-------------+----------------+--------------+
  4. |<-- var32 -->|<-- var32 -->|<-- var64 -->|<-- var32 -->|<-- var64 -->|<-- String -->|<-- String -->|
  5. +----------------+----------------+
  6. | smallest_seqno | largest_seq_no |
  7. +----------------+----------------+
  8. <-- var64 -->|<-- var64 -->|

列族信息编辑记录:

标记列族功能的状态(打开/关闭)

  1. +------------------+----------------+
  2. | kColumnFamily | 0/1 |
  3. +------------------+----------------+
  4. <-- Var32 --->|<-- Var32 -->|

列族增加编辑记录:

增加一个列族

  1. +---------------------+----------------+
  2. | kColumnFamilyAdd | cf name |
  3. +---------------------+----------------+
  4. <-- Var32 --->|<-- String -->|

列族删除编辑记录: 删除所有列族

  1. +---------------------+
  2. | kColumnFamilyDrop |
  3. +---------------------+
  4. <-- Var32 --->|