@@ -18,6 +18,7 @@ namespace ProfileEvents
1818 extern const Event FilesystemCacheEvictionSkippedFileSegments;
1919 extern const Event FilesystemCacheEvictionTries;
2020 extern const Event FilesystemCacheEvictionSkippedEvictingFileSegments;
21+ extern const Event FilesystemCacheEvictionReusedIterator;
2122}
2223
2324namespace DB
@@ -36,6 +37,7 @@ LRUFileCachePriority::LRUFileCachePriority(
3637 : IFileCachePriority(max_size_, max_elements_)
3738 , description(description_)
3839 , log(getLogger(" LRUFileCachePriority" + (description.empty() ? " " : " (" + description + " )" )))
40+ , eviction_pos(queue.end())
3941{
4042 if (state_)
4143 state = state_;
@@ -100,6 +102,13 @@ LRUFileCachePriority::LRUIterator LRUFileCachePriority::add(EntryPtr entry, cons
100102 return LRUIterator (this , iterator);
101103}
102104
105+ void LRUFileCachePriority::increasePriority (LRUQueue::iterator it, const CachePriorityGuard::Lock &)
106+ {
107+ if (eviction_pos == it)
108+ eviction_pos = std::next (it);
109+ queue.splice (queue.end (), queue, it);
110+ }
111+
103112LRUFileCachePriority::LRUQueue::iterator
104113LRUFileCachePriority::remove (LRUQueue::iterator it, const CachePriorityGuard::Lock &)
105114{
@@ -115,6 +124,8 @@ LRUFileCachePriority::remove(LRUQueue::iterator it, const CachePriorityGuard::Lo
115124 log, " Removed entry from LRU queue, key: {}, offset: {}, size: {}" ,
116125 entry.key , entry.offset , entry.size .load ());
117126
127+ if (eviction_pos == it)
128+ eviction_pos = std::next (it);
118129 return queue.erase (it);
119130}
120131
@@ -166,8 +177,20 @@ bool LRUFileCachePriority::LRUIterator::operator ==(const LRUIterator & other) c
166177
167178void LRUFileCachePriority::iterate (IterateFunc func, const CachePriorityGuard::Lock & lock)
168179{
169- for (auto it = queue.begin (); it != queue.end ();)
180+ iterateImpl (queue.begin (), func, lock);
181+ }
182+
183+ LRUFileCachePriority::LRUQueue::iterator
184+ LRUFileCachePriority::iterateImpl (LRUQueue::iterator start_pos, IterateFunc func, const CachePriorityGuard::Lock & lock)
185+ {
186+ const size_t max_elements_to_iterate = queue.size ();
187+ auto it = start_pos;
188+
189+ for (size_t iterated_elements = 0 ; iterated_elements < max_elements_to_iterate; ++iterated_elements)
170190 {
191+ if (it == queue.end ())
192+ it = queue.begin ();
193+
171194 const auto & entry = **it;
172195
173196 if (entry.size == 0 )
@@ -223,7 +246,7 @@ void LRUFileCachePriority::iterate(IterateFunc func, const CachePriorityGuard::L
223246 {
224247 case IterationResult::BREAK:
225248 {
226- return ;
249+ return it ;
227250 }
228251 case IterationResult::CONTINUE:
229252 {
@@ -237,6 +260,7 @@ void LRUFileCachePriority::iterate(IterateFunc func, const CachePriorityGuard::L
237260 }
238261 }
239262 }
263+ return queue.end ();
240264}
241265
242266bool LRUFileCachePriority::canFit ( // / NOLINT
@@ -270,6 +294,7 @@ bool LRUFileCachePriority::collectCandidatesForEviction(
270294 FileCacheReserveStat & stat,
271295 EvictionCandidates & res,
272296 IFileCachePriority::IteratorPtr /* reservee */ ,
297+ bool continue_from_last_eviction_pos,
273298 const UserID &,
274299 const CachePriorityGuard::Lock & lock)
275300{
@@ -283,7 +308,7 @@ bool LRUFileCachePriority::collectCandidatesForEviction(
283308 return canFit (size, elements, stat.total_stat .releasable_size , stat.total_stat .releasable_count , lock);
284309 };
285310
286- iterateForEviction (res, stat, can_fit, lock);
311+ iterateForEviction (res, stat, can_fit, continue_from_last_eviction_pos, lock);
287312
288313 if (can_fit ())
289314 {
@@ -349,7 +374,7 @@ IFileCachePriority::CollectStatus LRUFileCachePriority::collectCandidatesForEvic
349374 }
350375 return false ;
351376 };
352- iterateForEviction (res, stat, stop_condition, lock);
377+ iterateForEviction (res, stat, stop_condition, false , lock);
353378 chassert (status != CollectStatus::SUCCESS || stop_condition ());
354379 return status;
355380}
@@ -358,14 +383,15 @@ void LRUFileCachePriority::iterateForEviction(
358383 EvictionCandidates & res,
359384 FileCacheReserveStat & stat,
360385 StopConditionFunc stop_condition,
386+ bool continue_from_last_eviction_pos,
361387 const CachePriorityGuard::Lock & lock)
362388{
363389 if (stop_condition ())
364390 return ;
365391
366392 ProfileEvents::increment (ProfileEvents::FilesystemCacheEvictionTries);
367393
368- IterateFunc iterate_func = [&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
394+ auto iterate_func = [&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
369395 {
370396 const auto & file_segment = segment_metadata->file_segment ;
371397 chassert (file_segment->assertCorrectness ());
@@ -380,14 +406,27 @@ void LRUFileCachePriority::iterateForEviction(
380406 ProfileEvents::increment (ProfileEvents::FilesystemCacheEvictionSkippedFileSegments);
381407 stat.update (segment_metadata->size (), file_segment->getKind (), false );
382408 }
383-
384- return IterationResult::CONTINUE;
385409 };
386410
387- iterate([&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
411+ auto start_pos = queue.begin ();
412+ if (continue_from_last_eviction_pos && eviction_pos != queue.end () && start_pos != eviction_pos)
388413 {
389- return stop_condition () ? IterationResult::BREAK : iterate_func (locked_key, segment_metadata);
414+ ProfileEvents::increment (ProfileEvents::FilesystemCacheEvictionReusedIterator);
415+ start_pos = eviction_pos;
416+ }
417+
418+ auto iteration_pos = iterateImpl (
419+ start_pos,
420+ [&](LockedKey & locked_key, const FileSegmentMetadataPtr & segment_metadata)
421+ {
422+ if (stop_condition ())
423+ return IterationResult::BREAK;
424+ iterate_func (locked_key, segment_metadata);
425+ return stop_condition () ? IterationResult::BREAK : IterationResult::CONTINUE;
390426 }, lock);
427+
428+ if (continue_from_last_eviction_pos)
429+ eviction_pos = iteration_pos;
391430}
392431
393432LRUFileCachePriority::LRUIterator LRUFileCachePriority::move (
@@ -415,6 +454,8 @@ LRUFileCachePriority::LRUIterator LRUFileCachePriority::move(
415454 }
416455#endif
417456
457+ if (other.eviction_pos == it.iterator )
458+ other.eviction_pos = std::next (it.iterator );
418459 queue.splice (queue.end (), other.queue , it.iterator );
419460
420461 updateSize (entry.size );
@@ -534,7 +575,7 @@ void LRUFileCachePriority::LRUIterator::decrementSize(size_t size)
534575size_t LRUFileCachePriority::LRUIterator::increasePriority (const CachePriorityGuard::Lock & lock)
535576{
536577 assertValid ();
537- cache_priority->queue . splice (cache_priority-> queue . end (), cache_priority-> queue , iterator );
578+ cache_priority->increasePriority (iterator, lock );
538579 cache_priority->check (lock);
539580 return ++((*iterator)->hits );
540581}
@@ -547,6 +588,7 @@ void LRUFileCachePriority::LRUIterator::assertValid() const
547588
548589void LRUFileCachePriority::shuffle (const CachePriorityGuard::Lock &)
549590{
591+ chassert (eviction_pos == queue.end ());
550592 std::vector<LRUQueue::iterator> its;
551593 its.reserve (queue.size ());
552594 for (auto it = queue.begin (); it != queue.end (); ++it)
0 commit comments