TwoLevelIterator是用来访问可用 index域和 data域访问的数据。
如,sstable中的data block和index block。就是分别将index block的block iter和data block的block iter赋值给index iter和data iter.
0. TwoLevelIterator内部成员·
1 | class TwoLevelIterator : public Iterator { |
注意到TwoLevelIterator中的成员函数主要包括, block_function_, index_iter和data_iter_
. 后面两个iter是一个包装类,主要提供了cache策略,减少由于虚函数调用带来的开销。
1. 创建一个TwoLevelIterator·
1 | Iterator* NewTwoLevelIterator(Iterator* index_iter, |
一个实际调用的例子(这部分VersionSet::MakeInputIterator中,实际上这个函数是在DoCompaction过程中被调用):
1 | list[num++] = NewTwoLevelIterator( |
- index_iter等于我们上篇文章中说的LevelFileNumIterator。
- block_function = GetFileIterator
- table_cache_,options,作为block_function的参数
2. Seek·
1 | void TwoLevelIterator::Seek(const Slice& target) { |
首先将index_iter定位到target。
InitDataBlock·
1 | void TwoLevelIterator::InitDataBlock() { |
首次调用InitiDataBlock,会走到:
1 | Iterator* iter = (*block_function_)(arg_, options_, handle); |
以下面的例子来说明这个创建过程。
1 | list[num++] = NewTwoLevelIterator( |
- block_function_是GetFileIterator
- arg_ = table_cache_
- options_ = ReadOptions
- handle = 文件序列号和文件size
现在深入到GetFileIterator中:
1 | static Iterator* GetFileIterator(void* arg, const ReadOptions& options, |
到这里可以得到结论, TwoLevelIterator由两个iterator组成,一个是LevelFileNumIterator, 用于提供数据索引需要的元信息。另一个是cache iterator, 用于实际访问数据。
注意:这里LevelFileNumIterator和Table Iterator实际上又会被IteratorWrapper warp起来。(上文也提到了)。
上一篇文章已经说过了LevelFileNumIterator, 之后再说说Table Iterator
3. Next & Prev·
一旦有了data_iter, next和prev就简单了。
1 | void TwoLevelIterator::Next() { |
ok,其余几个seek操作都比较简单。
4. key & value·
1 | Slice key() const override { |
5. TwolevelIterator总结·
TwoLevelIterator是一种组合的Iterator,其内部由两个iter组成:index_iter和data_iter. index_iter用于索引,它包含了用来创建data_iter的元数据,实际上真实的key value存放在data_iter中。 在TwolevelIterator的各个seek操作中,都是先由index_iter找到合适的位置(索引),得到用来创建data_iter的元数据(sstable的file number和file size), 然后创建data_iter, 最终data_iter才seek到真实数据的位置。
6. TwolevelIterator的应用–Table::Iterator·
之前通过Compaction过程中用到的iterator介绍了TwoleveIIterator。现在用Table的Iterator来进一步理解TwolevelIterator。先看看入口:
1 | Iterator* Table::NewIterator(const ReadOptions& options) const { |
首先分析用来创建index iter的Block::NewIterator:
1 | Iterator* Block::NewIterator(const Comparator* comparator) { |
从这里可以看到index iter本质上就是一个Block::Iter, 是用来遍历index_block. 我们曾在SSTable章节中说过,index_block和data_block采用完全相同的结构。所以可以用Block::Iter进行遍历。
现在,看TwoLevelIterator的data iter部分,data iter主要由NewTwoLevelIterator参数中 &Table::BlockReader, const_cast<Table*>(this), options
构成。在TwoLevelIterator::InitDataBlock
函数中会初始化data iter:
1 | Iterator* iter = (*block_function_)(arg_, options_, handle); |
此时:
- block_function_ = BlockReader
- arg_ = const_cast<Table*>(this)
- options_ = options
- handle = index_iter->value(), 即index_block的value,也即index_block对应data_block的block_handle(offset和size)。
再看BlockReader:
1 | // Convert an index iterator value (i.e., an encoded BlockHandle) |
丛这里可以看到,BlockReader返回的也是一个Block::Iter,所以这个TwoleveIIterator的data iter就是data block的Block::Iter.
总结·
Table的Iter,是一个TwoLevelIterator,这个Iterator由index iter和data iter组成。 index iter为Block::iter, datablock iter也为Block::Iter.