cachelib/allocator/CacheChainedItemIterator.h (69 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <folly/io/IOBuf.h> #include <stdexcept> #include "cachelib/common/Iterators.h" namespace facebook { namespace cachelib { namespace tests { template <typename AllocatorT> class BaseAllocatorTest; } // namespace tests // Class to iterate through chained items in the special case that the caller // has the item but no itemhandle (e.g. during release) template <typename Cache, typename ItemT> class CacheChainedItemIterator : public detail::IteratorFacade<CacheChainedItemIterator<Cache, ItemT>, ItemT, std::forward_iterator_tag> { public: using Item = ItemT; CacheChainedItemIterator() = default; Item& dereference() const { if (curr_) { return *curr_; } if (curIOBuf_) { return *reinterpret_cast<Item*>(curIOBuf_->writableData()); } throw std::runtime_error("no item to dereference"); } // advance the iterator. // Do nothing if uninitizliaed. void increment() { if (curr_) { curr_ = curr_->asChainedItem().getNext(*compressor_); } if (curIOBuf_) { curIOBuf_ = curIOBuf_->next(); } } bool equal(const CacheChainedItemIterator<Cache, Item>& other) const { if (curr_ || other.curr_) { return curr_ == other.curr_; } return curIOBuf_ == other.curIOBuf_; } private: using PtrCompressor = typename Item::PtrCompressor; // Private because only CacheT can create this. // @param item Pointer to chained item (nullptr for null iterator) // @param compressor Compressor used to get pointer to next in chain explicit CacheChainedItemIterator(Item* item, const PtrCompressor& compressor) : curr_(item), compressor_(&compressor) { // If @item is not nullptr, check that it is a chained item if (curr_ && !curr_->isChainedItem()) { throw std::invalid_argument( "Cannot initialize ChainedAllocIterator, Item is not a ChainedItem"); } } // only NvmCacheT can create with this constructor // this is used to construct chained item for ItemDestructor // with DipperItem on Navy, Item is allocated at heap (as IOBuf) // instead of in allocator memory pool. explicit CacheChainedItemIterator(folly::IOBuf* iobuf) : curIOBuf_(iobuf) { // If @item is not nullptr, check that it is a chained item or parent item // sine IOBuf chains is a circle, so we need to let the parent be the end // iterator if (curIOBuf_ && !dereference().isChainedItem() && !dereference().hasChainedItem()) { throw std::invalid_argument( "Cannot initialize ChainedAllocIterator, Item is not a ChainedItem"); } } // Current iterator position in chain Item* curr_{nullptr}; // Removed/evicted from NVM folly::IOBuf* curIOBuf_{nullptr}; // Pointer compressor to traverse the chain. const PtrCompressor* compressor_{nullptr}; friend Cache; friend typename Cache::NvmCacheT; friend typename Cache::ChainedAllocs; friend typename Cache::WritableChainedAllocs; // For testing template <typename AllocatorT> friend class facebook::cachelib::tests::BaseAllocatorTest; }; } // namespace cachelib } // namespace facebook