LevelFileNumIterator

这个迭代器用于遍历某层的 sst 文件。迭代器维持了一个指向文件的下标 index,通过它的增减表示向前后的遍历。 index 等于文件总个数时表示迭代器失效。 下面是迭代器主要方法的实现

1.1 Next

判断当前迭代器有效性。直接增加 index_

1.2 Prev

判断当前迭代器有效性。若当前 index 为0则设置为文件个数,表示失效。直接减小 index

1.3 Seek(const Slice& target)

使用 FindFile,通过二分法从文件列表中找出首个 largest >= target 的文件,即说明键 target 在这个文件之中。 设置 index_ 为此文件下标即是。 详情见代码注释

class Version::LevelFileNumIterator : public Iterator {
 public:
  LevelFileNumIterator(const InternalKeyComparator& icmp,
                       const std::vector<FileMetaData*>* flist)
      : icmp_(icmp),
        flist_(flist),
        index_(flist->size()) {        // Marks as invalid
  }
  virtual bool Valid() const {
    return index_ < flist_->size();
  }

  /************************************************************************/
  /* 
    lzh:
    返回首个 largest 比 target 的文件.
    若 target < flist_[0].smallest 则返回 0,该情况下表示 target 可能在 flist_[0] 中或者不在
    若 target > flist_[flist_->size()-1] 则返回 flist_->size(),无效的位置
  */
  /************************************************************************/
  virtual void Seek(const Slice& target) {
    index_ = FindFile(icmp_, *flist_, target);
  }
  virtual void SeekToFirst() { index_ = 0; }
  virtual void SeekToLast() {
    index_ = flist_->empty() ? 0 : flist_->size() - 1;
  }
  virtual void Next() {
    assert(Valid());
    index_++;
  }
  virtual void Prev() {
    assert(Valid());
    if (index_ == 0) {
      index_ = flist_->size();  // Marks as invalid
    } else {
      index_--;
    }
  }

  /************************************************************************/
  /* 
    lzh: 返回当前位置文件的 largest
  */
  /************************************************************************/
  Slice key() const {
    assert(Valid());
    return (*flist_)[index_]->largest.Encode();
  }

  /************************************************************************/
  /* 
    lzh: 返回当前位置文件的 number, size 的固长编码
  */
  /************************************************************************/
  Slice value() const {
    assert(Valid());
    EncodeFixed64(value_buf_, (*flist_)[index_]->number);
    EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size);
    return Slice(value_buf_, sizeof(value_buf_));
  }
  virtual Status status() const { return Status::OK(); }
 private:
  const InternalKeyComparator icmp_;
  const std::vector<FileMetaData*>* const flist_;
  uint32_t index_;

  // Backing store for value().  Holds the file number and size.
  mutable char value_buf_[16];
};

FindFile 是一个二分法查找算法,如下:

/************************************************************************/
/************************************************************************/
/* 
    lzh: 使用二分法找出 files(正序排列) 中首个 largest >= key 的 file
    注意边界条件
        1.若 files[0].smallest > key 则返回 0
        2.若 files[files.size()-1].largest < key 则返回 files.size()
    调用者若想调用此函数返回 key 所在的文件,则需要注意第 1 种情况可能是个反例
*/
/************************************************************************/
int FindFile(const InternalKeyComparator& icmp,
             const std::vector<FileMetaData*>& files,
             const Slice& key) {
  uint32_t left = 0;
  uint32_t right = files.size();
  while (left < right) {
    uint32_t mid = (left + right) / 2;
    const FileMetaData* f = files[mid];
    if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {
      // Key at "mid.largest" is < "target".  Therefore all
      // files at or before "mid" are uninteresting.
      left = mid + 1;
    } else {
      // Key at "mid.largest" is >= "target".  Therefore all files
      // after "mid" are uninteresting.
      right = mid;
    }
  }
  return right;
}

results matching ""

    No results matching ""