继续上一篇内容,本篇继续说明leveldb是如何将数据插入到MemTable中。
一、Iterate循环处理
插入到MemTable使用该接口WriteBatchInternal::InsertInto,具体实现是:
Status WriteBatchInternal::InsertInto(const WriteBatch* b,
MemTable* memtable) {
//初始化 Handler
MemTableInserter inserter;
inserter.sequence_ = WriteBatchInternal::Sequence(b);//获取序号
inserter.mem_ = memtable;
return b->Iterate(&inserter);
}
在WriteBatch中可能存在多个key-value对,所以在WriteBatch类中提供了一个迭代器方法Iterate,具体实现如下:
/**
* 将key-value一个一个存储到Memtable中
* @param handler 真正执行存储操作
* 特别说明:
* rep_是数据保存地方,格式为seq number|count|key-value|...|key-value
* Iterate方法主要工作是将一个一个key-value对解析出来 插入到Memtable中
*/
Status WriteBatch::Iterate(Handler* handler) const {
Slice input(rep_);
if (input.size() < kHeader) {
return Status::Corruption("malformed WriteBatch (too small)");
}
input.remove_prefix(kHeader);//跳过头部信息 seq number | count
Slice key, value;
int found = 0;
while (!input.empty()) {
found++;
char tag = input[0]; // 获取type
input.remove_prefix(1);
switch (tag) {
case kTypeValue://添加操作
if (GetLengthPrefixedSlice(&input, &key) &&
GetLengthPrefixedSlice(&input, &value)) {//解析出key - value
handler->Put(key, value);// MemTableInserter 此处的key value就是用输入的key和value
} else {
return Status::Corruption("bad WriteBatch Put");
}
break;
case kTypeDeletion://删除操作
if (GetLengthPrefixedSlice(&input, &key)) {
handler->Delete(key);//这里key为用户输入key
} else {
return Status::Corruption("bad WriteBatch Delete");
}
break;
default:
return Status::Corruption("unknown WriteBatch tag");
}
}
//最后再次判断是否已经完全处理完
if (found != WriteBatchInternal::Count(this)) {
return Status::Corruption("WriteBatch has wrong count");
} else {
return Status::OK();
}
}
通过上面代码可知,调用handler中的Put和Delete方法进行插入和删除。通过上面可知handler实际为MemTableInserter,下面是Put和Delete实现,比较简单:
virtual void Put(const Slice& key, const Slice& value) {
mem_->Add(sequence_, kTypeValue, key, value);
sequence_++;
}
/**
* Memtable只有插入操作 并没有真正删除操作
*/
virtual void Delete(const Slice& key) {
mem_->Add(sequence_, kTypeDeletion, key, Slice());// value是空字符串
sequence_++;
}
这里需要强调一下:
1) 这里的key/value是用户输入的key/value,后面在MemTable中leveldb会对其再次封装成InternalKey。
2) 这里的sequence_ 是独立计数器。
二、MemTable插入操作
对于MemTable插入流程可参考本篇《leveldb深度剖析-MemTable》。当MemTable占用内存空间超过4M就会将MemTable中数据flush到level0文件中,下一篇将介绍是如何写入到level0中。