当前位置:首页 > > 充电吧
[导读]这里的comparator包括抽象类Comparator及其两个实现类:一个是内置的BytewiseComparatorImpl,另一个是InternalKeyComparator。一.Compara

这里的comparator包括抽象类Comparator及其两个实现类:一个是内置的BytewiseComparatorImpl,另一个是InternalKeyComparator。
一.Comparator
Comparator只是导出了几个接口。

class Comparator {
 public:
  virtual ~Comparator();


  // Three-way comparison.  Returns value:
  //   < 0 iff "a" < "b",
  //   == 0 iff "a" == "b",
  //   > 0 iff "a" > "b"
  virtual int Compare(const Slice& a, const Slice& b) const = 0;


  // The name of the comparator.  Used to check for comparator
  // mismatches (i.e., a DB created with one comparator is
  // accessed using a different comparator.
  //
  // The client of this package should switch to a new name whenever
  // the comparator implementation changes in a way that will cause
  // the relative ordering of any two keys to change.
  //
  // Names starting with "leveldb." are reserved and should not be used
  // by any clients of this package.
  //返回comparator的名字
  virtual const char* Name() const = 0;


  // Advanced functions: these are used to reduce the space requirements
  // for internal data structures like index blocks.


  // If *start < limit, changes *start to a short string in [start,limit).
  // Simple comparator implementations may return with *start unchanged,
  // i.e., an implementation of this method that does nothing is correct.
  // 这两个函数作用是减少像index blocks这样的内部数据结构占用的空间。
  // 如果*start < limit,就在[start,limit)中找到一个短字符串,并赋给*start返回。
  // 当然返回的*start可能没变化(*start==limit),此时这个函数相当于啥都没干,这也是正确的。
  virtual void FindShortestSeparator(
      std::string* start,
      const Slice& limit) const = 0;


  // Changes *key to a short string >= *key.
  // Simple comparator implementations may return with *key unchanged,
  // i.e., an implementation of this method that does nothing is correct.
  // 将*key变成一个比原*key大的短字符串,并赋值给*key返回。
  virtual void FindShortSuccessor(std::string* key) const = 0;
};

二.BytewiseComparatorImpl
BytewiseComparatorImpl是按字典逐字节序进行比较的,也就是说i>helloworld,因为先比较i和h,i>h,比较结束。

class BytewiseComparatorImpl : public Comparator {
 public:
  BytewiseComparatorImpl() { }


  virtual const char* Name() const {
    return "leveldb.BytewiseComparator";
  }
  // 直接调用Slice的compare函数
  virtual int Compare(const Slice& a, const Slice& b) const {
    return a.compare(b);
  }
  // FindShortestSeparator找到start、limit之间最短的字符串,如“helloworld”和”hellozoomer”之间最短的key可以是”hellox”。
  virtual void FindShortestSeparator(
      std::string* start,
      const Slice& limit) const {
    // 找到共同前缀的长度
    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++;
    }
    // 如果一个字符串是另个一字符串的前缀,无需做截短操作,否则进入else。
    if (diff_index >= min_length) {
      // Do not shorten if one string is a prefix of the other
    } else {
      uint8_t diff_byte = static_cast((*start)[diff_index]);
      if (diff_byte < static_cast(0xff) &&
          diff_byte + 1 < static_cast(limit[diff_index])) {
        (*start)[diff_index]++;
        start->resize(diff_index + 1);
        assert(Compare(*start, limit) < 0);
      }
    }
  }
  // FindShortSuccessor则更极端,用于找到比key大的最短字符串,如传入“helloworld”,返回的key可能是“i”而已。
  virtual void FindShortSuccessor(std::string* key) const {
    // 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];
      if (byte != static_cast(0xff)) {
        (*key)[i] = byte + 1;
        key->resize(i+1);
        return;
      }
    }
    // *key is a run of 0xffs.  Leave it alone.
  }
};

三.Internal Key
1.Internal Key的结构。
下面是一个未编码前,或者说是一个解码后的Internal Key结构,它由user_key、sequence和type三个字段组成。

struct ParsedInternalKey {
  Slice user_key;
  SequenceNumber sequence;
  ValueType type;


  ParsedInternalKey() { }  // Intentionally left uninitialized (for speed)
  ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)
      : user_key(u), sequence(seq), type(t) { }
  std::string DebugString() const;
};

2.Internal Key的编码
源码中通过InternalKey类封装了Internal Key的相关操作。编码的用到的函数如下。

void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
  result->append(key.user_key.data(), key.user_key.size());
  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
}

static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
  assert(seq <= kMaxSequenceNumber);
  assert(t <= kValueTypeForSeek);
  return (seq << 8) | t;
}

AppendInternalKey函数先把user_key添加到*result中,然后用PackSequenceAndType函数将sequence和type打包,并将打包的结果添加到*result中。
PutFixed64函数只是简单的进行了拷贝,详见博客:LevelDB源码分析之一:coding
PackSequenceAndType函数的原理是先将seq左移8位,然后和t进行或操作,相当于把t放到了seq的低8为。为什么seq要小于等于kMaxSequenceNumber呢。
因为kMaxSequenceNumber的值如下所示。

typedef uint64_t SequenceNumber;
// We leave eight bits empty at the bottom so a type and sequence#
// can be packed together into 64-bits.
//0x1ull:u-unsigned 无符号;l-long 长整型,ll就是64位整型。整个0x1ull代表的含义是无符号64位整型常量1,用16进制表示。
static const SequenceNumber kMaxSequenceNumber = ((0x1ull << 56) - 1);

用二进制表示就是:0000 0000 1111 1111 1111 1111 1111 1111。如果seq大于kMaxSequenceNumber,左移8位的话会移出界。
3.Internal key的解码

inline bool ParseInternalKey(const Slice& internal_key,
                             ParsedInternalKey* result) {
  const size_t n = internal_key.size();
  if (n < 8) return false;
  // DecodeFixed64函数是PutFixed64函数的逆过程,返回sequence和type的打包结果,并赋值给num。
  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
  // 截取低8位,赋值给c
  unsigned char c = num & 0xff;
  // 右移8位,赋值给sequence
  result->sequence = num >> 8;
  // 将c转换为type
  result->type = static_cast(c);
  // 取出user_key
  result->user_key = Slice(internal_key.data(), n - 8);
  return (c <= static_cast(kTypeValue));
}

通过上述解码函数可以将编码后的internal_key解码为* result。为了使用方便,源码中还专门为解码user_key和type提供了两个函数。

// Returns the user key portion of an internal key.
inline Slice ExtractUserKey(const Slice& internal_key) {
  assert(internal_key.size() >= 8);
  return Slice(internal_key.data(), internal_key.size() - 8);
}

inline ValueType ExtractValueType(const Slice& internal_key) {
  assert(internal_key.size() >= 8);
  const size_t n = internal_key.size();
  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
  unsigned char c = num & 0xff;
  return static_cast(c);
}

四.InternalKeyComparator
InternalKeyComparator是要重点关注的一个比较器,它用来比较内部键(Internal Key)。内部键值是为了方便处理,将原普通键、序列号和值类型组成的新键。
先看下Compare函数

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;
}

1)首先比较user_key,如果user_key不相同,就直接返回比较结果,否则继续进行第二步。user_comparator_是用户指定的比较器,在InternalKeyComparator构造时传入。
2)在user_key相同的情况下,比较sequence_numer|value type然后返回结果(注意每个Internal Key的sequence_number是唯一的,因此不可能出现anum==bnum的情况)
再看看FindShortestSeparator函数

void InternalKeyComparator::FindShortestSeparator(
      std::string* start,
      const Slice& limit) const {
  // Attempt to shorten the user portion of the key
  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) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*start, tmp) < 0);
    assert(this->Compare(tmp, limit) < 0);
    start->swap(tmp);
  }
}

1)该函数取出Internal Key中的user_key字段,根据用户指定的comparator找到短字符串并替换user_start。此时user_start物理上是变短了,但是逻辑上却变大了,原理详见第二节的论述。
2)如果user_start被替换了,就用新的user_start更新Internal Key,并使用最大的sequence number。否则start保持不变。
接下来FindShortSuccessor函数

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) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*key, tmp) < 0);
    key->swap(tmp);
  }
}

原理上与FindShortestSeparator相同。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