in LevelDB 分布式数据库 ~ read.

LevelDB组件-LOG

LevelDB组件-LOG

Write Ahead Log

LevelDB 写MemTable之前的操作。

格式

![log](https://raw.githubusercontent.com/ccyuki/vnote_img/main/personal/written/leveldb组件-log.md/135254216242209.png =864x)

LevelDB 的 log 文件内容被组织成多个 32 KB 的定长块(block)。每个 block 由 1~N 个 record 组成(末尾可能会 padding)。

一个 record 由一个固定 7byte 的 header(checksum: uint32 + length: uint16 + type: uint8) 和实际数据(data: uint8[length])组成。

如果 block 的末尾不足 7 字节(小于 header 的大小),则全部填 0x00(padding),读取的时候会被忽略。

如果 block 的末尾刚好 7 字节,则填充一个 length 为 0 的 record。

将上层写入的数据称之为 user record,以区分 block 中的 record。由于 block 是定长的,而 user record 是变长的,一个 user record 有可能被截断成多个 record,保存到一段连续的 block 中。

因此,在 header 中有一个 type 字段用来表示 record 的类型:

enum RecordType {
  // Zero is reserved for preallocated files
  kZeroType = 0,

  kFullType = 1,        // 一个完整的 user record

  // For fragments
  kFirstType = 2,        // user record 的第一个 record
  kMiddleType = 3,        // user record 中间的 record。如果写入的数据比较大,kMiddleType 的 record 可能有多个
  kLastType = 4        // user record 的最后一个 record
};

示例

初始化整个 log 为空,假设有 3 条 user record:

A 大小为 1000 字节
B 大小为 97270 字节
C 大小为 8000 字节

32k = 32768 B

存储方式如图:

![log_eg](https://raw.githubusercontent.com/ccyuki/vnote_img/main/personal/written/leveldb组件-log.md/494193209235502.png =360x)

  • A = 1000
  • B_first = 32768-1000-7 = 31754
  • B_mid = 32768-7 = 32761
  • B_last = 97270-31754-32761 = 32755
  • C = 8000

絮叨

分 block 的意义

如果不分block,每条record的长度不定,当某条record损坏,此时,我们无法找到下一条正常record从哪开始,相当于所有的record都被毁坏了。

如果划分block,即便每条record的长度不定,单block大小固定,如某条record损坏,此时,我们无法在当前block中找到下一条正常record从哪开始,但是可以找到下个block的位置,进而判断该block是否损坏,从而保证了不让所有的record都因一条record出现问题导致全部失效。