文章目录
查询一个 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 MemTable
和SST
中查找了。
MemTable::Get(const LookupKey& key, std::string* value, Status* s)
的具体实现可移步参考大白话解析LevelDB:MemTable。
从 Immutable MemTable 中查找
Immutable Table
其实就是MemTable
,只是为了与MemTable
做区分,把名称叫做Immutable MemTable
,但代码实现中,Immutable MemTable
与MemTable
都是Class MemTable
。
MemTable* mem = mem_;
MemTable* imm = imm_;
所以,Immutable MemTable
的查找实现与MemTable
的查找实现是同一个接口,不再赘述啦。
从 SST 中查找
如果前面在MemTable
和Immutable MemTable
中都没找到目标 Key,就只能从SST
中查找了。
每个SST
文件都有个MetaData
,记录了该SST
文件的一些元信息,比如该SST
文件的最小Key
、最大Key
、该SST
文件的序列号等等。
当我们需要查找一个特定的Key
时,会先构造一个列表,通过读取SST
的元信息,将可能包含这个Key
的SST
放入列表中,再逐个查找目标Key
。
当我们对某个SST
文件进行查找后,没有找到目标Key
,就会把该SST
的allowed_seeks
减一。当allowed_seeks
减到 0 时,就会将该SST
标记为待Compaction
。
从SST
中查找指定Key
的函数为Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, GetStats* stats)
,具体实现可移步参考大白话解析LevelDB: Version。