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源 ...
随机推荐
- 在myeclipse中maven项目关于ssh整合时通过pom.xml导入依赖是pom.xml头部会报错
错误如下 ArtifactTransferException: Failure to transfer org.springframework:spring-jdbc:jar:3.0.5.RELEAS ...
- Python 进程池的同步方法
import time from multiprocessing import Process,Pool def f1(n): time.sleep(1) #print(n) return n*n i ...
- Python学习二十八周(vue.js)
一.指令 1.一个例子简单实用vue: 下载vue.js(这里实用1.0.21版本) 编写html代码: <!DOCTYPE html> <html lang="en&qu ...
- input[type='file']默认样式
<input type="file" name="" id="" value="" /> 当input的ty ...
- oracle-企业信息化
http://www.itpub.net/thread-1873735-1-1.html OCP考试心得 http://blog.csdn.net/rlhua/article/detai ...
- axiso实战问题
this.axios({ method: 'get', url: '/api/projectmgt/project/Project/list', withCredentials : true, hea ...
- 使用phpAnalysis打造PHP应用非侵入式性能分析器
使用phpAnalysis打造PHP应用非侵入式性能分析器,查找PHP性能瓶颈. 什么是phpAnalysis phpAnalysis是一款轻量级非侵入式PHP应用性能分析器,适用于开发.测试及生产环 ...
- NTP搭建
NTP(Network Time Protocol,网络时间协议),用于同步它所有客户端时钟的服务.NTP服务器将本地系统的时钟与一个公共的NTP服务器同步然后作为时间主机提供服务,使本地网络的所有客 ...
- mysql 插入更新判断 ON DUPLICATE KEY UPDATE 和 REPLACE INTO
平时我们在设计数据库表的时候总会设计 unique 或者 给表加上 primary key 的限制条件.此时 插入数据的时候 ,经常会有这样的情况:我们想向数据库插入一条记录: 若数据表中存在以相同主 ...
- 2017-07-06 eclipse在线安装SVN1.9插件
1,百度搜索subeclipse,点击第一个: 2,官网说,文档已移动到github wiki上: 3,打开github wiki,复制最新发布版本地址: 4,在eclipse里面,打开help-&g ...