Leveldb中每次都写都是通过Batch的方式进行批量操作,而Batch本质上做的事情就是将多次操作进行了编码,先通过WAL日志将编码后的内容落盘,然后交由Memtable进行批量写入,首先让我们看下Batch的结构。

class LEVELDB_EXPORT WriteBatch {
  public:
    .....
  private:
  friend class WriteBatchInternal;
  // 核心就是一个string,每次操作都会编码成string放在这里。
  std::string rep_;  // See comment in write_batch.cc for the format of rep_
};

接着我们看下WriteBatch是如何存放一次操作的。

void WriteBatch::Put(const Slice& key, const Slice& value) {
  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
  rep_.push_back(static_cast<char>(kTypeValue));
  // 先通过varint把size写入,接着写内容
  PutLengthPrefixedSlice(&rep_, key);
  PutLengthPrefixedSlice(&rep_, value);
}
  1. 先更新了WriteBatch中存放的操作个数
  2. 接着写入操作类型
  3. 最后将key和value的内容写入

最后我们来看下,一个WriteBatch编码后的内容格式,如下图:

Untitled

一条数据包含了sequence number、entry number、batch data,前8个字节用来存放sequence nunber,一次WriteBatch会分配一个递增的sequence nunber。接着8个字节用来存放这个WriteBatch中包含了多少次操作,接着就是每一次操作的具体内容了,就是上面提到的写入操作类型、key/value值等。