LevelDB源码解读-MemTable1

MemTable

MemTable是基于 跳表这种数据结构的一种内存的数据组织形式,之前我们实现的跳表中Node节点是只有一个 Key的,但是我们需要存储的是Key-Value形式的结构,因此我们就有必要将key/value封装成为一个Key

请添加图片描述

请添加图片描述

  • Internal Key Size: 顾名思义,Internal Key的大小(通过Varint32进行编码)
  • Internal Key : Userkey, SeqNumber, ValueType(delete or value)
  • Value Size : 同样通过Varint32 进行编码
比较的规则

InternalKeyComparatorCompare按照下面的优先级进行排序

  • 按照UserKey 进行升序排序
  • 按照SequenceNumber进行降序排序
  • 按照ValueType进行降序排序(不用了,上面两个就足够了)

保证:如果UserKey是相同的,那么最新版本会在前面,也就是说前面的到的永远是最新版本的

函数Add

按照上面的格式进行封装到buf中然后插入到跳表

void Memtable::Add(SequenceNumber seq, ValueType type, const Slice& userkey, const Slice& value) {

    /*
      KeySize: 32bit 
      KeyByte: char[keysize]
      Tag    : uint64((seq << 8) | type) 
      v-size : 32bit 
      v-Byte : char[valuesize]
    */
    size_t key_size   = userkey.size();
    size_t value_size = value.size();
    size_t internal_key_size = key_size + 8;      //user key size + 8 byte(seq, valueType)
    
    //值进行很好的压缩,最终需要的存储的空间大小是多少(Byte
    const size_t encoded_len = VarintLength(internal_key_size) + internal_key_size + 
                               VarintLength(value_size) + value_size;

    char* buf = arena_.Allocate(encoded_len);

    //1. internal size
    char* p   = EncodeVarint32(buf, internal_key_size);

    //2. Userkey value
    std::memcpy(p, userkey.data(), key_size);

    p += key_size;
    //3. Seqnumber & type [固定8字节,所以是64-bit]
    EncodeFixed64(p, (seq << 8) | type);

    p += 8;   //fixed 8 bytes

    //4. Value size
    p = EncodeVarint32(p, value_size);
   
    //5. Value 
    std::memcpy(p, value.data(), value_size);

    //进行断言检测
    assert(p + value_size == buf + encoded_len);
    
    table_.Insert(buf);         //调用SkipList的插入

 } 
LookUpKey

我们在使用Get函数的时候, 传入的参数需要指定Key,因此使用LookUpkey类作为一个辅助的类进行一些字段的封装

    LookupKey::LookupKey(const Slice& user_key, SequenceNumber sequence) {
        size_t usize  = user_key.size();
        size_t needed = usize + 15;     //保守的估计,实际上一般用不了这么多

        char* dst;
        if (needed <= sizeof(space_)) {
            dst = space_;
        } else {
            dst = new char[needed];
        }

        //1. keysize_
        size_ = dst;            //size_是开始的位置
        dst = EncodeVarint32(dst, usize + 8);       //usersize + 8byte

        //2. userkey
        userKey_ = dst;         //下面接上size_之后的位置
        std::memcpy(dst, user_key.data(), usize);   //将userkey写过来

        //3. 8-byte (seq + type)
        dst += usize;                      
        EncodeFixed64(dst, PackSeqAndType(sequence, kValueTypeForSeek));                       //将seq & type(valueType)一起写到dst中

        dst += 8;
        end_ = dst;                                 //the end of the dst 
    }	
Get函数

Get函数,从跳表中拿出数据传入的参数通过lookupkey进行封装。其中调用了很多的解压缩的函数,压缩的方式是按照leveldbcoding的声明来实现的。

 bool Memtable::Get(const LookupKey& key, std::string* value, Status* status) {
    Slice memkey = key.memtable_key();
    Table::Iterator iter(&table_);
    iter.Seek(memkey.data());             //寻找的是key的部分,最终查找的结果存放在iter类中的node_中
    
    if (iter.Valid()) {
        const char* entry = iter.key();   //从跳表中拿到的entry 
        uint32_t key_length = 0;
        //这个函数会拿到internal_size, 并且跳过size的部分
        const char* userkey_ptr = GetVarint32Ptr(entry, entry + 5, &key_length);
        if (comparator_.comparator.user_Comparator()->Compare(key.user_key(), Slice(userkey_ptr, key_length - 8)) == 0) {
            //传入的userKey同跳表中拿到的userKey是一样的
            //sequence & type
            const uint64_t tag = DecodeFixed64(userkey_ptr + key_length);
            switch (static_cast<ValueType>(tag & 0xff)) {
              case kTypeValue: {
                  Slice v = GetLengthPrefixedSlice(userkey_ptr + key_length);
                  value->assign(v.data(), v.size());
                  return true;
              }
              case kTypeDelete: 
                *status = Status::NotFound(Slice());
                return true;
            }
        }
    } 
    return false;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值