大白话解析LevelDB:Comparator

LevelDB 中的 Comparator

LevelDB 中 将 Key 之间的比较抽象为 Comparator,方便用户根据不同的业务场景实现不同的比较策略。

Comparator 接口概述

class LEVELDB_EXPORT Comparator {
   public:
    virtual ~Comparator();

    // 用于比较 Key a 和 Key b。
    //   - 如果 a < b,返回值 < 0;
    //   - 如果 a == b,返回值 == 0;
    //   - 如果 a > b,返回值 > 0。
    virtual int Compare(const Slice& a, const Slice& b) const = 0;

    // Comparator 的名称,用于检查 Comparator 是否匹配。
    // 比如数据库创建时使用的是 Comparator A,
    // 重新打开数据库时使用的是 Comparator B,
    // 此时 LevelDB 则会检测到 Comparator 不匹配。
    virtual const char* Name() const = 0;

    // 找到一个最短的字符串 seperator,使得 start <= seperator < limit,
    // 并将结果保存在 start 中。
    // 用于 SST 中 Data Block 的索引构建。
    virtual void FindShortestSeparator(std::string* start, const Slice& limit) const = 0;

    // 找到一个最短的字符串 successor,使得 key <= successor,
    // 并将结果保存在 key 中。
    // 用于 SST 中最后一个 Data Block 的索引构建,
    // 因为没有后续的 Key 了。
    virtual void FindShortSuccessor(std::string* key) const = 0;
};

LevelDB 中 Comparator 的默认实现:BytewiseComparatorImpl

在 LevelDB 中,如果用户没有指定 Comparator,那么 LevelDB 将使用默认的 Comparator:BytewiseComparatorImpl。

BytewiseComparatorImpl::Compare(const Slice& a, const Slice& b)

int Compare(const Slice& a, const Slice& b) const override { return a.compare(b); }

BytewiseComparatorImpl::Compare(const Slice& a, const Slice& b)的实现非常简单,直接甩给了 Slice::compare(const Slice& b)

inline int Slice::compare(const Slice& b) const {
    // 计算两个`Slice`的最小长度
    const size_t min_len = (size_ < b.size_) ? size_ : b.size_;
    // 使用`memcmp`比较两个字符串的前 min_len 个字符
    int r = memcmp(data_, b.data_, min_len);
    // 如果前 min_len 个字符相等,则比较两个字符串的长度
    if (r == 0) {
        if (size_ < b.size_)
            r = -1;
        else if (size_ > b.size_)
            r = +1;
    }
    return r;
}

Slice::compare(const Slice& b)就是使用了memcmp来比较。memcmp是一个 C 标准库函数,按字节序比较两个字符串的前 n 个字符。

BytewiseComparatorImpl::FindShortestSeparator(std::string* start, const Slice& limit)

BytewiseComparatorImpl::FindShortestSeparator的思路就是找到startlimit第一个不相同字符的下标diff_index, 然后将start[diff_index]加1,start[:diff_index]就是最短的分隔符。

void FindShortestSeparator(std::string* start, const Slice& limit) const override {
    // 先计算出 start 和 limit 的最短长度
    size_t min_length = std::min(start->size(), limit.size());
    // diff_index 用于记录 start 和 limit 第一个不同的字符的位置
    size_t diff_index = 0;
    while ((diff_index < min_length) && ((*start)[diff_index] == limit[diff_index])) {
        diff_index++;
    }

    if (diff_index >= min_length) {
        // 走到这就表示 start 是 limit 的前缀。
        // 这种 case 下,start 本身就是最短的分隔符,可以直接返回。
    } else {
        // 获取 start 的 第 diff_index 个字符
        uint8_t diff_byte = static_cast<uint8_t>((*start)[diff_index]);
        // 先判断 diff_byte < 0xff 的意义在于
        // 防止 diff_byte + 1 溢出,导致结果不正确。
        if (diff_byte < static_cast<uint8_t>(0xff) &&
            diff_byte + 1 < static_cast<uint8_t>(limit[diff_index])) {
            // start 与 limit 的前 diff_index 个字符都相同,
            // 只需要把 start 的第 diff_index 个字符加 1 ,
            // 就得到 Shortest Seperator 了。
            (*start)[diff_index]++;
            start->resize(diff_index + 1);
            assert(Compare(*start, limit) < 0);
        }
    }
}

BytewiseComparatorImpl::FindShortSuccessor(std::string* key)

FindShortSuccessor用于构建 SST 中最后一个 Data Block 的索引,因为没有后续的 Key 了。

void FindShortSuccessor(std::string* key) const override {
    // Find first character that can be incremented
    size_t n = key->size();
    for (size_t i = 0; i < n; i++) {
        const uint8_t byte = (*key)[i];
        // 找到第一个小于 0xff 的字符,然后加 1
        // 以该字符为上界。 
        if (byte != static_cast<uint8_t>(0xff)) {
            (*key)[i] = byte + 1;
            key->resize(i + 1);
            return;
        }
    }
    // *key is a run of 0xffs.  Leave it alone.
}
  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值