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 中两个主要的函数实现:

  1. Slice key() const override
  2. {
  3. assert(Valid());
  4. return flevel_->files[index_].largest_key;
  5. }
  6. Slice value() const override
  7. {
  8. assert(Valid());
  9. auto file_meta = flevel_->files[index_];
  10. current_value_ = file_meta.fd;
  11. return Slice(reinterpret_cast<const char*>(¤t_value_), sizeof(FileDescriptor));
  12. }

key()     :  表示的是当前index的sstable的largest_key

value()  :  表示的是是个由当前sstable文件的FileDescriptor信息,即包含其file number 和 file size


TwoLevelIterator

TwoLevelIterator为一个两层结构的迭代器,其类成员包括两个IteratorWrapper:

  1. IteratorWrapper first_level_iter_;
  2. IteratorWrapper second_level_iter_;​

上述的 LevelFileNumIterator 即为此处的 first_level_iter,当 TwoLevelIterator 初始化时,它会调用自身的 InitDataBlock() 函数:

  1. void TwoLevelIterator::InitDataBlock()
  2. {
  3. if (!first_level_iter_.Valid())
  4. {
  5. SetSecondLevelIterator(nullptr);
  6. }
  7. else
  8. {
  9. Slice handle = first_level_iter_.value();
  10. if (second_level_iter_.iter() != nullptr
  11. && !second_level_iter_.status().IsIncomplete()
  12. && handle.compare(data_block_handle_) == )
  13. {
  14. // second_level_iter is already constructed with this iterator, so
  15. // no need to change anything
  16. }
  17. else
  18. {
  19. InternalIterator* iter = state_->NewSecondaryIterator(handle);
  20. data_block_handle_.assign(handle.data(), handle.size());
  21. SetSecondLevelIterator(iter);
  22. }
  23. }

InitDataBlock() 根据自身的 state 和 first_level_iter_.value(),构建第二层Iterator。

在Compaction过程中

  1. InternalIterator* iter = state_->NewSecondaryIterator(handle);

实际调用的为:

  1. InternalIterator* NewSecondaryIterator(const Slice& meta_handle) override
  2. {
  3. if (meta_handle.size() != sizeof(FileDescriptor))
  4. {
  5. return NewErrorInternalIterator(
  6. Status::Corruption("FileReader invoked with unexpected value"));
  7. }
  8. const FileDescriptor* fd = reinterpret_cast<const FileDescriptor*>(meta_handle.data());
  9. return table_cache_->NewIterator(read_options_, env_options_, icomparator_, *fd, range_del_agg_,
  10. nullptr /* don't need reference to table */, file_read_hist_,
  11. for_compaction_, nullptr /* arena */, skip_filters_, level_);
  12. }

可以看出,实际调用的仍然为 TableCache::NewIterator(),根据某个sstable文件创建 InternalIterator

整体上来看,这个TwoLevelIterator内容为这一层的所有文件数据,

第一层Iterator:表示这一层所有文件的元信息

第二层Iterator:表示当前文件的数据信息

以下是TwoLevelIterator的Key-Value成员函数的代码,可以看出,它的Key-Value即表示当前sstable Iterator的当前Key-Value:

  1. virtual Slice key() const override
  2. {
  3. assert(Valid());
  4. return second_level_iter_.key();
  5. }
  6. virtual Slice value() const override
  7. {
  8. assert(Valid());
  9. return second_level_iter_.value();
  10. }​

Next() 操作定位下一个Key-Value,如果当前Block已结束,second_level_iter_移动到下一个Block

  1. void TwoLevelIterator::Next()
  2. {
  3. assert(Valid());
  4. second_level_iter_.Next();
  5. SkipEmptyDataBlocksForward();
  6. }​
  7. void TwoLevelIterator::SkipEmptyDataBlocksForward()
  8. {
  9. while (second_level_iter_.iter() == nullptr
  10. || (!second_level_iter_.Valid() && !second_level_iter_.status().IsIncomplete()))
  11. {
  12. // Move to next block
  13. if (!first_level_iter_.Valid())
  14. {
  15. SetSecondLevelIterator(nullptr);
  16. return;
  17. }
  18. first_level_iter_.Next();
  19. InitDataBlock();
  20. if (second_level_iter_.iter() != nullptr)
  21. {
  22. second_level_iter_.SeekToFirst();
  23. }
  24. }
  25. }

MergingIterator

MergingIterator 关键的成员变量如下:

  1. const Comparator* comparator_;
  2.  
  3. IteratorWrapper* current_;
  4.  
  5. autovector<IteratorWrapper, kNumIterReserve> children_;
  6.  
  7. MergerMinIterHeap minHeap_;
  8.  
  9. std::unique_ptr<MergerMaxIterHeap> maxHeap_;

从结构上来说,一个MergingIterator由一多个children_组成,每一个child也是一个Iterator,所有的子迭代器通过堆的数据结构组织,包括一个最小堆和一个最大堆。

最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左孩子和右孩子节点的值        ——摘自百度百科

MergingIterator的Key和Value成员函数均返回的是当前子迭代器 current_ 的Key与Value:

  1. virtual Slice key() const override
  2. {
  3. assert(Valid());
  4. return current_->key();
  5. }
  6. virtual Slice value() const override
  7. {
  8. assert(Valid());
  9. return current_->value();
  10. }​

current_ 默认为堆顶的child,即表示数值最小的child。在Compaction过程中,这些children表示的是某一个sstable(level-0层)或者某一层sstable数据。

对于MergingIterator的迭代过程,以下是Next() 成员函数的部分节选:

  1. virtual void Next() override
  2. {
  3. current_->Next();
  4. if (current_->Valid())
  5. {
  6. minHeap_.replace_top(current_);
  7. }
  8. else
  9. {
  10. minHeap_.pop();
  11. }
  12. current_ = CurrentForward();
  13. }​

MergingIterator的Next一般来说表示的就是current_的Next,但是当current_迭代结束之后,就会取下一个child作为current。

从Compaction的角度来说,也就是MergingIterator的Next操作也就是涉及到所有sstable数据中,Key从小到大顺序遍历的过程(direction=kForward)

RocksDB笔记 - Compaction中的Iterator的更多相关文章

  1. STL中实现 iterator trail 的编程技巧

    STL中实现 iterator trail 的编程技巧 <泛型编程和 STL>笔记及思考. 这篇文章主要记录在 STL 中迭代器设计过程中出现的编程技巧,围绕的 STL 主题为 (迭代器特 ...

  2. 如何在遍历中使用 iterator/reverse_iterator 删除元素

    如何在遍历中使用 iterator/reverse_iterator 删除元素 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公 ...

  3. Android笔记——Android中数据的存储方式(二)

    我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...

  4. 在遍历中使用 iterator/reverse_iterator 进行 Erase 的使用方法

    在遍历中使用 iterator/reverse_iterator 进行 Erase 的使用方法 罗朝辉 (http://blog.csdn.net/kesalin/) 本文遵循"署名-非商业 ...

  5. [ios-必看] WWDC 2013 Session笔记 - iOS7中的多任务【转】

    感谢:http://onevcat.com/2013/08/ios7-background-multitask/ http://www.objc.io/issue-5/multitasking.htm ...

  6. [.NET] 《Effective C#》快速笔记 - C# 中的动态编程

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  7. 涂抹mysql笔记-数据库中的权限体系

    涂抹mysql笔记-数据库中的权限体系<>能不能连接,主机名是否匹配.登陆使用的用户名和密码是否正确.mysql验证用户需要检查3项值:用户名.密码和主机来源(user.password. ...

  8. 关于ArrayList中的iterator返回的事迭代器实例问题。

    Arraylist是一个具体的类,它并没有定义它自己的iterator()方法,,它只是从AbstractList 这个抽象类中继承了iterator()这个方法,而AbstractList 中的it ...

  9. ArcGIS案例学习笔记-点集中最近点对和最远点对

    ArcGIS案例学习笔记-点集中最近点对和最远点对 联系方式:谢老师,135-4855-4328,xiexiaokui@qq.com 目的:对于点图层,查找最近的点对和最远的点对 数据: 方法: 1. ...

随机推荐

  1. mvc、三次握手

    1.所谓MVC便是: ① View:(查看,观察)就只处理View的事情,其它神马都不要管 ② 数据由Model处理,并且为View提供渲染需要的数据 ③ 由于后端可能抽风可能将name变成Name坑 ...

  2. Linux内核开机保留大块内存的方法

    http://www.linuxidc.com/Linux/2014-03/97952.htm

  3. [转]Direct3D 11 Tessellation Tutorial

    The new hardware tessellation feature available on Direct3D 11 video cards has great potential, but ...

  4. 各种Java序列化性能比较

    转载:http://www.jdon.com/concurrent/serialization.html 这里比较Java对象序列化 XML JSON  Kryo  POF等序列化性能比较. 很多人以 ...

  5. JavaScript 学习小结

    简要的功能点: 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编程代码. JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行. 操作 HTML 元素 d ...

  6. centos7 安装lamp

    1升级gcc4.8以上  yum update gcc2升级openssl     yum update openssl 3安装apache a 安装apr   ./configure --prefi ...

  7. <?xml version="1.0" encoding="UTF-8"?> 的作用?

    version="1.0" 声明用的xml版本是1.0 encoding="UTF-8" 声明用xml传输数据的时候的字符编码,假如文档里面有中文,编码方式不是 ...

  8. 转:C# WinForm获取 当前执行程序路径的几种方法

    1.获取和设置当前目录的完全限定路径. string str = System.Environment.CurrentDirectory; Result: C:xxxxxx 2.获取启动了应用程序的可 ...

  9. <button> 标签 id 与 function 重复时发生的问题

    今天遇到一种情况,在调用js自定义方法的时候,总是提示“import:660 Uncaught TypeError: ... is not a function”. 仔细检查了代码,并没有问题.甚至把 ...

  10. iOS 自定义图片和文字垂直显示按钮<上面是图片,文字显示下面>

    #import <UIKit/UIKit.h> @interface VerticalButton : UIButton @end #import "VerticalButton ...