RocksDB笔记 - Compaction中的Iterator
Compaction中的Iterator
一般来说,Compaction的Input涉及两层数据的合并,对于涉及到的每一层数据:
如果是level-0,对level-0的每一个sstable文件建立一个Iterator, 因为Level-0的sstable之间存在Overlap。
如果不是level-0,对该 level 的所有sstable文件建立一个TwoLevelIterator。
对于这个TwoLevelIterator:
first_level_iter_ : 表示该层所涉及到Compaction 的 file 元信息组成的 LevelFileNumIterator
second_level_iter_ : 表示当前所使用的数据 Block 构成的 Iterator
它们的组合将这一层所有sstable 的数据连接起来,构成了一个整体的 Iterator
这样,对于Compaction所用到的所有sstable文件,都建立了与之相关联的Iterator。最后将建立的所有Iterator合并,构成一个整体性的MergeIterator
以上为VersionSet::MakeInputIterator的操作过程
LevelFileNumIterator
LevelFileNumIterator的内容为该层所有文件的元信息:LevelFilesBrief,以下是 LevelFileNumIterator 中两个主要的函数实现:
Slice key() const override
{
assert(Valid());
return flevel_->files[index_].largest_key;
}
Slice value() const override
{
assert(Valid());
auto file_meta = flevel_->files[index_];
current_value_ = file_meta.fd;
return Slice(reinterpret_cast<const char*>(¤t_value_), sizeof(FileDescriptor));
}
key() : 表示的是当前index的sstable的largest_key
value() : 表示的是是个由当前sstable文件的FileDescriptor信息,即包含其file number 和 file size
TwoLevelIterator
TwoLevelIterator为一个两层结构的迭代器,其类成员包括两个IteratorWrapper:
IteratorWrapper first_level_iter_;
IteratorWrapper second_level_iter_;
上述的 LevelFileNumIterator 即为此处的 first_level_iter,当 TwoLevelIterator 初始化时,它会调用自身的 InitDataBlock() 函数:
void TwoLevelIterator::InitDataBlock()
{
if (!first_level_iter_.Valid())
{
SetSecondLevelIterator(nullptr);
}
else
{
Slice handle = first_level_iter_.value();
if (second_level_iter_.iter() != nullptr
&& !second_level_iter_.status().IsIncomplete()
&& handle.compare(data_block_handle_) == )
{
// second_level_iter is already constructed with this iterator, so
// no need to change anything
}
else
{
InternalIterator* iter = state_->NewSecondaryIterator(handle);
data_block_handle_.assign(handle.data(), handle.size());
SetSecondLevelIterator(iter);
}
}
InitDataBlock() 根据自身的 state 和 first_level_iter_.value(),构建第二层Iterator。
在Compaction过程中
InternalIterator* iter = state_->NewSecondaryIterator(handle);
实际调用的为:
InternalIterator* NewSecondaryIterator(const Slice& meta_handle) override
{
if (meta_handle.size() != sizeof(FileDescriptor))
{
return NewErrorInternalIterator(
Status::Corruption("FileReader invoked with unexpected value"));
}
const FileDescriptor* fd = reinterpret_cast<const FileDescriptor*>(meta_handle.data());
return table_cache_->NewIterator(read_options_, env_options_, icomparator_, *fd, range_del_agg_,
nullptr /* don't need reference to table */, file_read_hist_,
for_compaction_, nullptr /* arena */, skip_filters_, level_);
}
可以看出,实际调用的仍然为 TableCache::NewIterator(),根据某个sstable文件创建 InternalIterator
整体上来看,这个TwoLevelIterator内容为这一层的所有文件数据,
第一层Iterator:表示这一层所有文件的元信息
第二层Iterator:表示当前文件的数据信息
以下是TwoLevelIterator的Key-Value成员函数的代码,可以看出,它的Key-Value即表示当前sstable Iterator的当前Key-Value:
virtual Slice key() const override
{
assert(Valid());
return second_level_iter_.key();
}
virtual Slice value() const override
{
assert(Valid());
return second_level_iter_.value();
}
Next() 操作定位下一个Key-Value,如果当前Block已结束,second_level_iter_移动到下一个Block
void TwoLevelIterator::Next()
{
assert(Valid());
second_level_iter_.Next();
SkipEmptyDataBlocksForward();
}
void TwoLevelIterator::SkipEmptyDataBlocksForward()
{
while (second_level_iter_.iter() == nullptr
|| (!second_level_iter_.Valid() && !second_level_iter_.status().IsIncomplete()))
{
// Move to next block
if (!first_level_iter_.Valid())
{
SetSecondLevelIterator(nullptr);
return;
}
first_level_iter_.Next();
InitDataBlock();
if (second_level_iter_.iter() != nullptr)
{
second_level_iter_.SeekToFirst();
}
}
}
MergingIterator
MergingIterator 关键的成员变量如下:
const Comparator* comparator_; IteratorWrapper* current_; autovector<IteratorWrapper, kNumIterReserve> children_; MergerMinIterHeap minHeap_; std::unique_ptr<MergerMaxIterHeap> maxHeap_;
从结构上来说,一个MergingIterator由一多个children_组成,每一个child也是一个Iterator,所有的子迭代器通过堆的数据结构组织,包括一个最小堆和一个最大堆。
最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左孩子和右孩子节点的值 ——摘自百度百科
MergingIterator的Key和Value成员函数均返回的是当前子迭代器 current_ 的Key与Value:
virtual Slice key() const override
{
assert(Valid());
return current_->key();
}
virtual Slice value() const override
{
assert(Valid());
return current_->value();
}
current_ 默认为堆顶的child,即表示数值最小的child。在Compaction过程中,这些children表示的是某一个sstable(level-0层)或者某一层sstable数据。
对于MergingIterator的迭代过程,以下是Next() 成员函数的部分节选:
virtual void Next() override
{
current_->Next();
if (current_->Valid())
{
minHeap_.replace_top(current_);
}
else
{
minHeap_.pop();
}
current_ = CurrentForward();
}
MergingIterator的Next一般来说表示的就是current_的Next,但是当current_迭代结束之后,就会取下一个child作为current。
从Compaction的角度来说,也就是MergingIterator的Next操作也就是涉及到所有sstable数据中,Key从小到大顺序遍历的过程(direction=kForward)
RocksDB笔记 - Compaction中的Iterator的更多相关文章
- STL中实现 iterator trail 的编程技巧
STL中实现 iterator trail 的编程技巧 <泛型编程和 STL>笔记及思考. 这篇文章主要记录在 STL 中迭代器设计过程中出现的编程技巧,围绕的 STL 主题为 (迭代器特 ...
- 如何在遍历中使用 iterator/reverse_iterator 删除元素
如何在遍历中使用 iterator/reverse_iterator 删除元素 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公 ...
- Android笔记——Android中数据的存储方式(二)
我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的使用方法
在遍历中使用 iterator/reverse_iterator 进行 Erase 的使用方法 罗朝辉 (http://blog.csdn.net/kesalin/) 本文遵循"署名-非商业 ...
- [ios-必看] WWDC 2013 Session笔记 - iOS7中的多任务【转】
感谢:http://onevcat.com/2013/08/ios7-background-multitask/ http://www.objc.io/issue-5/multitasking.htm ...
- [.NET] 《Effective C#》快速笔记 - C# 中的动态编程
<Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...
- 涂抹mysql笔记-数据库中的权限体系
涂抹mysql笔记-数据库中的权限体系<>能不能连接,主机名是否匹配.登陆使用的用户名和密码是否正确.mysql验证用户需要检查3项值:用户名.密码和主机来源(user.password. ...
- 关于ArrayList中的iterator返回的事迭代器实例问题。
Arraylist是一个具体的类,它并没有定义它自己的iterator()方法,,它只是从AbstractList 这个抽象类中继承了iterator()这个方法,而AbstractList 中的it ...
- ArcGIS案例学习笔记-点集中最近点对和最远点对
ArcGIS案例学习笔记-点集中最近点对和最远点对 联系方式:谢老师,135-4855-4328,xiexiaokui@qq.com 目的:对于点图层,查找最近的点对和最远的点对 数据: 方法: 1. ...
随机推荐
- Android菜鸟成长记15 -- BitMap
BitMap简介 Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图像剪切.旋转.缩放等操作,并可以指定格式保存图像文件.本文从应用的角度,着重介绍怎么用Bi ...
- IE6 7下常见CSS兼容性处理
以下是一些比较常见的IE6 7下的兼容性问题. 在当下这个时代,其实我们几乎可以不用再去针对IE6做兼容性的处理,除非你的公司还是诡异的要求你兼容到IE6.但是了解一些常见的兼容性问题还是可以帮助我们 ...
- (转载)IE6支持透明PNG图片解决方案:DD_belatedPNG.js
DD_belatedPNG.js 是一个能是IE6支持p显示ng透明图片,而且还支持背景循环(background-repeat)和定位(backgrond-position) ,支持focus,Ho ...
- 【Python全栈笔记】05 [模块二] 19 Oct 文件的操作
文件操作 一般步骤1. 文件打开 2. 文件操作 3. 文件关闭 1. 打开文件 使用open(文件名(绝对路径), 打开模式, 编码) 文件打开的模式有: r: 只读模式(默认) w: 只写模式 ...
- 安装Linux系统Fedora 23
搭建了一个Linux(Fedora 23)环境,用于学习.实验. [TOC] 1 安装Fedora 以前一直只会光盘安装,刻录了好多个版本的distros,用完即弃在一旁.很浪费. 此次学会了在Lin ...
- hdu 3579 Hello Kiki (中国剩余定理)
Hello Kiki Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- (转)java中静态代码块的用法 static用法详解
一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来 ...
- 【转】 教大家防止Jar包被反编译
http://blog.csdn.net/zhengjingle/article/details/50833746 在需要放置编译的java类中加一个无用的class,然后再把class的名字修改了, ...
- sublime text3的安装与汉化
sublime text3 3126 64位的下载地址: https://download.sublimetext.com/Sublime%20Text%20Build%203126%20x64%20 ...
- 使用merge同时执行insert和update操作
SQL点滴18—SqlServer中的merge操作,相当地风骚 今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在tech ...