git / moonbite-core / src/leveldb/table/two_level_iterator.cc · raw
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file. See the AUTHORS file for names of contributors.#include "table/two_level_iterator.h"#include "leveldb/table.h"#include "table/block.h"#include "table/format.h"#include "table/iterator_wrapper.h"namespace leveldb {namespace {typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);class TwoLevelIterator : public Iterator { public: TwoLevelIterator(Iterator* index_iter, BlockFunction block_function, void* arg, const ReadOptions& options); ~TwoLevelIterator() override; void Seek(const Slice& target) override; void SeekToFirst() override; void SeekToLast() override; void Next() override; void Prev() override; bool Valid() const override { return data_iter_.Valid(); } Slice key() const override { assert(Valid()); return data_iter_.key(); } 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: 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 nullptr // 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_(nullptr) {}TwoLevelIterator::~TwoLevelIterator() = default;void TwoLevelIterator::Seek(const Slice& target) { index_iter_.Seek(target); InitDataBlock(); if (data_iter_.iter() != nullptr) data_iter_.Seek(target); SkipEmptyDataBlocksForward();}void TwoLevelIterator::SeekToFirst() { index_iter_.SeekToFirst(); InitDataBlock(); if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); SkipEmptyDataBlocksForward();}void TwoLevelIterator::SeekToLast() { index_iter_.SeekToLast(); InitDataBlock(); if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); SkipEmptyDataBlocksBackward();}void TwoLevelIterator::Next() { assert(Valid()); data_iter_.Next(); SkipEmptyDataBlocksForward();}void TwoLevelIterator::Prev() { assert(Valid()); data_iter_.Prev(); SkipEmptyDataBlocksBackward();}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(); }}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);}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); } }}} // namespaceIterator* NewTwoLevelIterator(Iterator* index_iter, BlockFunction block_function, void* arg, const ReadOptions& options) { return new TwoLevelIterator(index_iter, block_function, arg, options);}} // namespace leveldb