/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 |