// Copyright (c) Facebook, Inc. and its affiliates. 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). #pragma once #include "cache/cache_entry_roles.h" #include "port/lang.h" #include "table/block_based/block.h" #include "table/block_based/block_type.h" #include "table/block_based/parsed_full_filter_block.h" #include "table/format.h" namespace ROCKSDB_NAMESPACE { template class BlocklikeTraits; template Cache::CacheItemHelper* GetCacheItemHelperForRole(); template Cache::CreateCallback GetCreateCallback(size_t read_amp_bytes_per_bit, Statistics* statistics, bool using_zstd, const FilterPolicy* filter_policy) { return [read_amp_bytes_per_bit, statistics, using_zstd, filter_policy]( void* buf, size_t size, void** out_obj, size_t* charge) -> Status { assert(buf != nullptr); std::unique_ptr buf_data(new char[size]()); memcpy(buf_data.get(), buf, size); BlockContents bc = BlockContents(std::move(buf_data), size); TBlocklike* ucd_ptr = BlocklikeTraits::Create( std::move(bc), read_amp_bytes_per_bit, statistics, using_zstd, filter_policy); *out_obj = reinterpret_cast(ucd_ptr); *charge = size; return Status::OK(); }; } template <> class BlocklikeTraits { public: static BlockContents* Create(BlockContents&& contents, size_t /* read_amp_bytes_per_bit */, Statistics* /* statistics */, bool /* using_zstd */, const FilterPolicy* /* filter_policy */) { return new BlockContents(std::move(contents)); } static uint32_t GetNumRestarts(const BlockContents& /* contents */) { return 0; } static size_t SizeCallback(void* obj) { assert(obj != nullptr); BlockContents* ptr = static_cast(obj); return ptr->data.size(); } static Status SaveToCallback(void* from_obj, size_t from_offset, size_t length, void* out) { assert(from_obj != nullptr); BlockContents* ptr = static_cast(from_obj); const char* buf = ptr->data.data(); assert(length == ptr->data.size()); (void)from_offset; memcpy(out, buf, length); return Status::OK(); } static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) { if (block_type == BlockType::kFilter) { return GetCacheItemHelperForRole< BlockContents, CacheEntryRole::kDeprecatedFilterBlock>(); } else { // E.g. compressed cache return GetCacheItemHelperForRole(); } } }; template <> class BlocklikeTraits { public: static ParsedFullFilterBlock* Create(BlockContents&& contents, size_t /* read_amp_bytes_per_bit */, Statistics* /* statistics */, bool /* using_zstd */, const FilterPolicy* filter_policy) { return new ParsedFullFilterBlock(filter_policy, std::move(contents)); } static uint32_t GetNumRestarts(const ParsedFullFilterBlock& /* block */) { return 0; } static size_t SizeCallback(void* obj) { assert(obj != nullptr); ParsedFullFilterBlock* ptr = static_cast(obj); return ptr->GetBlockContentsData().size(); } static Status SaveToCallback(void* from_obj, size_t from_offset, size_t length, void* out) { assert(from_obj != nullptr); ParsedFullFilterBlock* ptr = static_cast(from_obj); const char* buf = ptr->GetBlockContentsData().data(); assert(length == ptr->GetBlockContentsData().size()); (void)from_offset; memcpy(out, buf, length); return Status::OK(); } static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) { (void)block_type; assert(block_type == BlockType::kFilter); return GetCacheItemHelperForRole(); } }; template <> class BlocklikeTraits { public: static Block* Create(BlockContents&& contents, size_t read_amp_bytes_per_bit, Statistics* statistics, bool /* using_zstd */, const FilterPolicy* /* filter_policy */) { return new Block(std::move(contents), read_amp_bytes_per_bit, statistics); } static uint32_t GetNumRestarts(const Block& block) { return block.NumRestarts(); } static size_t SizeCallback(void* obj) { assert(obj != nullptr); Block* ptr = static_cast(obj); return ptr->size(); } static Status SaveToCallback(void* from_obj, size_t from_offset, size_t length, void* out) { assert(from_obj != nullptr); Block* ptr = static_cast(from_obj); const char* buf = ptr->data(); assert(length == ptr->size()); (void)from_offset; memcpy(out, buf, length); return Status::OK(); } static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) { switch (block_type) { case BlockType::kData: return GetCacheItemHelperForRole(); case BlockType::kIndex: return GetCacheItemHelperForRole(); case BlockType::kFilter: return GetCacheItemHelperForRole(); default: // Not a recognized combination assert(false); FALLTHROUGH_INTENDED; case BlockType::kRangeDeletion: return GetCacheItemHelperForRole(); } } }; template <> class BlocklikeTraits { public: static UncompressionDict* Create(BlockContents&& contents, size_t /* read_amp_bytes_per_bit */, Statistics* /* statistics */, bool using_zstd, const FilterPolicy* /* filter_policy */) { return new UncompressionDict(contents.data, std::move(contents.allocation), using_zstd); } static uint32_t GetNumRestarts(const UncompressionDict& /* dict */) { return 0; } static size_t SizeCallback(void* obj) { assert(obj != nullptr); UncompressionDict* ptr = static_cast(obj); return ptr->slice_.size(); } static Status SaveToCallback(void* from_obj, size_t from_offset, size_t length, void* out) { assert(from_obj != nullptr); UncompressionDict* ptr = static_cast(from_obj); const char* buf = ptr->slice_.data(); assert(length == ptr->slice_.size()); (void)from_offset; memcpy(out, buf, length); return Status::OK(); } static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) { (void)block_type; assert(block_type == BlockType::kCompressionDictionary); return GetCacheItemHelperForRole(); } }; // Get an CacheItemHelper pointer for value type T and role R. template Cache::CacheItemHelper* GetCacheItemHelperForRole() { static Cache::CacheItemHelper cache_helper( BlocklikeTraits::SizeCallback, BlocklikeTraits::SaveToCallback, GetCacheEntryDeleterForRole()); return &cache_helper; } } // namespace ROCKSDB_NAMESPACE