rocksdb/table/block_based/block_like_traits.h
anand76 2553d1efa1 Revert "Avoid dynamic memory allocation on read path (#10453)" (#10541)
Summary:
This reverts commit 0d885e80d4. The original commit causes a ASAN stack-use-after-return failure due to the `CreateCallback` being allocated on stack and then used in another thread when a secondary cache object is promoted to the primary cache.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10541

Reviewed By: gitbw95

Differential Revision: D38850039

Pulled By: anand1976

fbshipit-source-id: 810c592b7de2523693f5bb267159b23b0ee9132c
2022-08-19 11:02:54 -07:00

222 lines
7.7 KiB
C++

// 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 <typename TBlocklike>
class BlocklikeTraits;
template <typename T, CacheEntryRole R>
Cache::CacheItemHelper* GetCacheItemHelperForRole();
template <typename TBlocklike>
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](
const void* buf, size_t size, void** out_obj,
size_t* charge) -> Status {
assert(buf != nullptr);
std::unique_ptr<char[]> buf_data(new char[size]());
memcpy(buf_data.get(), buf, size);
BlockContents bc = BlockContents(std::move(buf_data), size);
TBlocklike* ucd_ptr = BlocklikeTraits<TBlocklike>::Create(
std::move(bc), read_amp_bytes_per_bit, statistics, using_zstd,
filter_policy);
*out_obj = reinterpret_cast<void*>(ucd_ptr);
*charge = size;
return Status::OK();
};
}
template <>
class BlocklikeTraits<BlockContents> {
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<BlockContents*>(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<BlockContents*>(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*/) {
// E.g. compressed cache
return GetCacheItemHelperForRole<BlockContents,
CacheEntryRole::kOtherBlock>();
}
};
template <>
class BlocklikeTraits<ParsedFullFilterBlock> {
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<ParsedFullFilterBlock*>(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<ParsedFullFilterBlock*>(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<ParsedFullFilterBlock,
CacheEntryRole::kFilterBlock>();
}
};
template <>
class BlocklikeTraits<Block> {
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<Block*>(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<Block*>(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<Block, CacheEntryRole::kDataBlock>();
case BlockType::kIndex:
return GetCacheItemHelperForRole<Block, CacheEntryRole::kIndexBlock>();
case BlockType::kFilterPartitionIndex:
return GetCacheItemHelperForRole<Block,
CacheEntryRole::kFilterMetaBlock>();
default:
// Not a recognized combination
assert(false);
FALLTHROUGH_INTENDED;
case BlockType::kRangeDeletion:
return GetCacheItemHelperForRole<Block, CacheEntryRole::kOtherBlock>();
}
}
};
template <>
class BlocklikeTraits<UncompressionDict> {
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<UncompressionDict*>(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<UncompressionDict*>(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<UncompressionDict,
CacheEntryRole::kOtherBlock>();
}
};
// Get an CacheItemHelper pointer for value type T and role R.
template <typename T, CacheEntryRole R>
Cache::CacheItemHelper* GetCacheItemHelperForRole() {
static Cache::CacheItemHelper cache_helper(
BlocklikeTraits<T>::SizeCallback, BlocklikeTraits<T>::SaveToCallback,
GetCacheEntryDeleterForRole<T, R>());
return &cache_helper;
}
} // namespace ROCKSDB_NAMESPACE