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源 ...
随机推荐
- laravel 创建自动化生成数据库
1. 生成 迁移脚本 php artisan make:migration create_users_table --create=users(表名) 当你⽣成⼀个模型时想要顺便⽣成⼀个 数据库迁 ...
- lua经典问题
lua是一门比较简单的脚本语言,但是有些问题经常碰到,在这里总结一下: 1 lua 传参,如果参数是table,则相当于传引用 2 lua中只有nil和false返回假 3 lua and 和 or ...
- Python全栈之路----函数----高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一函数作为参数,这种函数就称之为高阶函数. 只需满足以下任意一个条件,即是高阶函数: 接收一个或多个函数作为输入 def func(x, ...
- 几种数据格式的处理 - Python
1. CSV数据 import csv csvfile = open('data_text.csv','rb') reader = csv.reader(csvfile) # 返回数据为列表类型 # ...
- 2018.4.26 lvm
lvm(Logical Volume Manager)逻辑卷管理,是Linux环境下对磁盘分区进行管理的一种机制. 基本概念: 1. 物理卷-----PV(Physical Volume)物理卷在逻辑 ...
- Spark:读取mysql数据作为DataFrame
在日常工作中,有时候需要读取mysql的数据作为DataFrame数据源进行后期的Spark处理,Spark自带了一些方法供我们使用,读取mysql我们可以直接使用表的结构信息,而不需要自己再去定义每 ...
- Python的深copy和浅copy
浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象. 浅copy: a = [1, 2, ...
- 第二章 C#语法基础(2.1C#语言的数据类型二)
数据类型案例说明 一.数据类型与变量(计算整数10与20的和) namespace ConsoleApp1 { class Program { static void Main(string[] ar ...
- 串口接收端verilog代码分析
串口接收端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...
- MySQL查询不使用索引汇总 + 如何优化sql语句
不使用索引原文 : http://itlab.idcquan.com/linux/MYSQL/918330.html MySQL查询不使用索引汇总 众所周知,增加索引是提高查询速度的有效途径,但是很多 ...