block_cache.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright (c) Meta Platforms, Inc. and affiliates.
  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. // Code supporting block cache (Cache) access for block-based table, based on
  6. // the convenient APIs in typed_cache.h
  7. #pragma once
  8. #include <type_traits>
  9. #include "cache/typed_cache.h"
  10. #include "port/lang.h"
  11. #include "table/block_based/block.h"
  12. #include "table/block_based/block_type.h"
  13. #include "table/block_based/parsed_full_filter_block.h"
  14. #include "table/format.h"
  15. namespace ROCKSDB_NAMESPACE {
  16. // Metaprogramming wrappers for Block, to give each type a single role when
  17. // used with FullTypedCacheInterface.
  18. // (NOTE: previous attempts to create actual derived classes of Block with
  19. // virtual calls resulted in performance regression)
  20. class Block_kData : public Block {
  21. public:
  22. using Block::Block;
  23. static constexpr CacheEntryRole kCacheEntryRole = CacheEntryRole::kDataBlock;
  24. static constexpr BlockType kBlockType = BlockType::kData;
  25. };
  26. class Block_kIndex : public Block {
  27. public:
  28. using Block::Block;
  29. static constexpr CacheEntryRole kCacheEntryRole = CacheEntryRole::kIndexBlock;
  30. static constexpr BlockType kBlockType = BlockType::kIndex;
  31. };
  32. class Block_kFilterPartitionIndex : public Block {
  33. public:
  34. using Block::Block;
  35. static constexpr CacheEntryRole kCacheEntryRole =
  36. CacheEntryRole::kFilterMetaBlock;
  37. static constexpr BlockType kBlockType = BlockType::kFilterPartitionIndex;
  38. };
  39. class Block_kRangeDeletion : public Block {
  40. public:
  41. using Block::Block;
  42. static constexpr CacheEntryRole kCacheEntryRole = CacheEntryRole::kOtherBlock;
  43. static constexpr BlockType kBlockType = BlockType::kRangeDeletion;
  44. };
  45. // Useful for creating the Block even though meta index blocks are not
  46. // yet stored in block cache
  47. class Block_kMetaIndex : public Block {
  48. public:
  49. using Block::Block;
  50. static constexpr CacheEntryRole kCacheEntryRole = CacheEntryRole::kOtherBlock;
  51. static constexpr BlockType kBlockType = BlockType::kMetaIndex;
  52. };
  53. class Block_kUserDefinedIndex : public BlockContents {
  54. public:
  55. static constexpr CacheEntryRole kCacheEntryRole = CacheEntryRole::kIndexBlock;
  56. static constexpr BlockType kBlockType = BlockType::kUserDefinedIndex;
  57. explicit Block_kUserDefinedIndex(BlockContents&& other)
  58. : BlockContents(std::move(other)) {}
  59. const Slice& ContentSlice() const { return data; }
  60. };
  61. struct BlockCreateContext : public Cache::CreateContext {
  62. BlockCreateContext() {}
  63. BlockCreateContext(const BlockBasedTableOptions* _table_options,
  64. const ImmutableOptions* _ioptions, Statistics* _statistics,
  65. Decompressor* _decompressor,
  66. uint8_t _protection_bytes_per_key,
  67. const Comparator* _raw_ucmp,
  68. bool _index_value_is_full = false,
  69. bool _index_has_first_key = false)
  70. : table_options(_table_options),
  71. ioptions(_ioptions),
  72. statistics(_statistics),
  73. decompressor(_decompressor),
  74. raw_ucmp(_raw_ucmp),
  75. protection_bytes_per_key(_protection_bytes_per_key),
  76. index_value_is_full(_index_value_is_full),
  77. index_has_first_key(_index_has_first_key) {}
  78. const BlockBasedTableOptions* table_options = nullptr;
  79. const ImmutableOptions* ioptions = nullptr;
  80. Statistics* statistics = nullptr;
  81. // TODO: refactor to avoid copying BlockCreateContext for dict in block cache
  82. Decompressor* decompressor = nullptr;
  83. const Comparator* raw_ucmp = nullptr;
  84. uint8_t protection_bytes_per_key = 0;
  85. bool index_value_is_full;
  86. bool index_has_first_key;
  87. // For TypedCacheInterface
  88. template <typename TBlocklike>
  89. inline void Create(std::unique_ptr<TBlocklike>* parsed_out,
  90. size_t* charge_out, const Slice& data,
  91. CompressionType type, MemoryAllocator* alloc) {
  92. BlockContents uncompressed_block_contents;
  93. if (type != CompressionType::kNoCompression) {
  94. assert(decompressor != nullptr);
  95. Status s =
  96. DecompressBlockData(data.data(), data.size(), type, *decompressor,
  97. &uncompressed_block_contents, *ioptions, alloc);
  98. if (!s.ok()) {
  99. parsed_out->reset();
  100. return;
  101. }
  102. } else {
  103. uncompressed_block_contents =
  104. BlockContents(AllocateAndCopyBlock(data, alloc), data.size());
  105. }
  106. Create(parsed_out, std::move(uncompressed_block_contents));
  107. *charge_out = parsed_out->get()->ApproximateMemoryUsage();
  108. }
  109. void Create(std::unique_ptr<Block_kData>* parsed_out, BlockContents&& block);
  110. void Create(std::unique_ptr<Block_kIndex>* parsed_out, BlockContents&& block);
  111. void Create(std::unique_ptr<Block_kFilterPartitionIndex>* parsed_out,
  112. BlockContents&& block);
  113. void Create(std::unique_ptr<Block_kRangeDeletion>* parsed_out,
  114. BlockContents&& block);
  115. void Create(std::unique_ptr<Block_kMetaIndex>* parsed_out,
  116. BlockContents&& block);
  117. void Create(std::unique_ptr<Block_kUserDefinedIndex>* parsed_out,
  118. BlockContents&& block);
  119. void Create(std::unique_ptr<ParsedFullFilterBlock>* parsed_out,
  120. BlockContents&& block);
  121. void Create(std::unique_ptr<DecompressorDict>* parsed_out,
  122. BlockContents&& block);
  123. };
  124. // Convenient cache interface to use for block_cache, with support for
  125. // SecondaryCache.
  126. template <typename TBlocklike>
  127. using BlockCacheInterface =
  128. FullTypedCacheInterface<TBlocklike, BlockCreateContext>;
  129. // Shortcut name for cache handles under BlockCacheInterface
  130. template <typename TBlocklike>
  131. using BlockCacheTypedHandle =
  132. typename BlockCacheInterface<TBlocklike>::TypedHandle;
  133. // Selects the right helper based on BlockType and CacheTier
  134. const Cache::CacheItemHelper* GetCacheItemHelper(
  135. BlockType block_type,
  136. CacheTier lowest_used_cache_tier = CacheTier::kNonVolatileBlockTier);
  137. // For SFINAE check that a type is "blocklike" with a kCacheEntryRole member.
  138. // Can get difficult compiler/linker errors without a good check like this.
  139. template <typename TUse, typename TBlocklike>
  140. using WithBlocklikeCheck = std::enable_if_t<
  141. TBlocklike::kCacheEntryRole == CacheEntryRole::kMisc || true, TUse>;
  142. // Helper for the uncache_aggressiveness option
  143. class UncacheAggressivenessAdvisor {
  144. public:
  145. UncacheAggressivenessAdvisor(uint32_t uncache_aggressiveness) {
  146. assert(uncache_aggressiveness > 0);
  147. allowance_ = std::min(uncache_aggressiveness, uint32_t{3});
  148. threshold_ = std::pow(0.99, uncache_aggressiveness - 1);
  149. }
  150. void Report(bool erased) { ++(erased ? useful_ : not_useful_); }
  151. bool ShouldContinue() {
  152. if (not_useful_ < allowance_) {
  153. return true;
  154. } else {
  155. // See UncacheAggressivenessAdvisor unit test
  156. return (useful_ + 1.0) / (useful_ + not_useful_ - allowance_ + 1.5) >=
  157. threshold_;
  158. }
  159. }
  160. private:
  161. // Baseline minimum number of "not useful" to consider stopping, to allow
  162. // sufficient evidence for checking the threshold. Actual minimum will be
  163. // higher as threshold gets well below 1.0.
  164. int allowance_;
  165. // After allowance, stop if useful ratio is below this threshold
  166. double threshold_;
  167. // Counts
  168. int useful_ = 0;
  169. int not_useful_ = 0;
  170. };
  171. } // namespace ROCKSDB_NAMESPACE