大白话解析LevelDB 4: 查找一个 Key

本文详细描述了LevelDB中查询Key的过程,包括MemTable、ImmutableMemTable(实际上是MemTable的别名)和SST的查找机制,以及SST文件的无效查找处理和Compaction策略。
摘要由CSDN通过智能技术生成

查询一个 Key

查找 Key 的入口: DBImpl::Get(const ReadOptions& options, const Slice& key, std::string* value)

LevelDB 中查询一个Key的接口为Status DBImpl::Get(const ReadOptions& options, const Slice& key, std::string* value);,其实现如下。

Status DBImpl::Get(const ReadOptions& options, const Slice& key, std::string* value) {
    Status s;
    MutexLock l(&mutex_);

    // 如果 options 中指定了 Snapshot,就使用该 Snapshot。
    // 否则的话,隐式的创建一个最新的 Snapshot,从该 Snapshot 
    // 中查询 Key。
    SequenceNumber snapshot;
    if (options.snapshot != nullptr) {
        snapshot = static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();
    } else {
        snapshot = versions_->LastSequence();
    }

    // Key 可能存在 3 个地方:
    //   - MemTable
    //   - Immutable MemTable
    //   - SST
    // 这 3 个地方都需要查,先把它们的引用计数加 1,防止中途被销毁。
    MemTable* mem = mem_;
    MemTable* imm = imm_;
    Version* current = versions_->current();
    mem->Ref();
    if (imm != nullptr) imm->Ref();
    current->Ref();

    bool have_stat_update = false;
    Version::GetStats stats;

    {
        // 进入查询流程了,对 Memtable, Immutable Memtable 和 SST 只会做读取操作,
        // 不会做写操作,所以可以先释放锁,允许其他线程继续写入。
        mutex_.Unlock();
        
        // 基于 UserKey 和 Snapshot 构造一个 LookupKey,使用该 LookupKey 来做查询。
        LookupKey lkey(key, snapshot);
        if (mem->Get(lkey, value, &s)) {
            // 优先在 MemTable 中查找,如果查找成功,就不会在 Immutable MemTable 和 SST 中查找了。
        } else if (imm != nullptr && imm->Get(lkey, value, &s)) {
            // MemTable 中没找到,就在 Immutable MemTable 中查找。
        } else {
            // MemTable 和 Immutable MemTable 都没找到,就在 SST 中查找。
            // 把 have_stat_update 标记为 true,表示在 SST 中进行查找了。
            // 在 SST 中查找完后,会将查找的额外信息存放到 stats 中:
            //   - 读取了哪个 SST
            //   - 读取到 SST 位于哪一层
            s = current->Get(options, lkey, value, &stats);
            have_stat_update = true;
        }
        mutex_.Lock();
    }

    // 如果是从 SST 中查找的 Key,并且该 SST 的累计无效查找次数达到了阈值,
    // 那么就将该 SST 标记为待 Compaction,并尝试触发一轮 Compaction。
    if (have_stat_update && current->UpdateStats(stats)) {
        MaybeScheduleCompaction();
    }

    // 查找完毕,将 MemTable, Immutable MemTable 和 SST 的引用计数减 1。
    mem->Unref();
    if (imm != nullptr) imm->Unref();
    current->Unref();
    return s;
}

查询一个Key的流程如下:

从 MemTable 中查找

使用MemTable::Get(const LookupKey& key, std::string* value, Status* s)优先在MemTable中查找,如果查找成功,就不会在Immutable MemTableSST中查找了。

MemTable::Get(const LookupKey& key, std::string* value, Status* s)的具体实现可移步参考大白话解析LevelDB:MemTable

从 Immutable MemTable 中查找

Immutable Table其实就是MemTable,只是为了与MemTable做区分,把名称叫做Immutable MemTable,但代码实现中,Immutable MemTableMemTable都是Class MemTable

MemTable* mem = mem_;
MemTable* imm = imm_;

所以,Immutable MemTable的查找实现与MemTable的查找实现是同一个接口,不再赘述啦。

从 SST 中查找

如果前面在MemTableImmutable MemTable中都没找到目标 Key,就只能从SST中查找了。

每个SST文件都有个MetaData,记录了该SST文件的一些元信息,比如该SST文件的最小Key、最大Key、该SST文件的序列号等等。

当我们需要查找一个特定的Key时,会先构造一个列表,通过读取SST的元信息,将可能包含这个KeySST放入列表中,再逐个查找目标Key

当我们对某个SST文件进行查找后,没有找到目标Key,就会把该SSTallowed_seeks减一。当allowed_seeks减到 0 时,就会将该SST标记为待Compaction

SST中查找指定Key的函数为Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, GetStats* stats),具体实现可移步参考大白话解析LevelDB: Version

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值