10#include <fmt/format.h>
12#include <userver/cache/cache_update_trait.hpp>
13#include <userver/cache/data_provider.hpp>
14#include <userver/cache/exceptions.hpp>
15#include <userver/compiler/demangle.hpp>
16#include <userver/components/component_base.hpp>
17#include <userver/components/component_context.hpp>
18#include <userver/components/component_fwd.hpp>
19#include <userver/concurrent/async_event_channel.hpp>
20#include <userver/dump/helpers.hpp>
21#include <userver/dump/meta.hpp>
22#include <userver/dump/operations.hpp>
23#include <userver/engine/async.hpp>
24#include <userver/rcu/rcu.hpp>
25#include <userver/utils/assert.hpp>
26#include <userver/utils/impl/wait_token_storage.hpp>
27#include <userver/utils/meta.hpp>
28#include <userver/utils/shared_readable_ptr.hpp>
29#include <userver/yaml_config/schema.hpp>
31USERVER_NAMESPACE_BEGIN
137 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
138 ~CachingComponentBase()
override;
150 utils::SharedReadablePtr<T>
Get()
const final;
157 template <
class Class>
161 void (Class::*func)(
const std::shared_ptr<
const T>&)
164 concurrent::
AsyncEventChannel<
const std::shared_ptr<
const T>&>& GetEventChannel();
166 static yaml_config::Schema GetStaticConfigSchema();
174 void Set(std::unique_ptr<
const T> value_ptr);
185 void Attach(
const std::shared_ptr<
const T>& value_ptr);
188 template <
typename... Args>
189 void Emplace(Args&&... args);
201 virtual std::unique_ptr<
const T> ReadContents(dump::
Reader& reader)
const;
207 virtual void PreAssignCheck(
const T* old_value_ptr,
const T* new_value_ptr)
const;
210 void Cleanup()
final;
212 void MarkAsExpired()
final;
214 void GetAndWrite(dump::
Writer& writer)
const final;
215 void ReadAndSet(dump::
Reader& reader)
final;
217 std::shared_ptr<
const T> TransformNewValue(std::unique_ptr<
const T> new_value);
219 rcu::Variable<std::shared_ptr<
const T>> cache_;
221 utils::impl::WaitTokenStorage wait_token_storage_;
225CachingComponentBase<T>::CachingComponentBase(
const ComponentConfig& config,
const ComponentContext& context)
226 : ComponentBase(config, context),
229 components::GetCurrentComponentName(context),
230 [
this](
const auto& function) {
231 const auto ptr = cache_.ReadCopy();
242 cache_.Assign(
nullptr);
245 wait_token_storage_.WaitForAllTokens();
252 throw cache::EmptyCacheError(
Name());
258template <
typename Class>
260 T>::
UpdateAndListen(Class* obj, std::string name,
void (Class::*func)(
const std::shared_ptr<
const T>&)) {
261 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
269 return event_channel_;
274 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
279 Attach(TransformNewValue(std::move(value_ptr))
);
284 Emplace(std::move(value));
289 if (HasPreAssignCheck()) {
290 auto old_value = cache_.Read();
294 cache_.Assign(new_value);
295 event_channel_.SendEvent(new_value);
300template <
typename... Args>
302 Set(std::make_unique<T>(std::forward<Args>(args)...));
307 cache_.Assign(std::make_unique<
const T>());
319 throw cache::EmptyCacheError(
Name());
326 auto data = ReadContents(reader);
327 if constexpr (meta::kIsSizable<T>) {
329 SetDataSizeStatistic(std::size(*data));
332 Set(std::move(data));
337 if constexpr (dump::kIsDumpable<T>) {
338 writer.Write(contents);
340 dump::ThrowDumpUnimplemented(
Name());
346 if constexpr (dump::kIsDumpable<T>) {
348 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
350 dump::ThrowDumpUnimplemented(
Name());
361 Set(std::unique_ptr<
const T>{});
366yaml_config::Schema GetCachingComponentBaseSchema();
368template <
typename T,
typename Deleter>
369auto MakeAsyncDeleter(engine::TaskProcessor& task_processor, Deleter deleter) {
370 return [&task_processor, deleter = std::move(deleter)](
const T* raw_ptr)
mutable {
371 std::unique_ptr<
const T, Deleter> ptr(raw_ptr, std::move(deleter));
373 engine::DetachUnscopedUnsafe(engine::CriticalAsyncNoSpan(task_processor, [ptr = std::move(ptr)]()
mutable {}));
381 return impl::GetCachingComponentBaseSchema();
389 "{} type does not support std::size(), add implementation of "
390 "the method size() for this type or "
391 "override cache::CachingComponentBase::PreAssignCheck.",
392 compiler::GetTypeName<T>()
396 if constexpr (meta::kIsSizable<T>) {
397 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
398 throw cache::EmptyDataError(
Name());
404std::shared_ptr<
const T>
CachingComponentBase<T>::TransformNewValue(std::unique_ptr<
const T> new_value) {
406 if (IsSafeDataLifetime()) {
408 auto deleter_with_token = [token = wait_token_storage_.GetToken()](
const T* raw_ptr) {
410 std::default_delete<
const T>{}(raw_ptr);
412 return std::shared_ptr<
const T>(
414 impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(), std::move(deleter_with_token))
417 return std::shared_ptr<
const T>(
419 impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(), std::default_delete<
const T>{})