跟着源码实现LevelDB (五)db/log_writer

发布于:2025-03-11 ⋅ 阅读:(76) ⋅ 点赞:(0)

1. 日志格式

        参考 https://zhuanlan.zhihu.com/p/149794318

1.1 每条记录Record有7B存储meta信息

1.2 log按照32KB切分,如果32KB还剩下小于7B, 由于Record只能存放meta信息,所以填'\x00' * leftover

    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;
    }

1.3 record和block的关系(FULL, FIRST, MIDDLE, LAST)

 (1) A 在一个Block中完整存在;B一部分在Block1, 中间部分在Block2(显然B超过32K才有这种情况), B最后一部分在Block3

2.代码细节

2.1 每条Recored7B元数据

  1. 7B的元数据在这里完成组装,注释中payload 是指信息传输中的有用数据;
  2. 默认是写一条Record语义执行Flush到内核缓冲区,LogWriter本身不保证数据落盘; sycn语义在外部调用时用sync参数指定,才能保证每次写数据落盘。
Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr,
                                  size_t length) {
  // 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;
}

2.2 【高性能】 log_writer.cc 中 log::Writer的成员 uint32_t type_crc_[kMaxRecordType + 1]; 每次不需要计算LogType的CRC

   

static void InitTypeCrc(uint32_t* type_crc) {
    for(int i = 0; i <= kMaxRecordType; i++) {
        char t = i;
        type_crc[i] = crc32c::Value(&t, 1);
    }
}
  uint32_t crc = crc32c::Extend(type_crc_[t], ptr, length);

本节代码地址

section 5, log_writer · 9DemonFox/myleveldb@72728f1 · GitHub