美文网首页
LevelDB的WAL设计

LevelDB的WAL设计

作者: rickif | 来源:发表于2020-03-10 00:02 被阅读0次

WAL(Write Ahead Log)是数据库软件常用的数据恢复技术,通过在实际修改数据文件之前,将数据变更的日志写入到磁盘进行持久化。在数据库进程因为异常崩溃重启后,可以通过重新加载WAL日志并将其提交,从而恢复数据。WAL日志从记录内容上可以分为物理型和逻辑型两种,所谓物理型WAL日志记录的信息为拟写入的文件信息(名称)、拟写入的文件偏移量和拟写入文件的数据,InnoDB存储引擎的redo log即是这种形式的WAL日志;逻辑型的WAL日志记录的是待写入的数据逻辑信息,如对应到kv存储引擎的key-value信息,LevelDB即是采用的逻辑型的WAL日志。

日志格式

如图所示,LevelDB的WAL日志由定长的日志数据头header和变长的数据payload组成。

header组成

日志header是一个长度为7的定长char数组。[0:3]为存储payload的crc32校验信息,[4:5]存储payload的长度,[6]存储日志类型。需要说明的是,日志的写入是以block的形式进行组织写入,日志的数据可能因为block存储空间原因分别存储在2个block中,此时对应的length和crc32对应的是存储在该block中的部分payload。

recordType

前面有提到,为了提高写入效率,WAL Log是以32768字节固定长度的block的形式组织写入的。长度变化的WAL Log自然会导致其被划分为多个fragment存储于block的不同位置。根据日志数据是否划分为多个fragment以及不同的存储位置,LevelDB将写入的block记录划分为4种recordType。

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

  kFullType = 1,  // Log恰好占满1个block

  // For fragments
  kFirstType = 2, // fragment位于block的起始位置
  kMiddleType = 3, // fragment位于block的中间位置
  kLastType = 4 // fragment位于block的末尾
};

写入流程

WAL写入流程

在Linux平台上,WAL写入流程分为[写header到buffer]、[写payload到buffer]和[写buffer数据到磁盘]3个步骤。在拷贝数据到buffer过程中,如果出现buffer容量不足的情形,会直接触发buffer数据以及WAL数据的Flush。在数据都拷贝到buffer后,Flush数据持久化到磁盘。LevelDB这里的WAL Log的Flush操作是直接调用了Posix的ssize_t write(int fd, const void *buf, size_t count);系统调用。write系统调用成功返回并不会保证数据已经正确持久化到磁盘,数据可能还存在在操作系统缓存、磁盘缓存中。在数据持久化到磁盘之前发生断电,是很可能造成数据损坏甚至丢失的。因此,LevelDB调用fdatasync()系统调用,保证数据完整写入到磁盘。WAL是用来进行故障恢复的重要手段,数据安全性这一点尤为重要。

相关文章

网友评论

      本文标题:LevelDB的WAL设计

      本文链接:https://www.haomeiwen.com/subject/fvusdhtx.html