LevelDB源码分析-Get
Get
LevelDB提供了Get接口用于给定key的查找:
Status DBImpl::Get(const ReadOptions &options,
const Slice &key,
std::string *value)
Get操作可以指定在某个snapshot的情况下进行,如果指定了snapshot,则获取该snapshot的sequencenumber,如果没有指定snapshot,就取当前最新的sequencenumber:
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 *mem = mem_;
MemTable *imm = imm_;
Version *current = versions_->current();
mem->Ref();
if (imm != nullptr)
imm->Ref();
current->Ref();
首先在memtable里找,如果找到了就结束查找,然后再immutable memtable里找(如果immutable memtable存在),如果找到了就结束查找,在这两个地方查找使用的都是MemTable类提供的Get接口函数(在这里有分析https://www.cnblogs.com/YuNanlong/p/9426795.html)。最后使用Version类提供的Get接口函数在sstable中查找:
// Unlock while reading from files and memtables
{
mutex_.Unlock();
// First look in the memtable, then in the immutable memtable (if any).
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();
}
如果在sstable中查找了,会更新查找涉及到的sstable的seek次数,可能会触发compact条件,因此需要调用MaybeScheduleCompaction函数进行可能的compact操作(在这里有分析https://www.cnblogs.com/YuNanlong/p/9440548.html):
if (have_stat_update && current->UpdateStats(stats))
{
MaybeScheduleCompaction();
}
mem->Unref();
if (imm != nullptr)
imm->Unref();
current->Unref();
return s;
接下来分析Version类封装的Get函数:
Status Version::Get(const ReadOptions &options,
const LookupKey &k,
std::string *value,
GetStats *stats)
首先是一些变量必要的初始化:
Slice ikey = k.internal_key();
Slice user_key = k.user_key();
const Comparator *ucmp = vset_->icmp_.user_comparator();
Status s;
stats->seek_file = nullptr;
stats->seek_file_level = -1;
FileMetaData *last_file_read = nullptr;
int last_file_read_level = -1;
// We can search level-by-level since entries never hop across
// levels. Therefore we are guaranteed that if we find data
// in an smaller level, later levels are irrelevant.
std::vector<FileMetaData *> tmp;
FileMetaData *tmp2;
在每一层中搜索:
for (int level = 0; level < config::kNumLevels; level++)
{
如果该level没有文件则直接跳过:
size_t num_files = files_[level].size();
if (num_files == 0)
continue;
如果当前位于level0,将所有可能包含key的文件都加入files中:
// Get the list of files to search in this level
FileMetaData *const *files = &files_[level][0];
if (level == 0)
{
// Level-0 files may overlap each other. Find all files that
// overlap user_key and process them in order from newest to oldest.
tmp.reserve(num_files);
for (uint32_t i = 0; i < num_files; i++)
{
FileMetaData *f = files[i];
if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
ucmp->Compare(user_key, f->largest.user_key()) <= 0)
{
tmp.push_back(f);
}
}
if (tmp.empty())
continue;
std::sort(tmp.begin(), tmp.end(), NewestFirst);
files = &tmp[0];
num_files = tmp.size();
}
如果当前不是level0,则调用FindFile进行二分查找,找到file后验证要找的key是不是在file中,如果是,加入files:
else
{
// Binary search to find earliest index whose largest key >= ikey.
uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);
if (index >= num_files)
{
files = nullptr;
num_files = 0;
}
else
{
tmp2 = files[index];
if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0)
{
// All of "tmp2" is past any data for user_key
files = nullptr;
num_files = 0;
}
else
{
files = &tmp2;
num_files = 1;
}
}
}
遍历找到的files,如果seek的文件不止一个,则记录下第一个seek的文件,之后要将这个文件的seek减一(调用UpdateStats函数):
for (uint32_t i = 0; i < num_files; ++i)
{
if (last_file_read != nullptr && stats->seek_file == nullptr)
{
// We have had more than one seek for this read. Charge the 1st file.
stats->seek_file = last_file_read;
stats->seek_file_level = last_file_read_level;
}
FileMetaData *f = files[i];
last_file_read = f;
last_file_read_level = level;
调用table_cache_->Get函数在文件中搜索key值,如果没有找到,则继续搜索下一个file,如果找到了,不论是删除的还是过期的,都返回(因为之后就算找到了key,也比现在的key旧,被现在的key覆盖):
Saver saver;
saver.state = kNotFound;
saver.ucmp = ucmp;
saver.user_key = user_key;
saver.value = value;
s = vset_->table_cache_->Get(options, f->number, f->file_size,
ikey, &saver, SaveValue);
if (!s.ok())
{
return s;
}
switch (saver.state)
{
case kNotFound:
break; // Keep searching in other files
case kFound:
return s;
case kDeleted:
s = Status::NotFound(Slice()); // Use empty error message for speed
return s;
case kCorrupt:
s = Status::Corruption("corrupted key for ", user_key);
return s;
}
}
230 Love u
LevelDB源码分析-Get的更多相关文章
- leveldb源码分析--SSTable之block
在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...
- leveldb源码分析--WriteBatch
从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批 ...
- leveldb源码分析--Key结构
[注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...
- Leveldb源码分析--1
coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...
- leveldb源码分析--日志
我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析 ...
- leveldb源码分析之Slice
转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...
- LevelDB源码分析--Cache及Get查找流程
本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...
- leveldb源码分析--SSTable之TableBuilder
上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...
- leveldb源码分析之内存池Arena
转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...
- 【转】Leveldb源码分析——1
先来看看Leveldb的基本框架,几大关键组件,如图1-1所示. Leveldb是一种基于operation log的文件系统,是Log-Structured-Merge Tree的典型实现.LSM源 ...
随机推荐
- 剑指Offer 37. 数字在排序数组中出现的次数 (数组)
题目描述 统计一个数字在排序数组中出现的次数. 题目地址 https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId ...
- 关于使用JPA中@Query注解传递表名/视图名参数的问题
因碰到需要动态查询不同视图的结果,自己尝试使用@Query注解中传递视图名称参数: @Query("select * from ?1") List<Object> ge ...
- 【数据库(一)】SQL语言-表定义、查询
基本模式定义+ SQL支持许多不同的完整性约束. not null, 在该属性上不允许空值 primary key 是否是是主码,主码必须非空且唯一 foreign key check(P),P是谓词 ...
- JS 验证字符串是否为空
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue列表组件与弹窗组件示例
列表组件 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <me ...
- openstack--9--深入理解虚拟机
登录计算节点查看进程 [root@linux-node2 ~]# ps aux | grep kvm root 824 0.0 0.0 0 0 ? S< 10:19 0:00 [kvm-irqf ...
- JAVA AES CBC 加密 解密
AES 256 , KEY 的长度为 32字节(32*8=256bit). AES 128 , KEY 的长度为 16字节(16*8=128bit) CBC 模式需要IV, IV的值是固定写死,还是当 ...
- Azure VMSS (2) 对VM执行Generalize操作
<Windows Azure Platform 系列文章目录> 在本章中,笔者将介绍如何创建Azure Template镜像模板. 1.首先,我们先创建1台Windows Server 2 ...
- Java8-dateTimeFormatter
时间格式化LocalDate,DateTimeFormatter--->parse,ofParttern 伴随lambda表达式.streams以及一系列小优化,Java 8 推出了全新的日期时 ...
- java基础-反射(细节)
java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...