leveldb-SSTable中部分代码实现

本文简要说明了block和footer中的代码实现,其中带有注释和部分讲解

blockbuilder

blockbuilder的结构

class BlockBuilder {
  
  // 存放的就是按照输出的格式进行处理好的内存区域
  std::string 	buffer_;
  
  // 同一个restart区域就是属于group的区域, 内部的key只是会存放non-shared的部分
  std::vector<uint32_t> restarts_;		
  
  // 所有的entries的数目
  int 					counter_;		
  
  // 是否是finish了, Finish() called
  bool finished_;		
  
  //最后一个key?
  
  std::string last_key_;
};

  • Entry: 保存具体的key, value数据,当然是no-shared
  • Restart:保存每条restart 索引
  • RestartNum: restart的数目,能够找到restart的 起点
BlockBuilder::BlockBuilder(const Options* options)
    : options_(options), restarts_(), counter_(0), finished_(false)
{
    assert(options->block_restart_interval >= 1);
    restarts_.push_back(0);     // 第一个重启点的Offset是0
}    

Slice BlockBuilder::Finish() {
    // 结束了key value 的插入,restart代表着索引啥的,插入进去
    for (int i = 0; i < restarts_.size(); i++) {
        PutFixed32(&buffer_, restarts_[i]);
    }
    PutFixed32(&buffer_, restarts_.size());     // 这样就能够确认首个restart的位置
    finished_ = true;
    return Slice(buffer_);
}

size_t BlockBuilder::CurrentSizeEstimate() const {
    return buffer_.size() + restarts_.size() * sizeof(uint32_t) + sizeof(uint32_t);
}


void BlockBuilder::Reset() {
    buffer_.clear();
    restarts_.clear();
    restarts_.push_back(0);
    counter_ = 0;
    finished_ = false;
    last_key_.clear();
}

// 将Key, Value按照SST的格式写进buffer中
void BlockBuilder::Add(const Slice& key, const Slice& value) {
    Slice last_key_slice(last_key_);
    assert(!finished_);
    assert(counter_ <= options_->block_restart_interval);
    // 下面是要保证传入的key是有序的,
    assert(buffer_.empty() || options_->comparator->Compare(key, last_key_slice) > 0);
    size_t shared = 0;
    if (counter_ < options_->block_restart_interval) {
        // 看一下相同的前缀的长度
        const size_t minlen = std::min(last_key_slice.size(), key.size());
        while (shared < minlen && last_key_slice[shared] == key[shared]) 
            shared++;
    } else {
        // 那就是重启了一个group?
        restarts_.push_back(buffer_.size());
        counter_ = 0;
    }

    const size_t no_shared = key.size() - shared;

    PutVarint32(&buffer_, shared);   
    PutVarint32(&buffer_, no_shared);
    PutVarint32(&buffer_, value.size());

    // 将具体的key value存放进去
    buffer_.append(key.data() + shared, no_shared);
    buffer_.append(value.data(), value.size());

    last_key_.resize(shared);
    last_key_.append(key.data() + shared, no_shared);

    assert(Slice(last_key_) == key);

    counter_++;
}

Footer

Footer就是 block 中最后的部分【metaIndex, index】, 最后以 魔数为结尾。

我们读取 block的时候就是从这里开始读取和解析的,其中编码和解码的处理还是很哇塞的🤩

void BlockHandle::EncodeTo(std::string *dst) const {
    PutVarint64(dst, offset_);      // 内部调用的是append
    PutVarint64(dst, size_);
}


Status BlockHandle::DecodeFrom(Slice* input) {
    if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) {
        // get之后内部会更改一下input,移动一下齐起始的位置
        return Status::OK();
    } else {
        return Status::Corruption("bad block handle");
    }
}

// 将footer写进dst中
void Footer::EncodeTo(std::string* dst) const {

    const int originsize = dst->size();
    // 1.将index[s] 放进去
    metaIndex_handle_.EncodeTo(dst);
    index_handle_.EncodeTo(dst);

    // 2.Padding
    dst->resize(2 * BlockHandle::kMaxEncodedLength);    

    // 3.MagicNumber
    PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
    PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
    assert(originsize + kEncodedLen == dst->size());
    (void)originsize;   // 清除掉Warning 
}

// 解析
Status Footer::DecodeFrom(Slice* input) {
    // 1.我们首先解析魔数
    const char* magic_ptr = input->data() + kEncodedLen - 8;      // 魔数的起始位置
    uint32_t Magic_Number_Low = DecodeFixed32(magic_ptr);
    uint32_t Magic_Number_Hig = DecodeFixed32(magic_ptr + 4);
    uint64_t Magic_Number = static_cast<uint64_t>(Magic_Number_Hig << 32) | static_cast<uint64_t>(Magic_Number_Low);    

    if (Magic_Number != kTableMagicNumber) {
        return Status::Corruption("not an sstable(bad magic numer)");
    }

    // 2.解析metahandle & indexhandle
    Status result = metaIndex_handle_.DecodeFrom(input);
    if (result.ok()) {
        result = index_handle_.DecodeFrom(input);
    }
    // 3.去除掉padding
    if (result.ok()) {
        const char* end = magic_ptr + 8;
        *input = Slice(end, input->data() + input->size() - end);
    }
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值