10#include <fmt/format.h>
12#include <userver/cache/cache_update_trait.hpp>
13#include <userver/cache/exceptions.hpp>
14#include <userver/compiler/demangle.hpp>
15#include <userver/components/component_fwd.hpp>
16#include <userver/components/loggable_component_base.hpp>
17#include <userver/concurrent/async_event_channel.hpp>
18#include <userver/dump/helpers.hpp>
19#include <userver/dump/meta.hpp>
20#include <userver/dump/operations.hpp>
21#include <userver/engine/async.hpp>
22#include <userver/rcu/rcu.hpp>
23#include <userver/utils/assert.hpp>
24#include <userver/utils/impl/wait_token_storage.hpp>
25#include <userver/utils/meta.hpp>
26#include <userver/utils/shared_readable_ptr.hpp>
27#include <userver/yaml_config/schema.hpp>
29USERVER_NAMESPACE_BEGIN
105 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
106 ~CachingComponentBase()
override;
121 template <
class Class>
123 Class* obj, std::string name,
124 void (Class::*func)(
const std::shared_ptr<
const T>&));
129 static yaml_config::Schema GetStaticConfigSchema();
132 void Set(std::unique_ptr<
const T> value_ptr);
135 template <
typename... Args>
136 void Emplace(Args&&... args);
149 virtual std::unique_ptr<
const T> ReadContents(dump::Reader& reader)
const;
153 void OnAllComponentsLoaded()
final;
155 void Cleanup()
final;
157 void MarkAsExpired()
final;
159 void GetAndWrite(
dump::
Writer& writer)
const final;
165 virtual void PreAssignCheck(
const T* old_value_ptr,
166 const T* new_value_ptr)
const;
168 rcu::Variable<std::shared_ptr<
const T>> cache_;
170 utils::impl::WaitTokenStorage wait_token_storage_;
175 const ComponentContext& context)
179 [
this](
auto& function) {
180 const auto ptr = cache_.ReadCopy();
181 if (ptr) function(ptr);
183 const auto initial_config = GetConfig();
189 cache_.Assign(
nullptr);
192 wait_token_storage_.WaitForAllTokens();
199 throw cache::EmptyCacheError(
Name());
205template <
typename Class>
207 Class* obj, std::string name,
208 void (Class::*func)(
const std::shared_ptr<
const T>&)) {
209 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
218 return event_channel_;
223 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
228 auto deleter = [token = wait_token_storage_.GetToken(),
229 &cache_task_processor =
230 GetCacheTaskProcessor()](
const T* raw_ptr)
mutable {
231 std::unique_ptr<
const T> ptr{raw_ptr};
234 engine::CriticalAsyncNoSpan(cache_task_processor, [ptr = std::move(ptr),
242 const std::shared_ptr<
const T> new_value(value_ptr.release(),
245 if (HasPreAssignCheck()) {
246 auto old_value = cache_.Read();
247 PreAssignCheck(old_value->get(), new_value.get());
250 cache_.Assign(new_value);
251 event_channel_.SendEvent(new_value);
257 Emplace(std::move(value));
261template <
typename... Args>
263 Set(std::make_unique<T>(std::forward<Args>(args)...));
268 cache_.Assign(std::make_unique<
const T>());
279 if (!contents)
throw cache::EmptyCacheError(
Name());
285 Set(ReadContents(reader));
290 const T& contents)
const {
291 if constexpr (
dump::kIsDumpable<T>) {
292 writer.Write(contents);
300 dump::Reader& reader)
const {
301 if constexpr (
dump::kIsDumpable<T>) {
303 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
311 AssertPeriodicUpdateStarted();
321 Set(std::unique_ptr<
const T>{});
326yaml_config::Schema GetCachingComponentBaseSchema();
332 return impl::GetCachingComponentBaseSchema();
337 const T*, [[maybe_unused]]
const T* new_value_ptr)
const {
340 fmt::format(
"{} type does not support std::size(), add implementation of "
341 "the method size() for this type or "
342 "override cache::CachingComponentBase::PreAssignCheck.",
343 compiler::GetTypeName<T>()));
345 if constexpr (meta::kIsSizable<T>) {
346 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
347 throw cache::EmptyDataError(
Name());