Coverage Report

Created: 2026-04-10 07:52

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