Rocksdb的Memtable
概述
因为Rocksdb采用LSM-Tree的算法实现,用户使用Rocksdb进行插入或删除操作key-value,首先写入内存的数据结构—Memtable,一旦一个Memtable被写满,它就会转为Immutable,然后被替换为一个新的Memtable.
Memtable 和 Immutable Memtable
在Rocksdb中,Memtable 和 Immutable memtable都位于内存, 它俩属于一样的数据结构,唯一的区别是Memtable可读可写,而Immutable memtable是只读的,不允许写入。Rocksdb引入了Column family的概念,在一个Column family中只有一个Memtable,但允许存在多个Immutable memtable. 与LevelDB不同的是,Rocksdb实现多个数据结构类型的Memtable,默认的是SkipList,即跳跃表。用户可以根据不同的需求,选择不同的Memtable实现,参考Wiki-Memtable。
Memtable 与Immutable Memtable的转换
在一个column family中,维护一个Memtable数据结构mem_和一个Immutable Memtable的列表imm_:
MemTable* mem_;
|
当达到限定条件,需要将Memtable转为Immutable Memtable时:首先构造一个新的Memtable, 然后将旧的Memtable添加至imm_,增加新的Memtable的引用计数,最后将新的Memtable添加至column family:
new_mem = cfd->ConstructNewMemtable(mutable_cf_options, seq);
|
Memtable的数据结构
我们以默认的SkipList来分析Memtable, 源码在db/memtable.cc,在一个Memtable中维护两个SkipList,其中范围删除插入range_del_table_,其余的操作写入table_。首先来看Memtable定义的操作接口: Add(),Get()
Add()
bool MemTable::Add(SequenceNumber s, ValueType type,
|
Add()函数将用户的key和value封装成一个buf,然后根据不同的条件调用table->Insert()插入至Memtable。table就是Memtable的工厂类实现,默认SkiplistRep, 即通过调用SkipList的Insert()完成key的插入。
Get()
bool MemTable::Get(const LookupKey& key, std::string* value, Status* s,
|
Memtable的Get()调用了SkipListRep的Get()接口,通过SkipList的FindGreaterOrEqual()来查找。查找出来的key会被传入的回调函数SaveValue()根据type处理,例如kTypeDeletion就返回NotFound()。
我们顺便来看一下SkipList的实现: memtable/skiplist.h
SkipList数据结构
class SkipList {
|
SkipList本质上是一个带有分层的有序链表:
Node的数据结构
template<typename Key, class Comparator>
|
SkipList的插入
这个就是Memtable的Add()最后写入Skiplist调用的接口Insert()。插入的时候随机生成一个高度height,将构造的新的节点从第0层到height层分别插入。
template<typename Key, class Comparator>
|
SkipList的迭代
SkipList的Iterator迭代比较简单,直接从第0层的单链表根据next_[0]顺序迭代。

浙公网安备 33010602011771号