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源 ...
随机推荐
- activity select problem(greedy algorithms)
many activities will use the same place, every activity ai has its' start time si and finish time f ...
- Django-----加入MD5格式上传图片
上传图片为什么要加 MD5 ? 答 :避免用户上传图片的时候图片名重复,而引起先上传的图片被后上传的图片所覆盖的失误! MD5是什么? 答:一种被广泛使用的密码散列函数,可以产生出一个128位(16字 ...
- 01bootstrap_基本结构和布局
01bootstrap_基本结构 学习bootstrap需要下载必要的文件:www.bootcss.com 基本结构 container page-header 布局 1.响应式布局:containe ...
- Self-Introduce
My name is Leo.I like listening music, especially English song.What's more, I enjoy playing games, l ...
- 学习笔记TF015:加载图像、图像格式、图像操作、颜色
TensorFlow支持JPG.PNG图像格式,RGB.RGBA颜色空间.图像用与图像尺寸相同(height*width*chnanel)张量表示.通道表示为包含每个通道颜色数量标量秩1张量.图像所有 ...
- rabbitmq management advance lesson
rabbitmq management advance management install rabbitmq-plugins enable rabbitmq_management visit : h ...
- How to create an rpm package
转自:https://linuxconfig.org/how-to-create-an-rpm-package Rpm is both the package manager and the pack ...
- Docker进入容器后使用ifconfig等命令“command not found”解决办法
当进入一个容器后,使用ifconfig.ip addr等命令时,出现如下“command not found”: 解决办法: yum update yum -y install n ...
- golang web framework--Martini
Martini是一个功能强大的软件包,用于在Golang中快速编写模块化Web应用程序/服务. 下载 $ go get github.com/go-martini/martini Demo serve ...
- Spring Cloud(Dalston.SR5)--Zuul 网关-过滤器
Spring Cloud 为 HTTP 请求的各个阶段提供了多个过滤器,这些过滤器的执行顺序由各自提供的一个 int 值决定,提供的值越小则优先级越高,默认的过滤器及优先级如下: 自定义过滤器 在默认 ...