77#include < cassert>
88#include < shared_mutex>
99#include < mutex>
10- #include < optional >
10+ #include < vector >
1111
1212#include " impl/mpl_helpers.hpp"
1313#include " container.hpp"
@@ -63,19 +63,33 @@ class ExpirableContainer {
6363 bool insert (Value&& value) { return emplace (std::move (value)).second ; }
6464
6565 template <typename Tag, typename Key>
66- std::optional<Value> get (const Key& key) {
66+ std::vector<Value> get (const Key& key) {
67+ auto now = std::chrono::steady_clock::now ();
6768 std::lock_guard<userver::engine::SharedMutex> lock (mutex_);
68- auto it = find<Tag, Key>(lock, key);
69- if (it == end<Tag>()) {
70- return std::nullopt ;
69+
70+ std::vector<Value> result;
71+ auto & index = container_.template get_index <Tag>();
72+
73+ if constexpr (impl::is_unique_index<decltype (index)>::value) {
74+ auto it = find<Tag, Key>(lock, key, now);
75+ if (it != container_.template end <Tag>()) {
76+ result.push_back (it->value );
77+ }
78+ } else {
79+ auto range = find_range<Tag, Key>(lock, key, now);
80+ for (auto it = range.first ; it != range.second ; ++it) {
81+ result.push_back (it->value );
82+ }
7183 }
72- return *it;
84+
85+ return result;
7386 }
7487
7588 template <typename Tag, typename Key>
7689 bool contains (const Key& key) {
90+ auto now = std::chrono::steady_clock::now ();
7791 std::lock_guard<userver::engine::SharedMutex> lock (mutex_);
78- return this -> template find <Tag, Key>(lock, key) != container_.template end <Tag>();
92+ return find<Tag, Key>(lock, key, now ) != container_.template end <Tag>();
7993 }
8094
8195 template <typename Tag, typename Key>
@@ -117,19 +131,55 @@ class ExpirableContainer {
117131 using CacheContainer = Container<CacheItem, IndexSpecifierList, Allocator>;
118132
119133 template <typename Tag, typename Key>
120- auto find (std::lock_guard<userver::engine::SharedMutex>&, const Key& key) {
134+ auto find (std::lock_guard<userver::engine::SharedMutex>&,
135+ const Key& key,
136+ std::chrono::steady_clock::time_point now) {
121137 auto it = container_.template find <Tag, Key>(key);
122138
123- if (it != container_. template end <Tag>()) {
124- if (std::chrono::steady_clock:: now() > it->last_accessed + ttl_) {
139+ if (it != end<Tag>()) {
140+ if (now > it->last_accessed + ttl_) {
125141 container_.template get_index <Tag>().erase (it);
126- return impl::TimestampedIteratorWrapper{container_.template end <Tag>()};
142+ return end<Tag>();
143+ } else {
144+ it->last_accessed = now;
127145 }
128-
129- it->last_accessed = std::chrono::steady_clock::now ();
130146 }
147+
148+ return it;
149+ }
131150
132- return impl::TimestampedIteratorWrapper{it};
151+ template <typename Tag, typename Key>
152+ auto find_range (std::lock_guard<userver::engine::SharedMutex>&,
153+ const Key& key,
154+ std::chrono::steady_clock::time_point now) {
155+ auto & index = container_.template get_index <Tag>();
156+ auto [begin, end] = index.equal_range (key);
157+
158+ auto it = begin;
159+ std::vector<decltype (it)> to_erase;
160+ std::vector<decltype (it)> to_move;
161+
162+ while (it != end) {
163+ if (now > it->last_accessed + ttl_) {
164+ to_erase.push_back (it);
165+ ++it;
166+ } else {
167+ it->last_accessed = now;
168+ to_move.push_back (it);
169+ ++it;
170+ }
171+ }
172+
173+ for (auto erase_it : to_erase) {
174+ index.erase (erase_it);
175+ }
176+
177+ auto & seq_index = container_.get_sequensed ();
178+ for (auto move_it : to_move) {
179+ seq_index.relocate (seq_index.begin (), container_.project_to_sequenced (move_it));
180+ }
181+
182+ return index.equal_range (key);
133183 }
134184
135185 void cleanup () {
@@ -174,7 +224,6 @@ class ExpirableContainer {
174224 userver::engine::Task cleanup_task_;
175225};
176226
177-
178227} // namespace multi_index_lru
179228
180229USERVER_NAMESPACE_END
0 commit comments