leveldb中memtable封装了一个skiplist用来存储真正的数据,跳跃列表的实现一定需要定义存储项的序关系,而在leveldb中这个序关系通过comparator相关类来实现。leveldb中使用InternalKeyComparator
类来进行internal_key的比较操作。
int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
// Order by:
// increasing user key (according to user-supplied comparator)
// decreasing sequence number
// decreasing type (though sequence# should be enough to disambiguate)
int r = user_comparator_->Compare(ExtractUserKey(akey),ExtractUserKey(bkey));
if(r == 0) {
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
if(anum > bnum) {
r = -1;
}
else if (anum < bnum) {
r = +1;
}
}
return r;
}
Compare
函数中首先使用user_comparator_比较user_key的大小,如果user_key不相等则直接使用user_key的比较结果返回,否则继续比较sequence的大小。
注意:akey.data() + akey.size() - 8经过解码后是sequence的七位和type的一位组合的8位数字,但由于sequence是不可能重复的,所以这里不需要继续解码,直接比较结果也是正确的。
当user_key相同时,sequence按照逆序排序。即相同user_key中序列号越大,在skiplist中位置越靠前。
在这里给出默认的user_comparator_初始化流程以及其比较机制。
InternalKeyComparator
是继承于Comparator
的派生类,leveldb中还有一个继承于Comparator
的派生类:BytewiseComparatorImpl
。剧透一下:BytewiseComparatorImpl
就是默认的user_comparator_对象的类型。leveldb中默认使用BytewiseComparatorImpl
比较user_key,使用InternalKeyComparator
比较entry的internal_key部分。
在DB::Open函数中,impl被生成。
DBImpl* impl = new DBImpl(options, dbname);
DBImpl对象中有一成员internal_comparator_,其类型为InternalKeyComparator
。在DBImpl构造函数中,internal_comparator_成员通过传入的option中的成员初始化。默认情况下,Options的comparator成员初始化为BytewiseComparatorImpl
对象,所以internal_comparator_对象中的user_comparator_成员被初始化BytewiseComparatorImpl
类型。
Options::Options(): comparator(BytewiseComparator()), env(Env::Default()) {}
const Comparator* BytewiseComparator() {
static NoDestructor<BytewiseComparatorImpl> singleton;
return singleton.get();
}
来看看BytewiseComparatorImpl
类中是如何比较user_key的:其调用Slice的compare方法,首先比较a和b的长度,长度小的一方属于小的一方。当长度相同时,通过memcmp函数进行比较。
virtual int Compare(const Slice& a, const Slice& b) const {
return a.compare(b);
}
inline int Slice::compare(const Slice& b) const {
const size_t min_len = (size_ < b.size_) ? size_ : b.size_;
int r = memcmp(data_, b.data_, min_len);
if (r == 0) {
if (size_ < b.size_)
r = -1;
else if (size_ > b.size_)
r = +1;
}
return r;
}
DB::Open函数中接着使用impl->internal_comparator_对象初始化了impl对象中的mem_成员。
impl->mem_ = new MemTable(impl->internal_comparator_);
MemTable
类型中封装了类型KeyComparator
,其封装了InternalKeyComparator
。
struct KeyComparator {
const InternalKeyComparator comparator;
explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) {}
int operator()(const char* a, const char* b) const;
};
之后的Get,Put等基本操作的分析过程中会继续看到这些成员和函数的使用。
本节最重要的结论:通过InternalKeyComparator
和BytewiseComparatorImpl
这两个类,skiplist的存储项排序按照user_key升序,相同user_key项按照sequence降序。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。