leveldb当中所有kv都有一个版本号,通过版本号来实现快照功能,可以进行并发的读写操作。
Status DBImpl::Get(const ReadOptions& options, const Slice& key,
std::string* value) {
Status s;
MutexLock l(&mutex_);
// 指定了快照那么就使用指定快照的版本号,没有指定则使用最新的版本号
SequenceNumber snapshot;
if (options.snapshot != nullptr) {
snapshot =
static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();
} else {
snapshot = versions_->LastSequence();
}
// 引用mem_, imm_,当前版本current,避免读取过程中内存被释放
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;
// Unlock while reading from files and memtables
// 读取文件过程中不需要加锁,因为不涉及文件的修改
{
mutex_.Unlock();
// First look in the memtable, then in the immutable memtable (if any).
// 现在memtable中找,然后在immutable memtable中找
LookupKey lkey(key, snapshot);
if (mem->Get(lkey, value, &s)) {
// Done
} else if (imm != nullptr && imm->Get(lkey, value, &s)) {
// Done
} else {
// 到文件中找
s = current->Get(options, lkey, value, &stats);
have_stat_update = true;
}
mutex_.Lock();
}
if (have_stat_update && current->UpdateStats(stats)) {
MaybeScheduleCompaction();
}
mem->Unref();
if (imm != nullptr) imm->Unref();
current->Unref();
return s;
}查找的流程就是memtable → immutable memtable → table文件集。
将k组装成memtable中entry里key的形式,然后可以进行比较判断key是否存在。前面两者都没有找到,那么就会版本对应的文件当中查找对应的key。