levelDB的组件Comparator、Status、Env、Options
levelDB中有很多常用的组件,下面我们来对其进行介绍。
- Comparator : 定义了比较的规则,是一个虚基类。
 
- Status : 定义函数执行的结果信息。
 
- Env : 封装系统相关的调用,比如文件操作,线程操作。
 
- Options : 指定数据库选项。
 
Comparator
            源码位置与说明:
utils/comparator.h utils/comparator.cc :
虚基类与BytewiseComparatorImpl类头文件与实现
db/dbformat.h db/format.cc :
InternalKeyComparator类头文件与实现
           
Comparator定义了比较规则,这个是一个虚基类,所以如果想要实现自定义的接口需要实现自己的类。
其中levelDB基于Comparator实现了一些内置比较类:BytewiseComparatorImpl和InternalKeyComparator,两者的作用是不同的。
- BytewiseComparatorImpl : 实现key的按二进制来进行比较。
 
- InternalKeyComparator :
用于内部的key比较器,基于BytewiseComparatorImpl。
 
            由于levelDB是key-value的结构,其中key就是Slice对象。所以BytewiseComparatorImpl用于key之间的比较,这个key称为usr-key。
但是levelDB内部的存储的key结构并不是usr-key,所以需要默认定义两种比较类。
           
Comparator源码剖析
首先我们来看一下虚基类的定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   |  class LEVELDB_EXPORT Comparator { public:          virtual ~Comparator();          virtual int Compare(const Slice &a, const Slice &b) const = 0;
           virtual const char *Name() const = 0;
                               virtual void FindShortestSeparator(std::string *start,                                        const Slice &limit) const = 0;
                          virtual void FindShortSuccessor(std::string *key) const = 0; };
 
 
  | 
 
其中FindShortestSeparator和FindShortSuccessor可能会令人感到疑惑,这两个方法的作用是缩短索引。因为levelDB内部是有序的,假如有这样的两个索引"Aaaaa"和"Acccc",其实我们只需要"Ab"就能将两者分开了;另外,假如一个表中的最后一项是"Yaaaa",我们只需要"Z"就能确定这个项的上界了。这就是这两个函数能减短索引的原理。
接下来我们来看一下BytewiseComparatorImpl类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
   |  class BytewiseComparatorImpl : public Comparator { public:     BytewiseComparatorImpl() = default;     const char *Name() const override { return "leveldb.BytewiseComparator"; }     int Compare(const Slice &a, const Slice &b) const override     {         return a.compare(b);     }
      void FindShortestSeparator(std::string *start,                                const Slice &limit) const override     {                  size_t min_length = std::min(start->size(), limit.size());         size_t diff_index = 0;         while ((diff_index < min_length) &&                ((*start)[diff_index] == limit[diff_index]))         {             diff_index++;         }
          if (diff_index >= min_length)         {                      }         else         {                          uint8_t diff_byte = static_cast<uint8_t>((*start)[diff_index]);             if (diff_byte < static_cast<uint8_t>(0xff) &&                 diff_byte + 1 < static_cast<uint8_t>(limit[diff_index]))             {                 (*start)[diff_index]++;                 start->resize(diff_index + 1);                 assert(Compare(*start, limit) < 0);             }         }     }
      void FindShortSuccessor(std::string *key) const override     {                  size_t n = key->size();         for (size_t i = 0; i < n; i++)         {             const uint8_t byte = (*key)[i];             if (byte != static_cast<uint8_t>(0xff))             {                 (*key)[i] = byte + 1;                 key->resize(i + 1);                 return;             }         }              } };
 
 
 
  const Comparator *BytewiseComparator() {     static NoDestructor<BytewiseComparatorImpl> singleton;     return singleton.get(); }
 
 
  | 
 
这部分比较的规则其实就是我们前面看到的虚基类的具体化。需要注意它存在一个为了保证线程安全的方法,进一步了解可以看此处。
接下来我们来看一下InternalKeyComparator的头文件和实现文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | 
 
  class InternalKeyComparator : public Comparator { private:          const Comparator *user_comparator_;
  public:          explicit InternalKeyComparator(const Comparator *c) : user_comparator_(c) {}     const char *Name() const override;     int Compare(const Slice &a, const Slice &b) const override;     void FindShortestSeparator(std::string *start,                                const Slice &limit) const override;     void FindShortSuccessor(std::string *key) const override;
           const Comparator *user_comparator() const { return user_comparator_; }          int Compare(const InternalKey &a, const InternalKey &b) const; };
 
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
   | 
 
  const char *InternalKeyComparator::Name() const {     return "leveldb.InternalKeyComparator"; }
 
  int InternalKeyComparator::Compare(const Slice &akey, const Slice &bkey) const {     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; }
 
  void InternalKeyComparator::FindShortestSeparator(std::string *start,                                                   const Slice &limit) const {     Slice user_start = ExtractUserKey(*start);     Slice user_limit = ExtractUserKey(limit);     std::string tmp(user_start.data(), user_start.size());     user_comparator_->FindShortestSeparator(&tmp, user_limit);     if (tmp.size() < user_start.size() &&         user_comparator_->Compare(user_start, tmp) < 0)     {         PutFixed64(&tmp,                    PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));         assert(this->Compare(*start, tmp) < 0);         assert(this->Compare(tmp, limit) < 0);         start->swap(tmp);     } }
  void InternalKeyComparator::FindShortSuccessor(std::string *key) const {     Slice user_key = ExtractUserKey(*key);     std::string tmp(user_key.data(), user_key.size());     user_comparator_->FindShortSuccessor(&tmp);     if (tmp.size() < user_key.size() &&         user_comparator_->Compare(user_key, tmp) < 0)     {         PutFixed64(&tmp,                    PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));         assert(this->Compare(*key, tmp) < 0);         key->swap(tmp);     } }
 
  inline int InternalKeyComparator::Compare(const InternalKey &a,                                           const InternalKey &b) const {     return Compare(a.Encode(), b.Encode()); }
 
 
  | 
 
