1 //  Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #pragma once
7 
8 #include "cache/cache_entry_roles.h"
9 #include "port/lang.h"
10 #include "table/block_based/block.h"
11 #include "table/block_based/block_type.h"
12 #include "table/block_based/parsed_full_filter_block.h"
13 #include "table/format.h"
14 
15 namespace ROCKSDB_NAMESPACE {
16 
17 template <typename TBlocklike>
18 class BlocklikeTraits;
19 
20 template <typename T, CacheEntryRole R>
21 Cache::CacheItemHelper* GetCacheItemHelperForRole();
22 
23 template <typename TBlocklike>
GetCreateCallback(size_t read_amp_bytes_per_bit,Statistics * statistics,bool using_zstd,const FilterPolicy * filter_policy)24 Cache::CreateCallback GetCreateCallback(size_t read_amp_bytes_per_bit,
25                                         Statistics* statistics, bool using_zstd,
26                                         const FilterPolicy* filter_policy) {
27   return [read_amp_bytes_per_bit, statistics, using_zstd, filter_policy](
28              void* buf, size_t size, void** out_obj, size_t* charge) -> Status {
29     assert(buf != nullptr);
30     std::unique_ptr<char[]> buf_data(new char[size]());
31     memcpy(buf_data.get(), buf, size);
32     BlockContents bc = BlockContents(std::move(buf_data), size);
33     TBlocklike* ucd_ptr = BlocklikeTraits<TBlocklike>::Create(
34         std::move(bc), read_amp_bytes_per_bit, statistics, using_zstd,
35         filter_policy);
36     *out_obj = reinterpret_cast<void*>(ucd_ptr);
37     *charge = size;
38     return Status::OK();
39   };
40 }
41 
42 template <>
43 class BlocklikeTraits<BlockContents> {
44  public:
Create(BlockContents && contents,size_t,Statistics *,bool,const FilterPolicy *)45   static BlockContents* Create(BlockContents&& contents,
46                                size_t /* read_amp_bytes_per_bit */,
47                                Statistics* /* statistics */,
48                                bool /* using_zstd */,
49                                const FilterPolicy* /* filter_policy */) {
50     return new BlockContents(std::move(contents));
51   }
52 
GetNumRestarts(const BlockContents &)53   static uint32_t GetNumRestarts(const BlockContents& /* contents */) {
54     return 0;
55   }
56 
SizeCallback(void * obj)57   static size_t SizeCallback(void* obj) {
58     assert(obj != nullptr);
59     BlockContents* ptr = static_cast<BlockContents*>(obj);
60     return ptr->data.size();
61   }
62 
SaveToCallback(void * from_obj,size_t from_offset,size_t length,void * out)63   static Status SaveToCallback(void* from_obj, size_t from_offset,
64                                size_t length, void* out) {
65     assert(from_obj != nullptr);
66     BlockContents* ptr = static_cast<BlockContents*>(from_obj);
67     const char* buf = ptr->data.data();
68     assert(length == ptr->data.size());
69     (void)from_offset;
70     memcpy(out, buf, length);
71     return Status::OK();
72   }
73 
GetCacheItemHelper(BlockType block_type)74   static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) {
75     if (block_type == BlockType::kFilter) {
76       return GetCacheItemHelperForRole<
77           BlockContents, CacheEntryRole::kDeprecatedFilterBlock>();
78     } else {
79       // E.g. compressed cache
80       return GetCacheItemHelperForRole<BlockContents,
81                                        CacheEntryRole::kOtherBlock>();
82     }
83   }
84 };
85 
86 template <>
87 class BlocklikeTraits<ParsedFullFilterBlock> {
88  public:
Create(BlockContents && contents,size_t,Statistics *,bool,const FilterPolicy * filter_policy)89   static ParsedFullFilterBlock* Create(BlockContents&& contents,
90                                        size_t /* read_amp_bytes_per_bit */,
91                                        Statistics* /* statistics */,
92                                        bool /* using_zstd */,
93                                        const FilterPolicy* filter_policy) {
94     return new ParsedFullFilterBlock(filter_policy, std::move(contents));
95   }
96 
GetNumRestarts(const ParsedFullFilterBlock &)97   static uint32_t GetNumRestarts(const ParsedFullFilterBlock& /* block */) {
98     return 0;
99   }
100 
SizeCallback(void * obj)101   static size_t SizeCallback(void* obj) {
102     assert(obj != nullptr);
103     ParsedFullFilterBlock* ptr = static_cast<ParsedFullFilterBlock*>(obj);
104     return ptr->GetBlockContentsData().size();
105   }
106 
SaveToCallback(void * from_obj,size_t from_offset,size_t length,void * out)107   static Status SaveToCallback(void* from_obj, size_t from_offset,
108                                size_t length, void* out) {
109     assert(from_obj != nullptr);
110     ParsedFullFilterBlock* ptr = static_cast<ParsedFullFilterBlock*>(from_obj);
111     const char* buf = ptr->GetBlockContentsData().data();
112     assert(length == ptr->GetBlockContentsData().size());
113     (void)from_offset;
114     memcpy(out, buf, length);
115     return Status::OK();
116   }
117 
GetCacheItemHelper(BlockType block_type)118   static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) {
119     (void)block_type;
120     assert(block_type == BlockType::kFilter);
121     return GetCacheItemHelperForRole<ParsedFullFilterBlock,
122                                      CacheEntryRole::kFilterBlock>();
123   }
124 };
125 
126 template <>
127 class BlocklikeTraits<Block> {
128  public:
Create(BlockContents && contents,size_t read_amp_bytes_per_bit,Statistics * statistics,bool,const FilterPolicy *)129   static Block* Create(BlockContents&& contents, size_t read_amp_bytes_per_bit,
130                        Statistics* statistics, bool /* using_zstd */,
131                        const FilterPolicy* /* filter_policy */) {
132     return new Block(std::move(contents), read_amp_bytes_per_bit, statistics);
133   }
134 
GetNumRestarts(const Block & block)135   static uint32_t GetNumRestarts(const Block& block) {
136     return block.NumRestarts();
137   }
138 
SizeCallback(void * obj)139   static size_t SizeCallback(void* obj) {
140     assert(obj != nullptr);
141     Block* ptr = static_cast<Block*>(obj);
142     return ptr->size();
143   }
144 
SaveToCallback(void * from_obj,size_t from_offset,size_t length,void * out)145   static Status SaveToCallback(void* from_obj, size_t from_offset,
146                                size_t length, void* out) {
147     assert(from_obj != nullptr);
148     Block* ptr = static_cast<Block*>(from_obj);
149     const char* buf = ptr->data();
150     assert(length == ptr->size());
151     (void)from_offset;
152     memcpy(out, buf, length);
153     return Status::OK();
154   }
155 
GetCacheItemHelper(BlockType block_type)156   static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) {
157     switch (block_type) {
158       case BlockType::kData:
159         return GetCacheItemHelperForRole<Block, CacheEntryRole::kDataBlock>();
160       case BlockType::kIndex:
161         return GetCacheItemHelperForRole<Block, CacheEntryRole::kIndexBlock>();
162       case BlockType::kFilter:
163         return GetCacheItemHelperForRole<Block,
164                                          CacheEntryRole::kFilterMetaBlock>();
165       default:
166         // Not a recognized combination
167         assert(false);
168         FALLTHROUGH_INTENDED;
169       case BlockType::kRangeDeletion:
170         return GetCacheItemHelperForRole<Block, CacheEntryRole::kOtherBlock>();
171     }
172   }
173 };
174 
175 template <>
176 class BlocklikeTraits<UncompressionDict> {
177  public:
Create(BlockContents && contents,size_t,Statistics *,bool using_zstd,const FilterPolicy *)178   static UncompressionDict* Create(BlockContents&& contents,
179                                    size_t /* read_amp_bytes_per_bit */,
180                                    Statistics* /* statistics */,
181                                    bool using_zstd,
182                                    const FilterPolicy* /* filter_policy */) {
183     return new UncompressionDict(contents.data, std::move(contents.allocation),
184                                  using_zstd);
185   }
186 
GetNumRestarts(const UncompressionDict &)187   static uint32_t GetNumRestarts(const UncompressionDict& /* dict */) {
188     return 0;
189   }
190 
SizeCallback(void * obj)191   static size_t SizeCallback(void* obj) {
192     assert(obj != nullptr);
193     UncompressionDict* ptr = static_cast<UncompressionDict*>(obj);
194     return ptr->slice_.size();
195   }
196 
SaveToCallback(void * from_obj,size_t from_offset,size_t length,void * out)197   static Status SaveToCallback(void* from_obj, size_t from_offset,
198                                size_t length, void* out) {
199     assert(from_obj != nullptr);
200     UncompressionDict* ptr = static_cast<UncompressionDict*>(from_obj);
201     const char* buf = ptr->slice_.data();
202     assert(length == ptr->slice_.size());
203     (void)from_offset;
204     memcpy(out, buf, length);
205     return Status::OK();
206   }
207 
GetCacheItemHelper(BlockType block_type)208   static Cache::CacheItemHelper* GetCacheItemHelper(BlockType block_type) {
209     (void)block_type;
210     assert(block_type == BlockType::kCompressionDictionary);
211     return GetCacheItemHelperForRole<UncompressionDict,
212                                      CacheEntryRole::kOtherBlock>();
213   }
214 };
215 
216 // Get an CacheItemHelper pointer for value type T and role R.
217 template <typename T, CacheEntryRole R>
GetCacheItemHelperForRole()218 Cache::CacheItemHelper* GetCacheItemHelperForRole() {
219   static Cache::CacheItemHelper cache_helper(
220       BlocklikeTraits<T>::SizeCallback, BlocklikeTraits<T>::SaveToCallback,
221       GetCacheEntryDeleterForRole<T, R>());
222   return &cache_helper;
223 }
224 
225 }  // namespace ROCKSDB_NAMESPACE
226