userver: userver/cache/lru_cache_component_base.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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/loggable_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, const std::string& name,
29 std::function<void(utils::statistics::Writer&)> func);
30
31dynamic_config::Source FindDynamicConfigSource(
32 const components::ComponentContext& context);
33
34bool IsDumpSupportEnabled(const components::ComponentConfig& config);
35
36yaml_config::Schema GetLruCacheComponentBaseSchema();
37
38} // namespace impl
39
40// clang-format off
41
42/// @ingroup userver_components userver_base_classes
43///
44/// @brief Base class for LRU-cache components
45///
46/// Provides facilities for creating LRU caches.
47/// You need to override LruCacheComponent::DoGetByKey to handle cache misses.
48///
49/// Caching components must be configured in service config (see options below)
50/// and may be reconfigured dynamically via components::DynamicConfig.
51///
52/// ## Dynamic config
53/// * @ref USERVER_LRU_CACHES
54///
55/// ## Static options:
56/// Name | Description | Default value
57/// ---- | ----------- | -------------
58/// size | max amount of items to store in cache | --
59/// ways | number of ways for associative cache | --
60/// lifetime | TTL for cache entries (0 is unlimited) | 0
61/// config-settings | enables dynamic reconfiguration with CacheConfigSet | true
62///
63/// ## Example usage:
64///
65/// @snippet cache/lru_cache_component_base_test.hpp Sample lru cache component
66///
67/// Do not forget to @ref userver_components "add the component to component list":
68/// @snippet cache/lru_cache_component_base_test.cpp Sample lru cache component registration
69///
70/// ## Example config:
71/// @snippet cache/lru_cache_component_base_test.cpp Sample lru cache component config
72
73// clang-format on
74template <typename Key, typename Value, typename Hash = std::hash<Key>,
75 typename Equal = std::equal_to<Key>>
76// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
78 private dump::DumpableEntity {
79 public:
80 using Cache = ExpirableLruCache<Key, Value, Hash, Equal>;
81 using CacheWrapper = LruCacheWrapper<Key, Value, Hash, Equal>;
82
83 LruCacheComponent(const components::ComponentConfig&,
84 const components::ComponentContext&);
85
86 ~LruCacheComponent() override;
87
88 CacheWrapper GetCache();
89
90 static yaml_config::Schema GetStaticConfigSchema();
91
92 protected:
93 virtual Value DoGetByKey(const Key& key) = 0;
94
95 std::shared_ptr<Cache> GetCacheRaw() { return cache_; }
96
97 private:
98 void DropCache();
99
100 Value GetByKey(const Key& key);
101
102 void OnConfigUpdate(const dynamic_config::Snapshot& cfg);
103
104 void UpdateConfig(const LruCacheConfig& config);
105
106 static constexpr bool kCacheIsDumpable =
107 dump::kIsDumpable<Key> && dump::kIsDumpable<Value>;
108
109 void GetAndWrite(dump::Writer& writer) const override;
110 void ReadAndSet(dump::Reader& reader) override;
111
112 const std::string name_;
113 const LruCacheConfigStatic static_config_;
114 std::shared_ptr<dump::Dumper> dumper_;
115 const std::shared_ptr<Cache> cache_;
116
117 // Subscriptions must be the last fields.
118 concurrent::AsyncEventSubscriberScope config_subscription_;
119 utils::statistics::Entry statistics_holder_;
120 testsuite::CacheResetRegistration reset_registration_;
121 // See the comment above before adding a new field.
122};
123
124template <typename Key, typename Value, typename Hash, typename Equal>
125LruCacheComponent<Key, Value, Hash, Equal>::LruCacheComponent(
126 const components::ComponentConfig& config,
127 const components::ComponentContext& context)
128 : LoggableComponentBase(config, context),
130 static_config_(config),
131 cache_(std::make_shared<Cache>(static_config_.ways,
132 static_config_.GetWaySize())) {
133 if (impl::IsDumpSupportEnabled(config)) {
134 dumper_ = std::make_shared<dump::Dumper>(
135 config, context, static_cast<dump::DumpableEntity&>(*this));
136 cache_->SetDumper(dumper_);
137 dumper_->ReadDump();
138 }
139
140 cache_->SetMaxLifetime(static_config_.config.lifetime);
141 cache_->SetBackgroundUpdate(static_config_.config.background_update);
142
143 if (static_config_.use_dynamic_config) {
144 LOG_INFO() << "Dynamic LRU cache config is enabled, subscribing on "
145 "dynamic-config updates, cache="
146 << name_;
147
148 config_subscription_ =
149 impl::FindDynamicConfigSource(context).UpdateAndListen(
150 this, "cache." + name_, &LruCacheComponent::OnConfigUpdate);
151 } else {
152 LOG_INFO() << "Dynamic LRU cache config is disabled, cache=" << name_;
153 }
154
155 statistics_holder_ = impl::RegisterOnStatisticsStorage(
156 context, name_,
157 [this](utils::statistics::Writer& writer) { writer = *cache_; });
158
159 reset_registration_ = testsuite::RegisterCache(config, context, this,
160 &LruCacheComponent::DropCache);
161}
162
163template <typename Key, typename Value, typename Hash, typename Equal>
164LruCacheComponent<Key, Value, Hash, Equal>::~LruCacheComponent() {
165 reset_registration_.Unregister();
166 statistics_holder_.Unregister();
167 config_subscription_.Unsubscribe();
168
169 if (dumper_) {
170 dumper_->CancelWriteTaskAndWait();
171 }
172}
173
174template <typename Key, typename Value, typename Hash, typename Equal>
175typename LruCacheComponent<Key, Value, Hash, Equal>::CacheWrapper
176LruCacheComponent<Key, Value, Hash, Equal>::GetCache() {
177 return CacheWrapper(cache_, [this](const Key& key) { return GetByKey(key); });
178}
179
180template <typename Key, typename Value, typename Hash, typename Equal>
181void LruCacheComponent<Key, Value, Hash, Equal>::DropCache() {
182 cache_->Invalidate();
183}
184
185template <typename Key, typename Value, typename Hash, typename Equal>
186Value LruCacheComponent<Key, Value, Hash, Equal>::GetByKey(const Key& key) {
187 return DoGetByKey(key);
188}
189
190template <typename Key, typename Value, typename Hash, typename Equal>
191void LruCacheComponent<Key, Value, Hash, Equal>::OnConfigUpdate(
192 const dynamic_config::Snapshot& cfg) {
193 const auto config = GetLruConfig(cfg, name_);
194 if (config) {
195 LOG_DEBUG() << "Using dynamic config for LRU cache";
196 UpdateConfig(*config);
197 } else {
198 LOG_DEBUG() << "Using static config for LRU cache";
199 UpdateConfig(static_config_.config);
200 }
201}
202
203template <typename Key, typename Value, typename Hash, typename Equal>
204void LruCacheComponent<Key, Value, Hash, Equal>::UpdateConfig(
205 const LruCacheConfig& config) {
206 cache_->SetWaySize(config.GetWaySize(static_config_.ways));
207 cache_->SetMaxLifetime(config.lifetime);
208 cache_->SetBackgroundUpdate(config.background_update);
209}
210
211template <typename Key, typename Value, typename Hash, typename Equal>
212yaml_config::Schema
213LruCacheComponent<Key, Value, Hash, Equal>::GetStaticConfigSchema() {
214 return impl::GetLruCacheComponentBaseSchema();
215}
216
217template <typename Key, typename Value, typename Hash, typename Equal>
218void LruCacheComponent<Key, Value, Hash, Equal>::GetAndWrite(
219 dump::Writer& writer) const {
220 if constexpr (kCacheIsDumpable) {
221 cache_->Write(writer);
222 } else {
223 dump::ThrowDumpUnimplemented(name_);
224 }
225}
226
227template <typename Key, typename Value, typename Hash, typename Equal>
228void LruCacheComponent<Key, Value, Hash, Equal>::ReadAndSet(
229 dump::Reader& reader) {
230 if constexpr (kCacheIsDumpable) {
231 cache_->Read(reader);
232 } else {
233 dump::ThrowDumpUnimplemented(name_);
234 }
235}
236
237} // namespace cache
238
239USERVER_NAMESPACE_END