菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
41
0

leveldb源代码分析系列1.1:memtable中comparator的实现

原创
05/13 14:22
阅读数 1120

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等基本操作的分析过程中会继续看到这些成员和函数的使用。

本节最重要的结论:通过InternalKeyComparatorBytewiseComparatorImpl这两个类,skiplist的存储项排序按照user_key升序,相同user_key项按照sequence降序。

发表评论

0/200
41 点赞
0 评论
收藏