7#include <userver/cache/lru_map.hpp> 
    8#include <userver/dump/dumper.hpp> 
    9#include <userver/dump/operations.hpp> 
   10#include <userver/engine/mutex.hpp> 
   12USERVER_NAMESPACE_BEGIN
 
   17template <
typename T, 
typename U, 
typename Hash = std::hash<T>,
 
   18          typename Equal = std::equal_to<T>>
 
   21  NWayLRU(size_t ways, size_t way_size, 
const Hash& hash = Hash(),
 
   22          const Equal& equal = Equal());
 
   24  void Put(
const T& key, U value);
 
   26  template <
typename Validator>
 
   27  std::optional<U> Get(
const T& key, Validator validator);
 
   29  std::optional<U> Get(
const T& key) {
 
   30    return Get(key, [](
const U&) { 
return true; });
 
   33  U GetOr(
const T& key, 
const U& default_value);
 
   37  void InvalidateByKey(
const T& key);
 
   40  template <
typename Function>
 
   43  size_t GetSize() 
const;
 
   45  void UpdateWaySize(size_t way_size);
 
   56    Way(Way&& other) 
noexcept : cache(std::move(other.cache)) {}
 
   59    Way(
const Hash& hash, 
const Equal& equal) : cache(1, hash, equal) {}
 
   61    mutable engine::Mutex mutex;
 
   62    LruMap<T, U, Hash, Equal> cache;
 
   65  Way& GetWay(
const T& key);
 
   69  std::vector<Way> caches_;
 
   71  std::shared_ptr<
dump::Dumper> dumper_{
nullptr};
 
   74template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
   75NWayLRU<T, U, Hash, Eq>::NWayLRU(size_t ways, size_t way_size, 
const Hash& hash,
 
   77    : caches_(), hash_fn_(hash) {
 
   78  caches_.reserve(ways);
 
   79  for (size_t i = 0; i < ways; ++i) caches_.emplace_back(hash, equal);
 
   80  if (ways == 0) 
throw std::logic_error(
"Ways must be positive");
 
   82  for (
auto& way : caches_) way.cache.SetMaxSize(way_size);
 
   85template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
   86void NWayLRU<T, U, Hash, Eq>::Put(
const T& key, U value) {
 
   87  auto& way = GetWay(key);
 
   89    std::unique_lock<engine::Mutex> lock(way.mutex);
 
   90    way.cache.Put(key, std::move(value));
 
   95template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
   96template <
typename Validator>
 
   97std::optional<U> NWayLRU<T, U, Hash, Eq>::Get(
const T& key,
 
   98                                              Validator validator) {
 
   99  auto& way = GetWay(key);
 
  100  std::unique_lock<engine::Mutex> lock(way.mutex);
 
  101  auto* value = way.cache.Get(key);
 
  104    if (validator(*value)) 
return *value;
 
  105    way.cache.Erase(key);
 
  111template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  112void NWayLRU<T, U, Hash, Eq>::InvalidateByKey(
const T& key) {
 
  113  auto& way = GetWay(key);
 
  115    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  116    way.cache.Erase(key);
 
  121template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  122U NWayLRU<T, U, Hash, Eq>::GetOr(
const T& key, 
const U& default_value) {
 
  123  auto& way = GetWay(key);
 
  124  std::unique_lock<engine::Mutex> lock(way.mutex);
 
  125  return way.cache.GetOr(key, default_value);
 
  128template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  129void NWayLRU<T, U, Hash, Eq>::Invalidate() {
 
  130  for (
auto& way : caches_) {
 
  131    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  137template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  138template <
typename Function>
 
  139void NWayLRU<T, U, Hash, Eq>::
VisitAll(Function func) 
const {
 
  140  for (
const auto& way : caches_) {
 
  141    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  142    way.cache.VisitAll(func);
 
  146template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  147size_t NWayLRU<T, U, Hash, Eq>::GetSize() 
const {
 
  149  for (
const auto& way : caches_) {
 
  150    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  151    size += way.cache.GetSize();
 
  156template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  157void NWayLRU<T, U, Hash, Eq>::UpdateWaySize(size_t way_size) {
 
  158  for (
auto& way : caches_) {
 
  159    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  160    way.cache.SetMaxSize(way_size);
 
  164template <
typename T, 
typename U, 
typename Hash, 
typename Eq>
 
  165typename NWayLRU<T, U, Hash, Eq>::Way& NWayLRU<T, U, Hash, Eq>::GetWay(
 
  167  auto n = hash_fn_(key) % caches_.size();
 
  171template <
typename T, 
typename U, 
typename Hash, 
typename Equal>
 
  172void NWayLRU<T, U, Hash, Equal>::Write(
dump::
Writer& writer) 
const {
 
  173  writer.Write(caches_.size());
 
  175  for (
const Way& way : caches_) {
 
  176    std::unique_lock<engine::Mutex> lock(way.mutex);
 
  178    writer.Write(way.cache.GetSize());
 
  180    way.cache.VisitAll([&writer](
const T& key, 
const U& value) {
 
  187template <
typename T, 
typename U, 
typename Hash, 
typename Equal>
 
  188void NWayLRU<T, U, Hash, Equal>::Read(
dump::
Reader& reader) {
 
  191  const auto ways = reader.Read<std::size_t>();
 
  192  for (std::size_t i = 0; i < ways; ++i) {
 
  193    const auto elements_in_way = reader.Read<std::size_t>();
 
  194    for (std::size_t j = 0; j < elements_in_way; ++j) {
 
  195      auto key = reader.Read<T>();
 
  196      auto value = reader.Read<U>();
 
  197      Put(std::move(key), std::move(value));
 
  202template <
typename T, 
typename U, 
typename Hash, 
typename Equal>
 
  203void NWayLRU<T, U, Hash, Equal>::NotifyDumper() {
 
  204  if (dumper_ != 
nullptr) {
 
  205    dumper_->OnUpdateCompleted();
 
  209template <
typename T, 
typename U, 
typename Hash, 
typename Equal>
 
  210void NWayLRU<T, U, Hash, Equal>::
SetDumper(
 
  211    std::shared_ptr<
dump::Dumper> dumper) {
 
  212  dumper_ = std::move(dumper);