// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // // 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. #pragma once #include #include "table/internal_iterator.h" namespace rocksdb { // A internal wrapper class with an interface similar to Iterator that // caches the valid() and key() results for an underlying iterator. // This can help avoid virtual function calls and also gives better // cache locality. class IteratorWrapper { public: IteratorWrapper() : iter_(nullptr), iters_pinned_(false), valid_(false) {} explicit IteratorWrapper(InternalIterator* _iter) : iter_(nullptr), iters_pinned_(false) { Set(_iter); } ~IteratorWrapper() {} InternalIterator* iter() const { return iter_; } // Takes the ownership of "_iter" and will delete it when destroyed. // Next call to Set() will destroy "_iter" except if PinData() was called. void Set(InternalIterator* _iter) { if (iters_pinned_ && iter_) { // keep old iterator until ReleasePinnedData() is called pinned_iters_.insert(iter_); } else { delete iter_; } iter_ = _iter; if (iter_ == nullptr) { valid_ = false; } else { Update(); if (iters_pinned_) { // Pin new iterator Status s = iter_->PinData(); assert(s.ok()); } } } Status PinData() { Status s; if (iters_pinned_) { return s; } if (iter_) { s = iter_->PinData(); } if (s.ok()) { iters_pinned_ = true; } return s; } Status ReleasePinnedData() { Status s; if (!iters_pinned_) { return s; } if (iter_) { s = iter_->ReleasePinnedData(); } if (s.ok()) { iters_pinned_ = false; // No need to call ReleasePinnedData() for pinned_iters_ // since we will delete them DeletePinnedIterators(false); } return s; } bool IsKeyPinned() const { assert(iter_); return iters_pinned_ && iter_->IsKeyPinned(); } void DeleteIter(bool is_arena_mode) { if (iter_ && pinned_iters_.find(iter_) == pinned_iters_.end()) { DestroyIterator(iter_, is_arena_mode); } DeletePinnedIterators(is_arena_mode); } // Iterator interface methods bool Valid() const { return valid_; } Slice key() const { assert(Valid()); return key_; } Slice value() const { assert(Valid()); return iter_->value(); } // Methods below require iter() != nullptr Status status() const { assert(iter_); return iter_->status(); } void Next() { assert(iter_); iter_->Next(); Update(); } void Prev() { assert(iter_); iter_->Prev(); Update(); } void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } private: void Update() { valid_ = iter_->Valid(); if (valid_) { key_ = iter_->key(); } } void DeletePinnedIterators(bool is_arena_mode) { for (auto it : pinned_iters_) { DestroyIterator(it, is_arena_mode); } pinned_iters_.clear(); } inline void DestroyIterator(InternalIterator* it, bool is_arena_mode) { if (!is_arena_mode) { delete it; } else { it->~InternalIterator(); } } InternalIterator* iter_; // If set to true, current and future iterators wont be deleted. bool iters_pinned_; // List of past iterators that are pinned and wont be deleted as long as // iters_pinned_ is true. When we are pinning iterators this set will contain // iterators of previous data blocks to keep them from being deleted. std::set pinned_iters_; bool valid_; Slice key_; }; class Arena; // Return an empty iterator (yields nothing) allocated from arena. extern InternalIterator* NewEmptyInternalIterator(Arena* arena); // Return an empty iterator with the specified status, allocated arena. extern InternalIterator* NewErrorInternalIterator(const Status& status, Arena* arena); } // namespace rocksdb