leveldb 是看着前辈们的大概分析,然后看着源码,将自己的疑惑和解决记录下来:
从memberTable插入一条记录和查找一条记录从上而下分析
插入:
插入的函数 void MemTable::Add(SequenceNumber s, ValueType type,const Slice& key,const Slice& value)
参数:
SequenceNumber 插入的序号,在skiplist里,这个序号是降序列的
ValueType type 类型添加值还是删除值,
Slice key 就是key
value 就是value
void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key, const Slice& value) { // Format of an entry is concatenation of: // key_size : varint32 of internal_key.size() // key bytes : char[internal_key.size()] // value_size : varint32 of value.size() // value bytes : char[value.size()] size_t key_size = key.size(); size_t val_size = value.size(); size_t internal_key_size = key_size + 8; const size_t encoded_len = VarintLength(internal_key_size) + internal_key_size + VarintLength(val_size) + val_size; char* buf = arena_.Allocate(encoded_len); char* p = EncodeVarint32(buf, internal_key_size); memcpy(p, key.data(), key_size); p += key_size; EncodeFixed64(p, (s << 8) | type); p += 8; p = EncodeVarint32(p, val_size); memcpy(p, value.data(), val_size); assert((p + val_size) - buf == encoded_len); table_.Insert(buf); }
这段代码是让
buf=key.size()压缩存储+(key+(SequenceNumber | TypeValue))+value.size()压缩存储+value
再将buf添加到skiplist里
查找:MemTable::Get(const LookupKey& key, std::string* value, Status* s)
参数:
LookupKey& key 查找的key,
string* value 用于存放查找结果的value
Status* s 存储key的状态,是删除还是添加
bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { Slice memkey = key.memtable_key(); Table::Iterator iter(&table_); iter.Seek(memkey.data()); if (iter.Valid()) { // entry format is: // klength varint32 // userkey char[klength] // tag uint64 // vlength varint32 // value char[vlength] // Check that it belongs to same user key. We do not check the // sequence number since the Seek() call above should have skipped // all entries with overly large sequence numbers. const char* entry = iter.key(); uint32_t key_length; const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); if (comparator_.comparator.user_comparator()->Compare( Slice(key_ptr, key_length - 8), key.user_key()) == 0) { // Correct user key const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); switch (static_cast<ValueType>(tag & 0xff)) { case kTypeValue: { Slice v = GetLengthPrefixedSlice(key_ptr + key_length); value->assign(v.data(), v.size()); return true; } case kTypeDeletion: *s = Status::NotFound(Slice()); return true; } } } return false; }
首先需要从LookupKey里提取符合memberTable格式的key出来,因为前面存储时是按照一定格式来的,所以LookupKey.memberTable_key()返回的字符串格式是:key.size()压缩存储+(key+(SequenceNumber | TypeValue),但是为什么没有后面的那部分呢(value.size()压缩存储+value),这是因为有 InternalKeyComparator class 的存在,这个是继承Comparator class的,而且里面包含了一个comparator。InternalKeyComparator相当于一个适配器,将符合memberTable key格式的数据段将key提取出来,再用用户自定义的comparator或者预置的comparator来对真实的key进行比较。如果真实key比较结果是相同,则将(SequenceNumber| TypeValue)提取出来进行比较,真实情况下,Type不会进行比较,只是SequenceNumber进行比较,因为SequenceNumber是在SkipList 里是降序排序的,为了防止TypeValue对排序的影响,所以LookupKey里的TypeValue是0x1。