LevelDB源码阅读-key

levelDB中的key

前言

levelDB中有五种不同的key,在正式分析memtable之前我们先介绍一下这5中不同的key

  • user_key
  • ParsedInternalKey
  • InternalKey
  • LookupKey
  • MemtableKey
user_key(用户key)

user_keySlice结构体来表示的,其内部就是简单封装了字符串和它的size
顾名思义,这个key就是用来保存用户输入的真实key值。

class LEVELDB_EXPORT Slice {
//...
 private:
  const char* data_;
  size_t size_;
};
ParsedInternalKey

ParseInternalKeyInternalKey是有所关联的,ParsedInternalKey是解析后的InternalKey

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

解析internal_key的函数,实现internal_keyParseInternalKey的转换

inline bool ParseInternalKey(const Slice& internal_key,
                             ParsedInternalKey* result) {
  const size_t n = internal_key.size();
  if (n < 8) return false;
  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
  unsigned char c = num & 0xff;
  //分别得到sequence type 和user_key
  result->sequence = num >> 8;
  result->type = static_cast<ValueType>(c);
  result->user_key = Slice(internal_key.data(), n - 8);
  return (c <= static_cast<unsigned char>(kTypeValue));
}
InternalKey(内部key)
class InternalKey {
 private:
   //私有成员,就是一个简单的字符串
  std::string rep_;
 public:
  //构造函数
  InternalKey() { }   // Leave rep_ as empty to indicate it is invalid
  InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {
    //构造一个内部key
    AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t));
  }

  void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); }
  Slice Encode() const {
    assert(!rep_.empty());
    return rep_;
  }
  //返回user_key
  Slice user_key() const { return ExtractUserKey(rep_); }

  void SetFrom(const ParsedInternalKey& p) {
    rep_.clear();
    AppendInternalKey(&rep_, p);
  }

  void Clear() { rep_.clear(); }

  std::string DebugString() const;
};

从源码可以看出,InternalKey的内部组成(rep_)格式为
(当插入数据时,SequenceNumber会依次增长)

|user_key|SequenceNumber|ValueType|
LookupKey / MemtableKey

LookupKey的内部组成为

| Size (int32变长)| User key (string) | sequence number (7 bytes) | value type (1 byte) |

维护了3个指针,如图:
在这里插入图片描述

内部成员函数
可以调用以下几个成员函数,返回不同类型的key,之前已经介绍过了internal_keyuser_key,以下代码的逻辑很简单。

  // Return a key suitable for lookup in a MemTable.
  //返回适合在MemTable中进行查找的key。
  Slice memtable_key() const { return Slice(start_, end_ - start_); }

  // Return an internal key (suitable for passing to an internal iterator)
  Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }

  // Return the user key
  Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }

LookupKey的结构源码

class LookupKey {
 public:
  // Initialize *this for looking up user_key at a snapshot with
  // the specified sequence number.
  LookupKey(const Slice& user_key, SequenceNumber sequence);
  ~LookupKey();
  //...

 private:
  // We construct a char array of the form:
  //    klength  varint32               <-- start_
  //    userkey  char[klength]          <-- kstart_
  //    tag      uint64
  //                                    <-- end_
  // The array is a suitable MemTable key.
  // The suffix starting with "userkey" can be used as an InternalKey.
  //内部维护了3个指针
  const char* start_;
  const char* kstart_;
  const char* end_;
  char space_[200];      // Avoid allocation for short keys

  // No copying allowed
  LookupKey(const LookupKey&);
  void operator=(const LookupKey&);
};

构造函数

LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
  size_t usize = user_key.size();
  size_t needed = usize + 13;  // A conservative estimate
  char* dst;
  //如果需求量小于space的大小,则直接指向space
  if (needed <= sizeof(space_)) {
    dst = space_;
  } else {
  //否则新开辟一段空间来满足需求
    dst = new char[needed];
  }
  //start_指向起始位置
  start_ = dst;
  dst = EncodeVarint32(dst, usize + 8);
  //kstart指向user_key开始的位置
  kstart_ = dst;
  memcpy(dst, user_key.data(), usize);
  dst += usize;
  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
  dst += 8;
  //end_指向结束的位置
  end_ = dst;
}

总结

以上介绍了在levelDB中出现的所有key,在不同的地方由他们不同的用处,我们可以看到lookup_key是比较通用的一种,可以调用其内部的成员函数返回其他类型的key。接下来我们正式分析memtable

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值