levelDB中的key
前言
在levelDB
中有五种不同的key
,在正式分析memtable
之前我们先介绍一下这5中不同的key
- user_key
- ParsedInternalKey
- InternalKey
- LookupKey
- MemtableKey
user_key(用户key)
user_key
是Slice
结构体来表示的,其内部就是简单封装了字符串和它的size
。
顾名思义,这个key
就是用来保存用户输入的真实key
值。
class LEVELDB_EXPORT Slice {
//...
private:
const char* data_;
size_t size_;
};
ParsedInternalKey
ParseInternalKey
和InternalKey
是有所关联的,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_key
到ParseInternalKey
的转换
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_key
和user_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