Put操作
继续看该段代码:
1 | leveldb::WriteOptions writeOptions; |
写入两次Key0,第一次value值为”Test data value: 0”,第二次value值为”Test data value: 1”
上一篇文章讲述了如何插入log文件,这篇文章讲述如何插入memtable文件
在如下位置打断点,并且看下调用路径:
1 | (gdb) b /home/xiaoju/leveldb/db/write_batch.cc:128 |
该函数代码如下:
1 | Status WriteBatchInternal::InsertInto(const WriteBatch* b, |
其中WriteBatch的Iterate函数会调用inserter的put/delete方法依次将数据插入.我们看下put方法调用
首先打印出在skiplist中的保存格式:
1 | (gdb) p encoded_len |
skiplist中的保存格式如下图:
对应gdb解析出的数据,可以看到八进制”\f”表示key总长度为12,”Key0”占4个字节,sequence<<8|type占用8个字节,可以看到type为1,sequence为3.接着是value的长度18及value值”Test data value: 0”
注意comparator比较时首先按key值的字母序比较,如果key值相同,则sequence大的会放到前边.
Get和Delete操作
1 | leveldb::ReadOptions readOptions; |
Get时会根据当前的sequence或者snapshot的sequence查找一个最新的key,即sequence最大的key.然后根据type判断是否删除,如果删除返回不存在该元素.否则返回相应的value
当然,Get如果在memtable中未查找到,会继续去immutable memtable和sstable中查找.immutable的查找同memtable.sstable的查找后文详述
Delete操作也是一个Put操作,只不过type是删除类型.
默认比较操作见dbformat.cc的如下函数
1 | int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const |
leveldb中的comparator
笔者在查看该处代码时对comparator类型有颇多疑问,所有单独加此一节介绍一下comparator类型
首先看一下调用链:
1 | #0 leveldb::InternalKeyComparator::Compare (this=0x6069e8, akey=..., bkey=...) at db/dbformat.cc:55 |
首先,db_impl.cc中的DB::Open函数如下语句:
1 | impl->mem_ = new MemTable(impl->internal_comparator_); |
打印出impl->internal_comparator_,
1 | (gdb) p impl.internal_comparator_.Name() |
memtable.cc中的构造函数如下:
1 | MemTable::MemTable(const InternalKeyComparator& cmp) |
我们看下memtable.h中各变量的定义:
1 | class MemTable { |
KeyComparator构造函数将comparator赋值为c,并且重载括号操作符.重载后为:
1 | int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) |
InternalKeyComparator的Compare函数为:
1 | int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { |
注意首先初始化options将comparator赋值为BytewiseComparatorImpl
1 | internal_comparator_(raw_options.comparator) |
然后用InternalKeyComparator的构造函数将user_comparator_赋值为BytewiseComparatorImpl
首先按key的字母序排,然后按sequence number,sequence大的排在前边.
调用时按如下方法:
1 | template<typename Key, class Comparator> |
重载括号操作符后会调用MemTable::KeyComparator::operator()函数.详见上文第一步bt后的调用链.