(二)LevelDB日志

概述

为了防止写入内存的数据库因为进程异常、系统掉电等情况发生丢失,leveldb在写内存之前会将本次写操作的内容写入日志文件中。
在这里插入图片描述
数据写入先写入log中,再写入memtable中,memtable写满后会变为immemtable,不可修改,同时log文件也会变成frozen log,不可修改。一旦immutable写入硬盘中,frozen log即删除。

日志具体结构

一条日志由一个或多个chunk组成,每个chunk由header和data组成,header为7个字节,分为三部分,第一部分checksum占4个字节,第二部分length占2个字节,表示chunk数据的长度。第三部分为类型,共有4中状态:full,first,middle以及last。如果一条记录只有一个chunk,则类型为full,若有多个chunk,则第一个chunk类型为First,最后一个类型为Last,中间的类型都是Middle。
在这里插入图片描述
一个block大小为32KB,可以包含一个或多个block

日志写

这部分代码在db/log_writter.cc中

do {
    const int leftover = kBlockSize - block_offset_;
    assert(leftover >= 0);
		//如果剩余空间小于7个字节(放不下header)
    if (leftover < kHeaderSize) {
      // Switch to a new block
      if (leftover > 0) {
        // Fill the trailer (literal below relies on kHeaderSize being 7)
        static_assert(kHeaderSize == 7, "");
				//将剩余空间置空
        dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover));
      }
      block_offset_ = 0;
    }

    // Invariant: we never leave < kHeaderSize bytes in a block.
    assert(kBlockSize - block_offset_ - kHeaderSize >= 0);

    const size_t avail = kBlockSize - block_offset_ - kHeaderSize;
    const size_t fragment_length = (left < avail) ? left : avail;

    RecordType type;
    const bool end = (left == fragment_length);
    if (begin && end) {
      type = kFullType;
    } else if (begin) {
      type = kFirstType;
    } else if (end) {
      type = kLastType;
    } else {
      type = kMiddleType;
    }
		//插入具体chunk数据
    s = EmitPhysicalRecord(type, ptr, fragment_length);
    ptr += fragment_length;
    left -= fragment_length;
    begin = false;
  } while (s.ok() && left > 0);

//将chunk写入日志文件中
Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr,
                                  size_t length) {
  assert(length <= 0xffff);  // Must fit in two bytes
  assert(block_offset_ + kHeaderSize + length <= kBlockSize);

  // Format the header
  char buf[kHeaderSize];
  buf[4] = static_cast<char>(length & 0xff);
  buf[5] = static_cast<char>(length >> 8);
  buf[6] = static_cast<char>(t);

  // Compute the crc of the record type and the payload.
  uint32_t crc = crc32c::Extend(type_crc_[t], ptr, length);
  crc = crc32c::Mask(crc);  // Adjust for storage
  EncodeFixed32(buf, crc);

  // Write the header and the payload
  Status s = dest_->Append(Slice(buf, kHeaderSize));
  if (s.ok()) {
    s = dest_->Append(Slice(ptr, length));
    if (s.ok()) {
      s = dest_->Flush();
    }
  }
  block_offset_ += kHeaderSize + length;
  return s;
}

日志读

这部分代码在db/log_reader.cc中

主要有两个方法,ReadRecord方法和ReadPhysicalRecord方法。其中ReadRecord方法是读取整条记录,而ReadPhysicalRecord是读取一个chunk,在ReadRecord方法中使用循环控制来多次调用ReadPhysicalRecord.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SZn..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值