// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root 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" #include "test_util/sync_point.h" namespace ROCKSDB_NAMESPACE { // 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. template class IteratorWrapperBase { public: IteratorWrapperBase() : iter_(nullptr), valid_(false) {} explicit IteratorWrapperBase(InternalIteratorBase* _iter) : iter_(nullptr) { Set(_iter); } ~IteratorWrapperBase() {} InternalIteratorBase* iter() const { return iter_; } void SetRangeDelReadSeqno(SequenceNumber read_seqno) { if (iter_) { iter_->SetRangeDelReadSeqno(read_seqno); } } // Set the underlying Iterator to _iter and return // previous underlying Iterator. InternalIteratorBase* Set(InternalIteratorBase* _iter) { InternalIteratorBase* old_iter = iter_; iter_ = _iter; if (iter_ == nullptr) { valid_ = false; } else { Update(); } return old_iter; } void DeleteIter(bool is_arena_mode) { if (iter_) { #ifdef ROCKSDB_ASSERT_STATUS_CHECKED if (!status_checked_after_invalid_) { // If this assertion fails, it is likely that you did not check // iterator status after Valid() returns false. fprintf(stderr, "Failed to check status after Valid() returned false from this " "iterator.\n"); port::PrintStack(); std::abort(); } #endif if (!is_arena_mode) { delete iter_; } else { iter_->~InternalIteratorBase(); } } } // Iterator interface methods bool Valid() const { #ifdef ROCKSDB_ASSERT_STATUS_CHECKED status_checked_after_invalid_ = valid_; #endif return valid_; } Slice key() const { assert(Valid()); return result_.key; } uint64_t write_unix_time() const { assert(Valid()); return iter_->write_unix_time(); } TValue value() const { assert(Valid()); return iter_->value(); } // Methods below require iter() != nullptr Status status() const { #ifdef ROCKSDB_ASSERT_STATUS_CHECKED status_checked_after_invalid_ = true; #endif assert(iter_); return iter_->status(); } bool PrepareValue() { assert(Valid()); if (result_.value_prepared) { return true; } if (iter_->PrepareValue()) { result_.value_prepared = true; result_.key = iter_->key(); return true; } assert(!iter_->Valid()); valid_ = false; return false; } void Next() { assert(iter_); valid_ = iter_->NextAndGetResult(&result_); assert(!valid_ || iter_->status().ok()); } bool NextAndGetResult(IterateResult* result) { assert(iter_); valid_ = iter_->NextAndGetResult(&result_); *result = result_; assert(!valid_ || iter_->status().ok()); return valid_; } void Prev() { assert(iter_); iter_->Prev(); Update(); } void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } void SeekForPrev(const Slice& k) { assert(iter_); iter_->SeekForPrev(k); Update(); } void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } bool MayBeOutOfLowerBound() { assert(Valid()); return iter_->MayBeOutOfLowerBound(); } IterBoundCheck UpperBoundCheckResult() { assert(Valid()); return result_.bound_check_result; } void SetPinnedItersMgr(PinnedIteratorsManager* pinned_iters_mgr) { assert(iter_); iter_->SetPinnedItersMgr(pinned_iters_mgr); } bool IsKeyPinned() const { assert(Valid()); return iter_->IsKeyPinned(); } bool IsValuePinned() const { assert(Valid()); return iter_->IsValuePinned(); } bool IsValuePrepared() const { return result_.value_prepared; } Slice user_key() const { assert(Valid()); return iter_->user_key(); } void UpdateReadaheadState(InternalIteratorBase* old_iter) { if (old_iter && iter_) { ReadaheadFileInfo readahead_file_info; old_iter->GetReadaheadState(&readahead_file_info); iter_->SetReadaheadState(&readahead_file_info); } } bool IsDeleteRangeSentinelKey() const { return iter_->IsDeleteRangeSentinelKey(); } private: void Update() { valid_ = iter_->Valid(); if (valid_) { assert(iter_->status().ok()); result_.key = iter_->key(); result_.bound_check_result = IterBoundCheck::kUnknown; result_.value_prepared = false; } } InternalIteratorBase* iter_; IterateResult result_; bool valid_; #ifdef ROCKSDB_ASSERT_STATUS_CHECKED mutable bool status_checked_after_invalid_ = true; #endif }; using IteratorWrapper = IteratorWrapperBase; class Arena; // Return an empty iterator (yields nothing) allocated from arena. template InternalIteratorBase* NewEmptyInternalIterator(Arena* arena); } // namespace ROCKSDB_NAMESPACE