leveldb源码剖析---日志系统

本文详细介绍了leveldb的日志系统,包括记录key-value的日志文件、版本信息变化的manifest文件和CURRENT文件。日志系统确保了数据在写入磁盘前的持久性,防止异常崩溃导致的数据丢失。在数据库恢复时,通过对日志文件的操作,保证了数据库的一致性和可靠性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

日志就是记录数据库增删记录的文件。之所以需要记录这些东西,主要是为了防止万一数据库运行期间异常崩溃导致的数据丢失。而之所以会出现数据丢失,原因在于我们在往数据库中写数据时,并不是真的将数据库写入到了磁盘中,而可能只是将数据暂存到内存中而已。如果在数据flush到磁盘之前系统崩溃(数据库bug,操作系统bug,机器故障等等),那缓存在内存中的数据就会丢失,而用户以为这些数据已经成功写入数据库了(这也是插入数据时数据库告知用户已经成功插入了)。下次重启时,用户会因为在数据库中找不到自己插入的数据而迷惑不解。

日志系统的作用就是保证插入到缓存中的数据也不会丢失。


leveldb日志系统组成

leveldb的日志文件主要分为三种:

  1. 记录key-value的日志文件
  2. 记录版本信息变化(VersionEdit)的日志文件(manifest文件)
  3. CURRENT文件,它包含一个指向上面类型2日志文件的指针

类型1的日志是日志恢复的核心,因为只有把所有写到数据库中的key-value都用日志记录下来,后续才有可能进行故障恢复。类型2是为了在每次数据库启动时都可以还原历史版本信息。类型3的日志则只包含一行记录,这行记录就是manifest日志的文件名。

下面我们从代码层面跟踪日志系统的操作流程


日志系统的操作流程 —— key-value日志文件

用户通过DBImpl::Write函数向数据库中写入数据,根据之前的分析,这里的写入并不是真的写入磁盘,而是写入内存的memtable中。在DBImpl::Write函数中,我们可以看到在将数据写入memtable之前,leveldb先将数据写入log_中

status = log_->AddRecord(WriteBatchInternal::Contents(updates));  // 写日志

而且如果我们深入到AddRecord函数中就会发现,它在将每个数据写入时都会flush,这样保证写入日志中的数据都实际地写入到了磁盘中。这里可能会觉得写日志会不会效率太低,其实不然,因为写日志是顺序写,和随机写相比,效率要高得多。

问题在于,这里的log_会记录历史上所有加入到数据库中的key-value吗?如果这样的话,日志文件实在就太大了。下面我们看到,其实每个memtable都会生成一个日志文件,而log_日志文件总是记录的是当前memtable中的key-value,也就是说当这个memtable转变成imm_等待被写入磁盘时,就会另生成一个log_,这个新的log_指向新的mem_。这个我们可以从DBImpl::MakeRoomForWrite函数中找到端倪:

      logfile_number_ = new_log_number;
      log_ = new log::Writer(lfile);
      imm_ = mem_; //后台将启动对imm_ 进行写磁盘的过程
      has_imm_
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值