leveldb 源码阅读,细节记录memberTable

leveldb 是看着前辈们的大概分析,然后看着源码,将自己的疑惑和解决记录下来:

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。

 

posted @ 2015-12-06 20:18  Xuyung  阅读(251)  评论(0编辑  收藏  举报