[RocksDB剖析系列] Iterator

1iin

参考:

Introduction

RocksDB的Iterator在经过高度封装后,可以像C++ stl库为每一个容器构造的迭代器的iterator一样被使用,它可以定位到某个key,并可以从这个key开始进行scan,它也可以被用来进行反向scan。

如果在创建迭代器时,ReadOptions.snapshot被给定,迭代器将返回该snapshot的数据,如果传入的为nullptr,隐性视图将被创建,隐性视图不能转为显性。

用户对Iterator的使用

  • NewIterator 创建一个迭代器,需要传入ReadOptions
  • Seek 查找一个key
  • SeekToFirst 迭代器移动到db的第一个key位置,一般用于顺序遍历整个db的所有key
  • SeekToLast 迭代器移动到db的最后一个key位置, 一般用于反向遍历整个db的所有key
  • SeekForPrev移动到当前key的上一个位置,一般用于遍历(limit, start]之间的key
  • Next 迭代器移动到下一个key
  • Prev迭代器移动到上一个key

Iterator::status()可以返回当前迭代器的error。error包含IO error,checksum不匹配,内部错误等...

如果没有错误,状态为Status::OK()。如果Iterator::Valid()是true,status肯定为OK。
而如果Iterator::Valid()为false,可能是因为此时迭代器走到了数据的末尾,这种情况status是OK;也有可能是出现了错误,这种情况status不是OK。

5.13.x或更早的版本中,这两个API会有不同,需要再查阅文档。

各Iterator

截屏2022-01-24 下午8.28.29.png

DBIter

Implementation: db/db_iter.cc
Interface: Iterator

DBIter是对InternalIterator的封装,它的工作主要是将Internal key解析成user key,并展示出来

Example

底层的InternalIterator中

InternalKey(user_key="Key1", seqno=10, Type=Put)    | Value = "KEY1_VAL2"
InternalKey(user_key="Key1", seqno=9,  Type=Put)    | Value = "KEY1_VAL1"
InternalKey(user_key="Key2", seqno=16, Type=Put)    | Value = "KEY2_VAL2"
InternalKey(user_key="Key2", seqno=15, Type=Delete) | Value = "KEY2_VAL1"
InternalKey(user_key="Key3", seqno=7,  Type=Delete) | Value = "KEY3_VAL1"
InternalKey(user_key="Key4", seqno=5,  Type=Put)    | Value = "KEY4_VAL1"

DBIter将Internal Key解析为User Key,并暴露接口给用户

Key="Key1"  | Value = "KEY1_VAL2"
Key="Key2"  | Value = "KEY2_VAL2"
Key="Key4"  | Value = "KEY4_VAL1"

MergingIterator

Implementation: table/merging_iterator.cc
Interface: InternalIterator

MergingIterator由很多Children Iterator组成

autovector<IteratorWrapper, kNumIterReserve> children_;

MergingIterator会将这些Children Iterator放入堆中,并向上层有序地展示。

Example

children iterator为:

= Child Iterator 1 =
InternalKey(user_key="Key1", seqno=10, Type=Put)    | Value = "KEY1_VAL2"

= Child Iterator 2 =
InternalKey(user_key="Key1", seqno=9,  Type=Put)    | Value = "KEY1_VAL1"
InternalKey(user_key="Key2", seqno=15, Type=Delete) | Value = "KEY2_VAL1"
InternalKey(user_key="Key4", seqno=5,  Type=Put)    | Value = "KEY4_VAL1"

= Child Iterator 3 =
InternalKey(user_key="Key2", seqno=16, Type=Put)    | Value = "KEY2_VAL2"
InternalKey(user_key="Key3", seqno=7,  Type=Delete) | Value = "KEY3_VAL1"

MergingIterator将所有children iterator放入堆中,使其有序

InternalKey(user_key="Key1", seqno=10, Type=Put)    | Value = "KEY1_VAL2"
InternalKey(user_key="Key1", seqno=9,  Type=Put)    | Value = "KEY1_VAL1"
InternalKey(user_key="Key2", seqno=16, Type=Put)    | Value = "KEY2_VAL2"
InternalKey(user_key="Key2", seqno=15, Type=Delete) | Value = "KEY2_VAL1"
InternalKey(user_key="Key3", seqno=7,  Type=Delete) | Value = "KEY3_VAL1"
InternalKey(user_key="Key4", seqno=5,  Type=Put)    | Value = "KEY4_VAL1"

MemtableIterator

Implementation: db/memtable.cc
Interface: InternalIterator

用作对Memtable的迭代器,每个memtable实现了他们自己的迭代器,来对外界暴露出有序可迭代的kv对

BlockIter

Implementation: table/block_based/block.h
Interface: InternalIterator

该迭代器用于从SST File中读取block,无论这些block是index block还是data block或是meta block(DataBlockIter、IndexBlockIter、MetaBlockIter继承了BlockIter)。由于SST文件块是有序且不可变的,因此我们将该块加载到内存中,并为此排序后的数据创建一个BlockIter。

TwoLevelIterator

Implementation: table/two_level_iterator.cc
Interface: InternalIterator

一个TwoLevelIterator由两个迭代器组成

  • first_level_iter_
  • second_level_iter_

first_level_iter_ 用来找到使用哪个second_level_iter_ , 然后second_level_iter_ 指向实际需要读的数据

Example

RocksDB使用TwoLevelIterator来读取SST files, first_level_iter_ 是对于Index block的BlockIter,second_level_iter_ 是对于Data block的BlockIter.

[Data block, offset: 0x0000]
KEY1  | VALUE1
KEY2  | VALUE2
KEY3  | VALUE3

[Data Block, offset: 0x0100]
KEY4  | VALUE4
KEY7  | VALUE7

[Data Block, offset: 0x0250]
KEY8  | VALUE8
KEY9  | VALUE9

[Data Block, offset: 0x0350]
KEY11 | VALUE11
KEY15 | VALUE15

[Index Block, offset: 0x0500]
KEY3  | 0x0000
KEY7  | 0x0100
KEY9  | 0x0250
KEY15 | 0x0500

first_level_iter_ => BlockIter over Index block
second_level_iter_ => BlockIter over Data block,将被first_level_iter_决定指向哪个
当使用TwoLevelIterator来seek KEY8时,首先使用first_level_iter_ seek到对应的data block(0x0250),然后使用second_level_iter_来seek具体的key。

读取Data Block时,若 Block 在 Block Cache 当中,直接返回对象地址,否则,发生磁盘IO,读取 SST 的 Block,构造 Block 对象并缓存其地址在 Block Cache 中。

阅读 781

Move on.

4 声望
3 粉丝
0 条评论

Move on.

4 声望
3 粉丝
文章目录
宣传栏