您的位置:首页 > 其它

LevelDB源码分析8-db key

2016-11-30 10:45 316 查看
为了更好的阅读Memtable,先看一看Memtable的key.

ValueType

levledb更新时不会操控db中的数据,每次操作都是直接插入一份kv数据,具体的数据合并和清除工作由后台的compact完成。所以,每次 put,db 中就会新加入一份 KV 数据,即使该 key 已经存在;而 delete 等同于 put 空的 value。为了区分真实 kv 数据和删除操作的 mock 数据,使用 ValueType 来标识:

enum ValueType {
kTypeDeletion = 0x0, //删除的key
kTypeValue = 0x1 //插入的key
};


SequenceNumber

SequenceNumber的定义为:
typedef uint64_t SequenceNumber;
.可见sequenceNumber是一个64位的数。每次更新时,由SequenceNumber来标识,整个 db 有一个全局值保存着当前使用到的 SequnceNumber。SequnceNumber 在 leveldb 有重要的地位,key 的排序,compact 以及 snapshot 都依赖于它。存储结构如下:

056
SequenceNumberValueType
SequnceNumber只占56bits,ValueType占用8bits.

因此定义了其最大值:

//SequenceNumber的最大值,56位
static const SequenceNumber kMaxSequenceNumber =
((0x1ull << 56) - 1);


ParsedInternalKey

ParsedInternalKey为db内部操作的key.db内部需要把user key(用户传入的key,为Slice格式)加入元信息一并处理。

//db内部操作的key,对用户传入的key(Slice)加入一个信息
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;
};


转换函数:

//把一个slice形式的internal_key转为一个ParsedInternalKey的struct
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);//seq+type
unsigned char c = num & 0xff;
result->sequence = num >> 8;
result->type = static_cast<ValueType>(c);
result->user_key = Slice(internal_key.data(), n - 8);//user_key
return (c <= static_cast<unsigned char>(kTypeValue));
}


 InternalKey

InternalKey为db内部使用,包装易用的结构,包含userkey于SequnceNumber/ValueType

InternalKey是内部成员为一个rep_(string).这个string组成为ParseInternalKey的元素:

//增加一个key的操作
void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
result->append(key.user_key.data(), key.user_key.size());//user key
PutFixed64(result, PackSequenceAndType(key.sequence, key.type));// SequenceNumber 和 ValueType
}


整体的结果如下

//InternalKey
class InternalKey {
private:
std::string rep_;//a string represent all the information
public:
InternalKey() { }   // Leave rep_ as empty to indicate it is invalid
//InternalKey string consist of (user_key)
InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {
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_;
}

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


LookupKey

db内部在memetable中查找数据使用

//LookupKey:db内部在memtable中查找数据
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();

// Return a key suitable for lookup in a MemTable.
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); }

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.
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&);
};

inline LookupKey::~LookupKey() {
if (start_ != space_) delete[] start_;
}




SkipList中的key

skiplist中的单个节点不仅存储了Key,也存储了value.格式如下图。内部的比较函数使用的是InternalKey。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: