TwoLevelIterator

TwoLevelIterator 是一个二维的迭代器. 即 TwoLevelIterator 的 value 是另一个迭代器对象的指针. 它的使用场景有两处:

  • 1.生成某一层 sst 文件所有的键值对迭代器。
  • 2.生成一个 Table 所有键值对迭代器。

我们来讨论它们的实现方式。 TwoLevelIterator 内部维持了两个迭代器:index_iter, data_iter。index_iter 是键与“低维迭代器构造信息”的对应, data_iter 是键与值对应,它是实际遍历的对象。index_iter.value() 即是构造 data_iter 的输入。

1.1 Seek(const Slice& target)

seek 的实现分三步

  • 1.使用 index_iter.Seek(target) 定位到 target 对应的“低维迭代器构造信息”。
  • 2.使用构造信息去生成一个 data_iter(可以优化为,若当前持有的 data_iter 正是要生成的则免去生成这一步)
  • 3.调用 data_iter.Seek(target) 定位

1.2 SeekToFirst

比较简单,index_iter.SeekToFirst,data_iter.SeekToFirst 即可。同 SeekToLast

1.3 Next

对 TwoLevelIterator 当前持有的 data_iter.Next,若 data_iter 此时位置无效则需要 index_iter.Next,生成新的 data_iter, 更稳一点,确保是 data_iter 第一个元素,调用 data_iter.SeekToFirst。 实际上 TwoLevelIterator 的 Seek- 系列函数都作了此处理:若 data_iter 为 NULL 或当前位置无效则需要额外处理。详见代码注释。 同 Prev

1.4 应用场景详解

本文最开始已经指出, TwoLevelIterator 有两个使用场景,它们各自的实现方式如下:

  • 1.生成某一层 sst 文件所有的键值对迭代器。实现方式是: 第一维的 index_iter 即是 LevelFileNumIterator,表示第 level 层文件列表的迭代器, 是键值与单个文件的映射. InternalKey --> (file number, file size) 第二维的 data_iter 即是 TableCache 的 Iterator,它是 TableCache 上的键值对迭代器,使用1中的 (file number 和 file size)构造出来。

  • 2.生成一个 Table 所有键值对迭代器。实现方式是: 第一维的 index_iter 即是 sst 文件格式中的 index_block,表示这个 sst 文件的索引,是键值与 sst 中位置信息的映射. InternalKey --> (offset, size) 第二维的 data_iter 是 Block 上的迭代器,用于返回元素的 key-value.

更多的细节见 two_level_iterator.cc 和部分 version_set.cc 代码注释。

//two_level_iterator.cc
namespace {

typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);


/************************************************************************/
/* 
lzh:    TwoLevelIterator 是一个二维的迭代器. 即 TwoLevelIterator 的 value 与另一个迭代器对象关联. 
        查找一个元素需要两次 Seek:第一次找到此元素所在的迭代器,第二次在上一个迭代器上查找此元素。
*/
/************************************************************************/
class TwoLevelIterator: public Iterator {
 public:
  TwoLevelIterator(
    Iterator* index_iter,
    BlockFunction block_function,
    void* arg,
    const ReadOptions& options);

  virtual ~TwoLevelIterator();

  virtual void Seek(const Slice& target);
  virtual void SeekToFirst();
  virtual void SeekToLast();
  virtual void Next();
  virtual void Prev();

  virtual bool Valid() const {
    return data_iter_.Valid();
  }
  virtual Slice key() const {
    assert(Valid());
    return data_iter_.key();
  }
  virtual Slice value() const {
    assert(Valid());
    return data_iter_.value();
  }
  virtual Status status() const {
    // It'd be nice if status() returned a const Status& instead of a Status
    if (!index_iter_.status().ok()) {
      return index_iter_.status();
    } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) {
      return data_iter_.status();
    } else {
      return status_;
    }
  }

 private:
  void SaveError(const Status& s) {
    if (status_.ok() && !s.ok()) status_ = s;
  }
  void SkipEmptyDataBlocksForward();
  void SkipEmptyDataBlocksBackward();
  void SetDataIterator(Iterator* data_iter);
  void InitDataBlock();

  BlockFunction block_function_;
  void* arg_;
  const ReadOptions options_;
  Status status_;
  IteratorWrapper index_iter_;
  IteratorWrapper data_iter_; // May be NULL
  // If data_iter_ is non-NULL, then "data_block_handle_" holds the
  // "index_value" passed to block_function_ to create the data_iter_.
  std::string data_block_handle_;
};

TwoLevelIterator::TwoLevelIterator(
    Iterator* index_iter,
    BlockFunction block_function,
    void* arg,
    const ReadOptions& options)
    : block_function_(block_function),
      arg_(arg),
      options_(options),
      index_iter_(index_iter),
      data_iter_(NULL) {
}

