leveldb之WriteBatch

1、leveldb的写数据

在leveldb中,我们通过调用db->Put(WriteOptions(),&key,&value);来写入数据,而WriteOptions只有一个变量sync,且默认初始值为false,因此leveldb默认的写数据方式是异步,即每将写操作提交将数据写入到内存中就返回,而将数据从内存写到磁盘的方式是异步的。

异步写比同步写的效率高得多,但是当系统故障时,可能导致最近的更新丢失。若将WriteOptions的sync设为true,则每次写入都会将数据写入到磁盘中,速度非常慢。

为此leveldb使用WriteBatch来替代简单的异步写操作,首先将所有的写操作记录到一个batch中,然后执行同步写,这样同步写的开销就被分散到多个写操作中。

利用leveldb的WriteBatch可以进行批量处理,用法如下:

  leveldb::WriteBatch batch;
  batch.Put(key1, value1);
  batch.Delete(key1);
  batch.Put(key2, value);
  s = db->Write(leveldb::WriteOptions(), &batch);

即使没有显式使用batch,在调用DB::Put()时,也是将一条记录通过WriteBatch的形式存储到系统中的

2、WriteBatch

WriteBatch的原理是先将所有的操作记录下来,然后再一起操作。

由之前的分析可知,leveldb插入和删除数据并不是直接插入、删除数据,而是插入一条记录(由记录的标志位来确定是要插入数据还是删除数据,具体的插入、删除操作将在Compaction时进行)
因此WriteBatch将会记录许多个操作,每一个操作代表着要插入或删除相应数据。

WriteBatch类的定义如下:

class WriteBatch {
 public:
  WriteBatch();
  ~WriteBatch();

  void Put(const Slice& key, const Slice& value);//写入一条要插入数据的记录
  void Delete(const Slice& key);//写入一条要删除数据的记录

  // Clear all updates buffered in this batch.
  void Clear(){//初始化
  rep_.clear();//首先清空rep_
  rep_.resize(kHeader);//equal to new char[KHeader],then you can use the buffer rep_.data()
}

  // Support for iterating over the contents of a batch.
  class Handler {
   public:
    virtual ~Handler();
    virtual void Put(const Slice& key, const Slice& value) = 0;
    virtual void Delete(const Slice& key) = 0;
  };
  Status Iterate(Handler* handler) const;

 private:
  friend class WriteBatchInternal;//so this class can access rep_

  std::string rep_;  //只有一个string成员变量,来存放所有操作
};

每一个WriteBatch都是以一个固定长度的头部开始,然后后面接着许多连续的记录,
固定头部共12字节,其中前8字节为WriteBatch的序列号,对应rep_[0]到rep_[7],每次处理Batch中的记录时才会更新,后四字节为当前Batch中的记录数,对应rep_[8]到rep_[11];

通过头部我们就可以知道每一个batch的序号了,并能够知道每一个batch中的记录数,将batch写入到文件中后就可以方便的依次获取每一条记录了。

后面的记录结构为:
插入数据时:type(kTypeValue、kTypeDeletion),Key_size,Key,Value_size,Value
删除数据时:type(kTypeValue、kTypeDeletion),Key_size,Key

3、WriteBatch的基本操作

WriteBatch的基本操作是记录一个要插入或删除某个数据的操作,最基本的操作就是Put和Delete

Put:将一条要插入数据的操作写入到rep_中

void WriteBatch::Put(const Slice& key, const Slice& value) {
  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);//操作总数加1
  rep_.push_back(static_cast<char>(kTypeValue));//写入操作类型
  PutLengthPrefixedSlice(&rep_, key);//写入key.size()和key.data()
  PutLengthPrefixedSlice(&rep_, value);//写入value.size()和value.data()
}

Delete:将一条要删除数据的操作写入到rep_中

void WriteBatch::Delete(const Slice& key) {
  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);//操作总数加1
  rep_.push_back(static_cast<char>(kTypeDeletion));//写入操作类型
  PutLengthPrefixedSlice(&rep_, key);//写入待删除数据的key值
}

4、基本示例

    WriteBatch wb;
    wb.Put("key1","hello");
    wb.Put("key2","hi");
    wb.Delete("key1");

执行上面的代码后,WriteBatch中的rep_如下:

10000000 3000 (前8位为序列号,从1开始,后4位为操作数,共3个操作)
0 4 k e y 1 5 h e l l o (第一个操作,0表示要插入数据)
0 4 k e y 2 2 h i (第二个操作)
1 4 k e y 1 (第三个操作,1表示要删除数据)
共39位

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值