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
27utils::statistics::Entry 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)
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 utils::statistics::Entry statistics_holder_;
111 testsuite::CacheResetRegistration reset_registration_;
112 // See the comment above before adding a new field.
113};
114
115template <typename Key, typename Value, typename Hash, typename Equal>
117 Key,
118 Value,
119 Hash,
120 Equal>::LruCacheComponent(const components::ComponentConfig& config, const components::ComponentContext& context)
121 : ComponentBase(config, context),
123 static_config_(config),
124 cache_(std::make_shared<Cache>(static_config_.ways, static_config_.GetWaySize()))
125{
126 if (impl::IsDumpSupportEnabled(config)) {
127 dumper_ = std::make_shared<dump::Dumper>(config, context, static_cast<dump::DumpableEntity&>(*this));
128 cache_->SetDumper(dumper_);
129 dumper_->ReadDump();
130 }
131
132 cache_->SetMaxLifetime(static_config_.config.lifetime);
133 cache_->SetBackgroundUpdate(static_config_.config.background_update);
134
135 if (static_config_.use_dynamic_config) {
136 LOG_INFO()
137 << "Dynamic LRU cache config is enabled, subscribing on "
138 "dynamic-config updates, cache="
139 << name_;
140
141 config_subscription_ =
142 impl::FindDynamicConfigSource(context)
143 .UpdateAndListen(this, "cache." + name_, &LruCacheComponent::OnConfigUpdate);
144 } else {
145 LOG_INFO() << "Dynamic LRU cache config is disabled, cache=" << name_;
146 }
147
148 statistics_holder_ = impl::RegisterOnStatisticsStorage(context, name_, [this](utils::statistics::Writer& writer) {
149 writer = *cache_;
150 });
151
152 reset_registration_ = testsuite::RegisterCache(context, this, &LruCacheComponent::DropCache);
153}
154
155template <typename Key, typename Value, typename Hash, typename Equal>
156LruCacheComponent<Key, Value, Hash, Equal>::~LruCacheComponent() {
157 reset_registration_.Unregister();
158 statistics_holder_.Unregister();
159 config_subscription_.Unsubscribe();
160
161 if (dumper_) {
163 }
164}
165
166template <typename Key, typename Value, typename Hash, typename Equal>
167typename LruCacheComponent<Key, Value, Hash, Equal>::CacheWrapper LruCacheComponent<
168 Key,
169 Value,
170 Hash,
171 Equal>::GetCache() {
172 return CacheWrapper(cache_, [this](const Key& key) { return GetByKey(key); });
173}
174
175template <typename Key, typename Value, typename Hash, typename Equal>
176void LruCacheComponent<Key, Value, Hash, Equal>::DropCache() {
177 cache_->Invalidate();
178}
179
180template <typename Key, typename Value, typename Hash, typename Equal>
181Value LruCacheComponent<Key, Value, Hash, Equal>::GetByKey(const Key& key) {
182 return DoGetByKey(key);
183}
184
185template <typename Key, typename Value, typename Hash, typename Equal>
186void LruCacheComponent<Key, Value, Hash, Equal>::OnConfigUpdate(const dynamic_config::Snapshot& cfg) {
187 const auto config = GetLruConfig(cfg, name_);
188 if (config) {
189 LOG_DEBUG() << "Using dynamic config for LRU cache";
190 UpdateConfig(*config);
191 } else {
192 LOG_DEBUG() << "Using static config for LRU cache";
193 UpdateConfig(static_config_.config);
194 }
195}
196
197template <typename Key, typename Value, typename Hash, typename Equal>
198void LruCacheComponent<Key, Value, Hash, Equal>::UpdateConfig(const LruCacheConfig& config) {
199 cache_->SetWaySize(config.GetWaySize(static_config_.ways));
200 cache_->SetMaxLifetime(config.lifetime);
201 cache_->SetBackgroundUpdate(config.background_update);
202}
203
204template <typename Key, typename Value, typename Hash, typename Equal>
205yaml_config::Schema LruCacheComponent<Key, Value, Hash, Equal>::GetStaticConfigSchema() {
206 return impl::GetLruCacheComponentBaseSchema();
207}
208
209template <typename Key, typename Value, typename Hash, typename Equal>
210void LruCacheComponent<Key, Value, Hash, Equal>::GetAndWrite(dump::Writer& writer) const {
211 if constexpr (kCacheIsDumpable) {
212 cache_->Write(writer);
213 } else {
214 dump::ThrowDumpUnimplemented(name_);
215 }
216}
217
218template <typename Key, typename Value, typename Hash, typename Equal>
219void LruCacheComponent<Key, Value, Hash, Equal>::ReadAndSet(dump::Reader& reader) {
220 if constexpr (kCacheIsDumpable) {
221 cache_->Read(reader);
222 } else {
223 dump::ThrowDumpUnimplemented(name_);
224 }
225}
226
227} // namespace cache
228
229USERVER_NAMESPACE_END