tiered_secondary_cache.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. #pragma once
  6. #include "rocksdb/cache.h"
  7. #include "rocksdb/secondary_cache.h"
  8. namespace ROCKSDB_NAMESPACE {
  9. // A SecondaryCache that implements stacking of a compressed secondary cache
  10. // and a non-volatile (local flash) cache. It implements an admission
  11. // policy of warming the bottommost tier (local flash) with compressed
  12. // blocks from the SST on misses, and on hits in the bottommost tier,
  13. // promoting to the compressed and/or primary block cache. The admission
  14. // policies of the primary block cache and compressed secondary cache remain
  15. // unchanged - promote on second access. There is no demotion ofablocks
  16. // evicted from a tier. They are just discarded.
  17. //
  18. // In order to properly handle compressed blocks directly read from SSTs, and
  19. // to allow writeback of blocks compressed by the compressed secondary
  20. // cache in the future, we make use of the compression type and source
  21. // cache tier arguments in InsertSaved.
  22. class TieredSecondaryCache : public SecondaryCacheWrapper {
  23. public:
  24. TieredSecondaryCache(std::shared_ptr<SecondaryCache> comp_sec_cache,
  25. std::shared_ptr<SecondaryCache> nvm_sec_cache,
  26. TieredAdmissionPolicy adm_policy)
  27. : SecondaryCacheWrapper(comp_sec_cache), nvm_sec_cache_(nvm_sec_cache) {
  28. #ifndef NDEBUG
  29. assert(adm_policy == TieredAdmissionPolicy::kAdmPolicyThreeQueue);
  30. #else
  31. (void)adm_policy;
  32. #endif
  33. }
  34. ~TieredSecondaryCache() override {}
  35. const char* Name() const override { return "TieredSecondaryCache"; }
  36. // This is a no-op as we currently don't allow demotion (i.e
  37. // insertion by the upper layer) of evicted blocks.
  38. Status Insert(const Slice& /*key*/, Cache::ObjectPtr /*obj*/,
  39. const Cache::CacheItemHelper* /*helper*/,
  40. bool /*force_insert*/) override {
  41. return Status::OK();
  42. }
  43. // Warm up the nvm tier directly
  44. Status InsertSaved(const Slice& key, const Slice& saved,
  45. CompressionType type = CompressionType::kNoCompression,
  46. CacheTier source = CacheTier::kVolatileTier) override {
  47. return nvm_sec_cache_->InsertSaved(key, saved, type, source);
  48. }
  49. std::unique_ptr<SecondaryCacheResultHandle> Lookup(
  50. const Slice& key, const Cache::CacheItemHelper* helper,
  51. Cache::CreateContext* create_context, bool wait, bool advise_erase,
  52. Statistics* stats, bool& kept_in_sec_cache) override;
  53. void WaitAll(std::vector<SecondaryCacheResultHandle*> handles) override;
  54. private:
  55. struct CreateContext : public Cache::CreateContext {
  56. const Slice* key;
  57. bool advise_erase;
  58. const Cache::CacheItemHelper* helper;
  59. Cache::CreateContext* inner_ctx;
  60. std::shared_ptr<SecondaryCacheResultHandle> inner_handle;
  61. SecondaryCache* comp_sec_cache;
  62. Statistics* stats;
  63. };
  64. class ResultHandle : public SecondaryCacheResultHandle {
  65. public:
  66. ~ResultHandle() override {}
  67. bool IsReady() override {
  68. if (inner_handle_ && inner_handle_->IsReady()) {
  69. Complete();
  70. }
  71. return ready_;
  72. }
  73. void Wait() override {
  74. inner_handle_->Wait();
  75. Complete();
  76. }
  77. size_t Size() override { return size_; }
  78. Cache::ObjectPtr Value() override { return value_; }
  79. void Complete() {
  80. size_ = inner_handle_->Size();
  81. value_ = inner_handle_->Value();
  82. inner_handle_.reset();
  83. ready_ = true;
  84. }
  85. void SetInnerHandle(std::unique_ptr<SecondaryCacheResultHandle>&& handle) {
  86. inner_handle_ = std::move(handle);
  87. }
  88. void SetSize(size_t size) { size_ = size; }
  89. void SetValue(Cache::ObjectPtr val) { value_ = val; }
  90. CreateContext* ctx() { return &ctx_; }
  91. SecondaryCacheResultHandle* inner_handle() { return inner_handle_.get(); }
  92. private:
  93. std::unique_ptr<SecondaryCacheResultHandle> inner_handle_;
  94. CreateContext ctx_;
  95. size_t size_;
  96. Cache::ObjectPtr value_;
  97. bool ready_ = false;
  98. };
  99. static void NoopDelete(Cache::ObjectPtr /*obj*/,
  100. MemoryAllocator* /*allocator*/) {
  101. assert(false);
  102. }
  103. static size_t ZeroSize(Cache::ObjectPtr /*obj*/) {
  104. assert(false);
  105. return 0;
  106. }
  107. static Status NoopSaveTo(Cache::ObjectPtr /*from_obj*/,
  108. size_t /*from_offset*/, size_t /*length*/,
  109. char* /*out_buf*/) {
  110. assert(false);
  111. return Status::OK();
  112. }
  113. static Status MaybeInsertAndCreate(const Slice& data, CompressionType type,
  114. CacheTier source,
  115. Cache::CreateContext* ctx,
  116. MemoryAllocator* allocator,
  117. Cache::ObjectPtr* out_obj,
  118. size_t* out_charge);
  119. static const Cache::CacheItemHelper* GetHelper() {
  120. const static Cache::CacheItemHelper basic_helper(CacheEntryRole::kMisc,
  121. &NoopDelete);
  122. const static Cache::CacheItemHelper maybe_insert_and_create_helper{
  123. CacheEntryRole::kMisc, &NoopDelete, &ZeroSize,
  124. &NoopSaveTo, &MaybeInsertAndCreate, &basic_helper,
  125. };
  126. return &maybe_insert_and_create_helper;
  127. }
  128. std::shared_ptr<SecondaryCache> comp_sec_cache_;
  129. std::shared_ptr<SecondaryCache> nvm_sec_cache_;
  130. };
  131. } // namespace ROCKSDB_NAMESPACE