TwoLevelIterator::~TwoLevelIterator() {
}

void TwoLevelIterator::Seek(const Slice& target) {
  index_iter_.Seek(target);
  InitDataBlock();
  if (data_iter_.iter() != NULL) data_iter_.Seek(target);
  SkipEmptyDataBlocksForward();
}

void TwoLevelIterator::SeekToFirst() {
  index_iter_.SeekToFirst();
  InitDataBlock();
  if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
  SkipEmptyDataBlocksForward();
}

void TwoLevelIterator::SeekToLast() {
  index_iter_.SeekToLast();
  InitDataBlock();
  if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
  SkipEmptyDataBlocksBackward();
}

void TwoLevelIterator::Next() {
  assert(Valid());
  data_iter_.Next();
  SkipEmptyDataBlocksForward();
}

void TwoLevelIterator::Prev() {
  assert(Valid());
  data_iter_.Prev();
  SkipEmptyDataBlocksBackward();
}

/************************************************************************/
/* 
    lzh: 向前(Next 方向)跳过空的或无效的数据块
*/
/************************************************************************/
void TwoLevelIterator::SkipEmptyDataBlocksForward() {
  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
    // Move to next block
    if (!index_iter_.Valid()) {
      SetDataIterator(NULL);
      return;
    }
    //lzh: 索引块往后遍历,即得到下一个数据块
    index_iter_.Next();
    InitDataBlock();
    //lzh: 新块的第一个位置
    if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
  }
}

/************************************************************************/
/* 
    lzh: 向后(Prev 方向)跳过空的或无效的数据块
*/
/************************************************************************/
void TwoLevelIterator::SkipEmptyDataBlocksBackward() {
  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
    // Move to next block
    if (!index_iter_.Valid()) {
      SetDataIterator(NULL);
      return;
    }
    index_iter_.Prev();
    InitDataBlock();
    if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
  }
}

void TwoLevelIterator::SetDataIterator(Iterator* data_iter) {
  if (data_iter_.iter() != NULL) SaveError(data_iter_.status());
  data_iter_.Set(data_iter);
}


/************************************************************************/
/* 
    lzh: 此函数在该迭代器的所有 Seek 系列方法中被调用, 
    注意当前迭代器 TwoLevelIterator 的值是 data_iter_ 迭代器中的索引
*/
/************************************************************************/
void TwoLevelIterator::InitDataBlock() {
  if (!index_iter_.Valid()) {
    SetDataIterator(NULL);
  } else {
    Slice handle = index_iter_.value();
    if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) {
      // data_iter_ is already constructed with this iterator, so
      // no need to change anything
    } else {

      Iterator* iter    //lzh: 
          = 
          (*block_function_)(
          arg_,            //lzh: table 
          options_,        //lzh: read option (block cache 挂在 option 中)
          handle        //lzh: handle 即是元素在 talbe 中的位置信息
          );
      data_block_handle_.assign(handle.data(), handle.size());
      SetDataIterator(iter);
    }
  }
}

}

Iterator* NewTwoLevelIterator(
    Iterator* index_iter,
    BlockFunction block_function,
    void* arg,
    const ReadOptions& options) {
  return new TwoLevelIterator(index_iter, block_function, arg, options);
}

第一种场景下的二维迭代器使用见 version_set.cc 如下代码:

/************************************************************************/
/* 
    lzh: 生成访问第 level 层的文件的迭代器.    它是一个二维的迭代器;
    第(1)维的 LevelFileNumIterator 迭代器是第 level 层文件列表的迭代器, 返回的单个文件{(file number, file size)}
    第(2)维的 TableCache 的 Iterator 是 TableCache 上的迭代器, 用于访问数据
*/
/************************************************************************/
Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
                                            int level) const {
  return NewTwoLevelIterator(
      new LevelFileNumIterator(vset_->icmp_, &files_[level]),
      &GetFileIterator, vset_->table_cache_, options);
}

第二种场景下的二维迭代器使用见 table.cc 如下代码:

/************************************************************************/
/* 
    lzh: 返回一个遍历此 Table 的迭代器.
    第一维的迭代器是 index_block 的迭代器,用于返回元素在 table 中的位置信息.
    第二维的迭代器是 table 上的迭代器,用于返回元素的 key-value.
*/
/************************************************************************/
Iterator* Table::NewIterator(const ReadOptions& options) const {
  return NewTwoLevelIterator(
      rep_->index_block->NewIterator(rep_->options.comparator),    //lzh: table 的 index_block
      &Table::BlockReader, 
      const_cast<Table*>(this), 
      options);
}

results matching ""

    No results matching ""