userver: userver/cache/lru_cache_component_base.hpp Source File
Loading...
Searching...
No Matches
lru_cache_component_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/cache/lru_cache_component_base.hpp
4/// @brief @copybrief cache::LruCacheComponent
5
6#include <functional>
7
8#include <userver/cache/expirable_lru_cache.hpp>
9#include <userver/cache/lru_cache_config.hpp>
10#include <userver/components/component_base.hpp>
11#include <userver/concurrent/async_event_source.hpp>
12#include <userver/dump/dumper.hpp>
13#include <userver/dump/meta.hpp>
14#include <userver/dump/operations.hpp>
15#include <userver/dynamic_config/source.hpp>
16#include <userver/logging/log.hpp>
17#include <userver/testsuite/cache_control.hpp>
18#include <userver/utils/statistics/entry.hpp>
19#include <userver/yaml_config/schema.hpp>
20
21USERVER_NAMESPACE_BEGIN
22
23namespace cache {
24
25namespace impl {
26
27void RegisterOnStatisticsStorage(
28 const components::ComponentContext& context,
29 const std::string& name,
30 std::function<void(utils::statistics::Writer&)> func
31);
32
33dynamic_config::Source FindDynamicConfigSource(const components::ComponentContext& context);
34
35bool IsDumpSupportEnabled(const components::ComponentConfig& config);
36
37yaml_config::Schema GetLruCacheComponentBaseSchema();
38
39} // namespace impl
40
41/// @ingroup userver_components userver_base_classes
42///
43/// @brief Base class for LRU-cache components
44///
45/// Provides facilities for creating LRU caches.
46/// You need to override LruCacheComponent::DoGetByKey to handle cache misses.
47///
48/// Caching components must be configured in service config (see options below)
49/// and may be reconfigured dynamically via components::DynamicConfig.
50///
51/// ## LruCacheComponent Dynamic config
52/// * @ref USERVER_LRU_CACHES
53///
54/// ## Static options of cache::LruCacheComponent :
55/// @include{doc} scripts/docs/en/components_schema/core/src/cache/lru_cache_component_base.md
56///
57/// Options inherited from @ref components::ComponentBase :
58/// @include{doc} scripts/docs/en/components_schema/core/src/components/impl/component_base.md
59///
60/// ## Example usage:
61///
62/// @snippet cache/lru_cache_component_base_test.hpp Sample lru cache component
63///
64/// Do not forget to @ref userver_components "add the component to component list":
65/// @snippet cache/lru_cache_component_base_test.cpp Sample lru cache component registration
66///
67/// ## Example config:
68/// @snippet cache/lru_cache_component_base_test.cpp Sample lru cache component config
69template <typename Key, typename Value, typename Hash = std::hash<Key>, typename Equal = std::equal_to<Key>>
70// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
71class LruCacheComponent : public components::ComponentBase, private dump::DumpableEntity {
72public:
73 using Cache = ExpirableLruCache<Key, Value, Hash, Equal>;
74 using CacheWrapper = LruCacheWrapper<Key, Value, Hash, Equal>;
75
76 LruCacheComponent(const components::ComponentConfig&, const components::ComponentContext&);
77
78 ~LruCacheComponent() override;
79
80 CacheWrapper GetCache();
81
82 static yaml_config::Schema GetStaticConfigSchema();
83
84protected:
85 virtual Value DoGetByKey(const Key& key) = 0;
86
87 std::shared_ptr<Cache> GetCacheRaw() { return cache_; }
88
89private:
90 void DropCache();
91
92 Value GetByKey(const Key& key);
93
94 void OnConfigUpdate(const dynamic_config::Snapshot& cfg);
95
96 void UpdateConfig(const LruCacheConfig& config);
97
98 static constexpr bool kCacheIsDumpable = dump::kIsDumpable<Key> && dump::kIsDumpable<Value>;
99
100 void GetAndWrite(dump::Writer& writer) const override;
101 void ReadAndSet(dump::Reader& reader) override;
102
103 const std::string name_;
104 const LruCacheConfigStatic static_config_;
105 std::shared_ptr<dump::Dumper> dumper_;
106 const std::shared_ptr<Cache> cache_;
107
108 // Subscriptions must be the last fields.
109 concurrent::AsyncEventSubscriberScope config_subscription_;
110 testsuite::CacheResetRegistration reset_registration_;
111 // See the comment above before adding a new field.
112};
113
114template <typename Key, typename Value, typename Hash, typename Equal>
116 Key,
117 Value,
118 Hash,
119 Equal>::LruCacheComponent(const components::ComponentConfig& config, const components::ComponentContext& context)
120 : ComponentBase(config, context),
121 name_(components::GetCurrentComponentName(context)),
122 static_config_(config),
123 cache_(std::make_shared<Cache>(static_config_.ways, static_config_.GetWaySize()))
124{
125 if (impl::IsDumpSupportEnabled(config)) {
126 dumper_ = std::make_shared<dump::Dumper>(config, context, static_cast<dump::DumpableEntity&>(*this));
127 cache_->SetDumper(dumper_);
128 dumper_->ReadDump();
129 }
130
131 cache_->SetMaxLifetime(static_config_.config.lifetime);
132 cache_->SetBackgroundUpdate(static_config_.config.background_update);
133
134 if (static_config_.use_dynamic_config) {
135 LOG_INFO()
136 << "Dynamic LRU cache config is enabled, subscribing on "
137 "dynamic-config updates, cache="
138 << name_;
139
140 config_subscription_ =
141 impl::FindDynamicConfigSource(context)
142 .UpdateAndListen(this, "cache." + name_, &LruCacheComponent::OnConfigUpdate);
143 } else {
144 LOG_INFO() << "Dynamic LRU cache config is disabled, cache=" << name_;
145 }
146
147 impl::RegisterOnStatisticsStorage(context, name_, [this](utils::statistics::Writer& writer) { writer = *cache_; });
148
149 reset_registration_ = testsuite::RegisterCache(context, this, &LruCacheComponent::DropCache);
150}
151
152template <typename Key, typename Value, typename Hash, typename Equal>
153LruCacheComponent<Key, Value, Hash, Equal>::~LruCacheComponent() {
154 reset_registration_.Unregister();
155 config_subscription_.Unsubscribe();
156
157 if (dumper_) {
158 dumper_->CancelWriteTaskAndWait();
159 }
160}
161
162template <typename Key, typename Value, typename Hash, typename Equal>
163typename LruCacheComponent<Key, Value, Hash, Equal>::CacheWrapper LruCacheComponent<
164 Key,
165 Value,
166 Hash,
167 Equal>::GetCache() {
168 return CacheWrapper(cache_, [this](const Key& key) { return GetByKey(key); });
169}
170
171template <typename Key, typename Value, typename Hash, typename Equal>
172void LruCacheComponent<Key, Value, Hash, Equal>::DropCache() {
173 cache_->Invalidate();
174}
175
176template <typename Key, typename Value, typename Hash, typename Equal>
177Value LruCacheComponent<Key, Value, Hash, Equal>::GetByKey(const Key& key) {
178 return DoGetByKey(key);
179}
180
181template <typename Key, typename Value, typename Hash, typename Equal>
182void LruCacheComponent<Key, Value, Hash, Equal>::OnConfigUpdate(const dynamic_config::Snapshot& cfg) {
183 const auto config = GetLruConfig(cfg, name_);
184 if (config) {
185 LOG_DEBUG() << "Using dynamic config for LRU cache";
186 UpdateConfig(*config);
187 } else {
188 LOG_DEBUG() << "Using static config for LRU cache";
189 UpdateConfig(static_config_.config);
190 }
191}
192
193template <typename Key, typename Value, typename Hash, typename Equal>
194void LruCacheComponent<Key, Value, Hash, Equal>::UpdateConfig(const LruCacheConfig& config) {
195 cache_->SetWaySize(config.GetWaySize(static_config_.ways));
196 cache_->SetMaxLifetime(config.lifetime);
197 cache_->SetBackgroundUpdate(config.background_update);
198}
199
200template <typename Key, typename Value, typename Hash, typename Equal>
201yaml_config::Schema LruCacheComponent<Key, Value, Hash, Equal>::GetStaticConfigSchema() {
202 return impl::GetLruCacheComponentBaseSchema();
203}
204
205template <typename Key, typename Value, typename Hash, typename Equal>
206void LruCacheComponent<Key, Value, Hash, Equal>::GetAndWrite(dump::Writer& writer) const {
207 if constexpr (kCacheIsDumpable) {
208 cache_->Write(writer);
209 } else {
210 dump::ThrowDumpUnimplemented(name_);
211 }
212}
213
214template <typename Key, typename Value, typename Hash, typename Equal>
215void LruCacheComponent<Key, Value, Hash, Equal>::ReadAndSet(dump::Reader& reader) {
216 if constexpr (kCacheIsDumpable) {
217 cache_->Read(reader);
218 } else {
219 dump::ThrowDumpUnimplemented(name_);
220 }
221}
222
223} // namespace cache
224
225USERVER_NAMESPACE_END