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
128 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
129 ~CachingComponentBase()
override;
137 utils::SharedReadablePtr<T>
Get()
const;
144 template <
class Class>
146 Class* obj, std::string name,
147 void (Class::*func)(
const std::shared_ptr<
const T>&));
152 static yaml_config::Schema GetStaticConfigSchema();
160 void Set(std::unique_ptr<
const T> value_ptr);
166 template <
typename... Args>
167 void Emplace(Args&&... args);
181 virtual std::unique_ptr<
const T> ReadContents(dump::Reader& reader)
const;
188 const T* new_value_ptr)
const;
191 void OnAllComponentsLoaded()
final;
193 void Cleanup()
final;
195 void MarkAsExpired()
final;
197 void GetAndWrite(
dump::
Writer& writer)
const final;
200 rcu::Variable<std::shared_ptr<
const T>> cache_;
202 utils::impl::WaitTokenStorage wait_token_storage_;
207 const ComponentContext& context)
211 [
this](
auto& function) {
212 const auto ptr = cache_.ReadCopy();
213 if (ptr) function(ptr);
215 const auto initial_config = GetConfig();
221 cache_.Assign(
nullptr);
224 wait_token_storage_.WaitForAllTokens();
231 throw cache::EmptyCacheError(
Name());
237template <
typename Class>
239 Class* obj, std::string name,
240 void (Class::*func)(
const std::shared_ptr<
const T>&)) {
241 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
250 return event_channel_;
255 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
260 auto deleter = [token = wait_token_storage_.GetToken(),
261 &cache_task_processor =
262 GetCacheTaskProcessor()](
const T* raw_ptr)
mutable {
263 std::unique_ptr<
const T> ptr{raw_ptr};
266 engine::CriticalAsyncNoSpan(cache_task_processor, [ptr = std::move(ptr),
274 const std::shared_ptr<
const T> new_value(value_ptr.release(),
277 if (HasPreAssignCheck()) {
278 auto old_value = cache_.Read();
279 PreAssignCheck(old_value->get(), new_value.get());
282 cache_.Assign(new_value);
283 event_channel_.SendEvent(new_value);
289 Emplace(std::move(value));
293template <
typename... Args>
295 Set(std::make_unique<T>(std::forward<Args>(args)...)
);
300 cache_.Assign(std::make_unique<
const T>());
311 if (!contents)
throw cache::EmptyCacheError(
Name());
317 auto data = ReadContents(reader);
318 if constexpr (meta::kIsSizable<T>) {
320 SetDataSizeStatistic(std::size(*data));
323 Set(std::move(data));
328 const T& contents)
const {
329 if constexpr (
dump::kIsDumpable<T>) {
330 writer.Write(contents);
338 dump::Reader& reader)
const {
339 if constexpr (
dump::kIsDumpable<T>) {
341 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
349 AssertPeriodicUpdateStarted();
359 Set(std::unique_ptr<
const T>{});
364yaml_config::Schema GetCachingComponentBaseSchema();
370 return impl::GetCachingComponentBaseSchema();
375 const T*, [[
maybe_unused]]
const T* new_value_ptr)
const {
378 fmt::format(
"{} type does not support std::size(), add implementation of "
379 "the method size() for this type or "
380 "override cache::CachingComponentBase::PreAssignCheck.",
381 compiler::GetTypeName<T>()));
383 if constexpr (meta::kIsSizable<T>) {
384 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
385 throw cache::EmptyDataError(
Name());