RocksDB源码学习(三): 读(二)

本篇博客关注 RocksDB 从 immutable memtable 中的读取,所有代码版本均为 v7.7.3

在 Rocksdb 中,memtable 和 immutable memtable 都位于内存,且它俩是一样的数据结构,唯一的区别是memtable 可读可写,而 immutable memtable 是只读的,不允许写入。写入从 writebatch 提交后,会进入 memtable,一旦一个 memtable 写满了,那么它就会转化成一个 immutable memtable,作为向 sstable 转换的过度态,然后生成一个新的空 memtable。

Rocksdb 引入了 CF 的概念,在一个 CF 中只有一个 memtable,但允许存在多个 immutable memtable。当从 memtable 中没读到时,就会尝试在这些 immutable memtable 中读。


从上一篇博客,读操作从 DBImpl::GetImpl() 开始依次从不同的部分读取,所以这里的分析如果依旧是 DBImpl::GetImpl()。截取部分代码,如下:

Status DBImpl::GetImpl(const ReadOptions& read_options, const Slice& key,
                       GetImplOptions& get_impl_options) {
  // ....
    if (get_impl_options.get_value) {
      if (sv->mem->Get(
              lkey,
              get_impl_options.value ? get_impl_options.value->GetSelf()
                                     : nullptr,
              get_impl_options.columns, timestamp, &s, &merge_context,
              &max_covering_tombstone_seq, read_options,
              false /* immutable_memtable */, get_impl_options.callback,
              get_impl_options.is_blob_index)) {
        done = true;

        if (get_impl_options.value) {
          get_impl_options.value->PinSelf();
        }

        RecordTick(stats_, MEMTABLE_HIT);
      } else if ((s.ok() || s.IsMergeInProgress()) &&
                 sv->imm->Get(lkey,
                              get_impl_options.value
                                  ? get_impl_options.value->GetSelf()
                                  : nullptr,
                              get_impl_options.columns, timestamp, &s,
                              &merge_context, &max_covering_tombstone_seq,
                              read_options, get_impl_options.callback,
                              get_impl_options.is_blob_index)) {
        done = true;

        if (get_impl_options.value) {
          get_impl_options.value->PinSelf();
        }

        RecordTick(stats_, MEMTABLE_HIT);
      }
    }
 // ...
}

代码的前半部分就是上一篇博客的入口,即 MemTable::Get()。而如果没有找到,则会调用 sv->imm->Get(),开始从 immutable memtable 中读取。实际上,这个 imm 并不是一个 immutable memtable,而是多个 immutable memtable 组成的一个链表,因为 RocksDB 中一个 CF 允许多个 immutable memetable 存在。

MemTableListVersion* imm;

类结构如下:

class MemTableListVersion {
 // ...
 private:
  // Immutable MemTables that have not yet been flushed.
  std::list<MemTable*> memlist_;
  // ...
}

可以看出来,immutable memtable 和 memtable 是一个数据结构,所以 imm 可以被看为一个由只读 memtable 组成的链表。

sv->imm->Get() 实际上调用的是 MemTableListVersion::Get(),其完整代码如下:

// Search all the memtables starting from the most recent one.
// Return the most recent value found, if any.
// Operands stores the list of merge operations to apply, so far.
bool MemTableListVersion::Get(const LookupKey& key, std::string* value,
                              PinnableWideColumns* columns,
                              std::string* timestamp, Status* s,
                              MergeContext* merge_context,
                              SequenceNumber* max_covering_tombstone_seq,
                              SequenceNumber* seq, const ReadOptions& read_opts,
                              ReadCallback* callback, bool* is_blob_index) {
  return GetFromList(&memlist_, key, value, columns, timestamp, s,
                     merge_context, max_covering_tombstone_seq, seq, read_opts,
                     callback, is_blob_index);
}

GetFromList() 的第一个参数为 memlist_,也就是 immutable memtable 组成的链表。该函数完整源码如下:

bool MemTableListVersion::GetFromList(
    std::list<MemTable*>* list, const LookupKey& key, std::string* value,
    PinnableWideColumns* columns, std::string* timestamp, Status* s,
    MergeContext* merge_context, SequenceNumber* max_covering_tombstone_seq,
    SequenceNumber* seq, const ReadOptions& read_opts, ReadCallback* callback,
    bool* is_blob_index) {
  *seq = kMaxSequenceNumber;

  for (auto& memtable : *list) {
    assert(memtable->IsFragmentedRangeTombstonesConstructed());
    SequenceNumber current_seq = kMaxSequenceNumber;

    bool done =
        memtable->Get(key, value, columns, timestamp, s, merge_context,
                      max_covering_tombstone_seq, &current_seq, read_opts,
                      true /* immutable_memtable */, callback, is_blob_index);
    if (*seq == kMaxSequenceNumber) {
      // Store the most recent sequence number of any operation on this key.
      // Since we only care about the most recent change, we only need to
      // return the first operation found when searching memtables in
      // reverse-chronological order.
      // current_seq would be equal to kMaxSequenceNumber if the value was to be
      // skipped. This allows seq to be assigned again when the next value is
      // read.
      *seq = current_seq;
    }

    if (done) {
      assert(*seq != kMaxSequenceNumber || s->IsNotFound());
      return true;
    }
    if (!done && !s->ok() && !s->IsMergeInProgress() && !s->IsNotFound()) {
      return false;
    }
  }
  return false;
}

可以看到,该函数就是遍历链表,从每一个 immutable memtable 中调用 MemTable::Get(),一旦读取成功就返回。MemTable::Get() 就是上一篇博客分析的从 memtable 中读取,因此从 immutable memtable 中读和从 memtable 中读完全一致。


至此,在内存中的读取操作已经分析完毕,下一篇博客将分析从磁盘 sstable 中的读取。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值