我们可以看到InternalKeyComparator的比较其实也是基于usr-key的,不过由于内部key与usr-key存在差异,剩余的代码主要是处理差异的,具体我们先不展开。
Status
            源码位置: leveldb/include/status.h
util/status.cc
           
这个类主要定义了很多操作的返回码,很多操作需要通过返回的status来判断下一步的行为。
Status源码剖析
我们接下来来看一下它的头文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
   |  class LEVELDB_EXPORT Status { private:          enum Code     {         kOk = 0,         kNotFound = 1,         kCorruption = 2,         kNotSupported = 3,         kInvalidArgument = 4,         kIOError = 5     };
      Code code() const     {         return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);     }     Status(Code code, const Slice &msg, const Slice &msg2);     static const char *CopyState(const char *s);
                          const char *state_;
  public:          Status() noexcept : state_(nullptr) {}     ~Status() { delete[] state_; }     Status(const Status &rhs);     Status &operator=(const Status &rhs);     Status(Status &&rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; }     Status &operator=(Status &&rhs) noexcept;
           static Status OK() { return Status(); }     static Status NotFound(const Slice &msg, const Slice &msg2 = Slice())     {         return Status(kNotFound, msg, msg2);     }     static Status Corruption(const Slice &msg, const Slice &msg2 = Slice())     {         return Status(kCorruption, msg, msg2);     }     static Status NotSupported(const Slice &msg, const Slice &msg2 = Slice())     {         return Status(kNotSupported, msg, msg2);     }     static Status InvalidArgument(const Slice &msg, const Slice &msg2 = Slice())     {         return Status(kInvalidArgument, msg, msg2);     }     static Status IOError(const Slice &msg, const Slice &msg2 = Slice())     {         return Status(kIOError, msg, msg2);     }
           bool ok() const { return (state_ == nullptr); }
           bool IsNotFound() const { return code() == kNotFound; }     bool IsCorruption() const { return code() == kCorruption; }     bool IsIOError() const { return code() == kIOError; }     bool IsNotSupportedError() const { return code() == kNotSupported; }     bool IsInvalidArgument() const { return code() == kInvalidArgument; }
           std::string ToString() const; };
 
 
  | 
 
由于这个类主要就是处理错误类型的,所以其实现也是非常简单的,此处就不展开了。
不过实现内部有一个小技巧:用memcpy去进行赋值。这个似乎会更快一些,不过我觉得这个还是用于大数组会比较好吧,毕竟针对内存块有SIMD之类的优化。
Env
            源码位置:
include/leveldb/env.h : env相关的接口定义
util/env_posix.cc util/posix_logger.h :
Posix系统相关的封装,包括文件操作,文件锁,后台线程创建,Posix写日志
util/env_windows.cc util/windows_logger.h :
Windows相关的实现
           
LevelDB是一个数据库函数库,数据库总是需要操作文件和线程,这就需要做很多系统调用。各个操作系统的系统调用方式不一样,为了跨平台支持,LevelDB对这些系统调用做了一层封装,提供了统一的接口来操作,并且提供了Posix和Windows两种实现,如果需要实现其他的系统,只需要根据系统实现相应的Env即可。
不过由于这些代码实在是太多,而且也就是一些系统调用,所以此处不展开了。
里面感觉有用的就是关于多线程的一个锁的问题,但是也相对比较简单。
Options
            源码位置:leveldb/include/options.h
util/options.cc
           
Options定义了操作数据库的选项,定义了3个struct来操作:
- Options定义打开数据库的选项
 
- ReadOptions定义读操作相关的选项
 
- WriteOptions定义写操作相关的选项
 
同样的,这部分源码也非常简单,也不展开了
总结
编程小技巧
- 可以定义虚基类来规定接口。
 
- 需要处理线程安全问题。
 
- memcpy进行数组赋值会更快。