【leveldb】TwoLevelIterator(十五)

在分析SSTable代码过程中涉及到了二级迭代器,此篇借此展开分析下。二级迭代器的存在便于对SSTable的DataBlock数据进行访问,其结构如下:
在这里插入图片描述

图1

对于SSTable来说:

  • Level_1是Index Block迭代器;
  • Level_2是指向DataBlock迭代器。

通过这种设计,可以对SSTable的所有key进行向前扫描,向后扫描这种批量查询工作。

源码解读
namespace leveldb {

namespace {

//设置二级迭代器时传入的回调函数
typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);

class TwoLevelIterator : public Iterator {
 public:
  
  //构造。对于SSTable来说:
  //1、index_iter是指向index block的迭代器;
  //2、block_function是Table::BlockReader,即读取一个block;
  //3、arg是指向一个SSTable;
  //4、options 读选项。
  TwoLevelIterator(Iterator* index_iter, BlockFunction block_function,
                   void* arg, const ReadOptions& options);

  ~TwoLevelIterator() override;

  //针对一级迭代器,target是一个index block元素,
  //这里就是seek到index block对应元素位置
  void Seek(const Slice& target) override;
  //针对一级迭代器操作
  void SeekToFirst() override;
  //针对一级迭代器操作
  void SeekToLast() override;
  //针对二级迭代器,DataBlock中的下一个Entry
  void Next() override;
  //针对二级迭代器,DataBlock中的前一个Entry
  void Prev() override;

  //针对二级迭代器,指向DataBlock的迭代器是否有效
  bool Valid() const override { return data_iter_.Valid(); }
  //针对二级迭代器,DataBlock中的一个Entry的Key
  Slice key() const override {
    assert(Valid());
    return data_iter_.key();
  }
  //针对二级迭代器,DataBlock中的一个Entry的Value
  Slice value() const override {
    assert(Valid());
    return data_iter_.value();
  }

  //当前二级迭代器的操作状态
  Status status() const override {
    // 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() != nullptr && !data_iter_.status().ok()) {
      return data_iter_.status();
    } else {
      return status_;
    }
  }

 private:
  //保存错误状态,如果最近一次状态是非ok状态,
  //则不保存
  void SaveError(const Status& s) {
    if (status_.ok() && !s.ok()) status_ = s;
  }
  //跳过当前空的DataBlock,转到下一个DataBlock
  void SkipEmptyDataBlocksForward();
  //跳过当前空的DataBlock,转到前一个DataBlock
  void SkipEmptyDataBlocksBackward();
  //设置二级迭代器data_iter
  void SetDataIterator(Iterator* data_iter);
  //初始化DataBlock的二级迭代器
  void InitDataBlock();

  BlockFunction block_function_;
  void* arg_;
  const ReadOptions options_;
  Status status_;
  //一级迭代器,对于SSTable来说就是指向index block
  IteratorWrapper index_iter_; 
  //二级迭代器,对于SSTable来说就是指向DataBlock
  IteratorWrapper data_iter_;  // May be nullptr
  
  //对于SSTable来说,保存index block中的offset+size。
  // 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_;
};

//构造二级迭代器。
//一级迭代器赋值为index_iner,
//二级迭代器赋值为nullptr。
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_(nullptr) {}

TwoLevelIterator::~TwoLevelIterator() = default;

//1、seek到target对应的一级迭代器位置;
//2、初始化二级迭代器;
//3、跳过当前空的DataBlock。
void TwoLevelIterator::Seek(const Slice& target) {
  index_iter_.Seek(target);
  InitDataBlock();
  if (data_iter_.iter() != nullptr) data_iter_.Seek(target);
  SkipEmptyDataBlocksForward();
}

//流程同Seek()
void TwoLevelIterator::SeekToFirst() {
  index_iter_.SeekToFirst();
  InitDataBlock();
  if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst();
  SkipEmptyDataBlocksForward();
}

//流程同Seek()
void TwoLevelIterator::SeekToLast() {
  index_iter_.SeekToLast();
  InitDataBlock();
  if (data_iter_.iter() != nullptr) data_iter_.SeekToLast();
  SkipEmptyDataBlocksBackward();
}

//二级迭代器的下一个元素,
//对SSTable来说就是DataBlock中的下一个元素。
//需要检查跳过空的DataBlck。
void TwoLevelIterator::Next() {
  assert(Valid());
  data_iter_.Next();
  SkipEmptyDataBlocksForward();
}

//二级迭代器的前一个元素,
//对SSTable来说就是DataBlock中的前一个元素。
//需要检查跳过空的DataBlck。
void TwoLevelIterator::Prev() {
  assert(Valid());
  data_iter_.Prev();
  SkipEmptyDataBlocksBackward();
}

//针对二级迭代器。
//如果当前二级迭代器指向为空或者非法;
//那就向后跳到下一个非空的DataBlock。
void TwoLevelIterator::SkipEmptyDataBlocksForward() {
  while (data_iter_.iter() == nullptr || !data_iter_.Valid()) {
    // Move to next block
    if (!index_iter_.Valid()) {
      SetDataIterator(nullptr);
      return;
    }
    index_iter_.Next();
    InitDataBlock();
    if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst();
  }
}

//针对二级迭代器。
//如果当前二级迭代器指向为空或者非法;
//那就向前跳到下一个非空的DataBlock。
void TwoLevelIterator::SkipEmptyDataBlocksBackward() {
  while (data_iter_.iter() == nullptr || !data_iter_.Valid()) {
    // Move to next block
    if (!index_iter_.Valid()) {
      SetDataIterator(nullptr);
      return;
    }
    index_iter_.Prev();
    InitDataBlock();
    if (data_iter_.iter() != nullptr) data_iter_.SeekToLast();
  }
}

//设置二级迭代器
void TwoLevelIterator::SetDataIterator(Iterator* data_iter) {
  if (data_iter_.iter() != nullptr) SaveError(data_iter_.status());
  data_iter_.Set(data_iter);
}

//初始化二级迭代器指向。
//对SSTable来说就是获取DataBlock的迭代器赋值给二级迭代器。
void TwoLevelIterator::InitDataBlock() {
  if (!index_iter_.Valid()) {
    SetDataIterator(nullptr);
  } else {
    Slice handle = index_iter_.value();
    if (data_iter_.iter() != nullptr &&
        handle.compare(data_block_handle_) == 0) {
      // data_iter_ is already constructed with this iterator, so
      // no need to change anything
    } else {
      Iterator* iter = (*block_function_)(arg_, options_, handle);
      data_block_handle_.assign(handle.data(), handle.size());
      SetDataIterator(iter);
    }
  }
}

}  // namespace

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

}  // namespace leveldb
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值