回想一下LSM数据存储的机制:
1. 热数据保存在内存中MemTable中;
2. 受限于内存存储空间大小的限制,当热数据超过一定大小时,需刷写到磁盘文件中;为了避免刷新过程中与写入操作的互斥锁操作,引入Immutable MemTable来保存待刷盘的、且不可修改的内存热数据;
3. 数据刷写到磁盘中,保存到SSTable文件中;
从数据存储的机制中,我们可以推演出数据读取的流程:
1. 从内存中的MemTable中查找数据,如查找成功则立即返回,如查找不到则到下一层中去查找数据;
- MemTable底层采用skiplist数据结构保存,其查找过程就是skiplist的数据查找过程;
- skiplist中只有一个key值,故需把用户的kv编码成一个interval key保存;
2. 从内存中的Immutable MemTable中查找数据;
3. 从level0层中SSTable文件中查找数据;
- level0中SSTable文件保存的数据范围存在重叠,故查找过程中,如新修改的SSTable文件中找不到数据,需查询这一层所有的SSTable文件;
4. 从levelN层中SSTable文件中查找数据;
- 先二分查找法,查找到可能包含此key值的SSTable文件;
- 从SSTable文件中查找特定key值;
SSTable文件中查找数据过程:
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();
}
// 增加MemTable和Version的引用计数,防止使用过程中数据被释放回收
MemTable* mem = mem_;
MemTable* imm = imm_;
Version* current = versions_->current();
mem->Ref();
if (imm != nullptr) imm->Ref();
current->Ref();
// Unlock while reading from files and memtables
{
mutex_.Unlock();
// 从MemTable中查找数据
LookupKey lkey(key, snapshot);
if (mem->Get(lkey, value, &s)) {
// Done
// 从ImmemTable中查找数据
} else if (imm != nullptr && imm->Get(lkey, value, &s)) {
// Done
} else {
// 从SSTable文件中查找数据
s = current->Get(options, lkey, value, &stats);
}
mutex_.Lock();
}
mem->Unref();
if (imm != nullptr) imm->Unref();
current->Unref();
return s;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。