@@ -87,7 +87,7 @@ void LRUHandleTable::Resize() {
8787
8888 uint32_t old_length = uint32_t {1 } << length_bits_;
8989 int new_length_bits = length_bits_ + 1 ;
90- std::unique_ptr<LRUHandle *[]> new_list{ new LRUHandle *[size_t {1 } << new_length_bits] {}};
90+ std::unique_ptr<LRUHandle *[]> new_list { new LRUHandle *[size_t {1 } << new_length_bits] {} };
9191 [[maybe_unused]] uint32_t count = 0 ;
9292 for (uint32_t i = 0 ; i < old_length; i++) {
9393 LRUHandle *h = list_[i];
@@ -225,6 +225,7 @@ double LRUCacheShard::GetLowPriPoolRatio() {
225225void LRUCacheShard::LRU_Remove (LRUHandle *e) {
226226 assert (e->next != nullptr );
227227 assert (e->prev != nullptr );
228+ bool was_tail = (lru_.next == e);
228229 if (lru_low_pri_ == e) {
229230 lru_low_pri_ = e->prev ;
230231 }
@@ -244,11 +245,15 @@ void LRUCacheShard::LRU_Remove(LRUHandle *e) {
244245 assert (low_pri_pool_usage_ >= e->total_charge );
245246 low_pri_pool_usage_ -= e->total_charge ;
246247 }
248+ if (was_tail) {
249+ NotifyTailChange ();
250+ }
247251}
248252
249253void LRUCacheShard::LRU_Insert (LRUHandle *e) {
250254 assert (e->next == nullptr );
251255 assert (e->prev == nullptr );
256+ bool was_empty = (lru_.next == &lru_);
252257 if (high_pri_pool_ratio_ > 0 && (e->IsHighPri () || e->HasHit ())) {
253258 // Inset "e" to head of LRU list.
254259 e->next = &lru_;
@@ -285,6 +290,10 @@ void LRUCacheShard::LRU_Insert(LRUHandle *e) {
285290 lru_bottom_pri_ = e;
286291 }
287292 lru_usage_ += e->total_charge ;
293+ if (was_empty) {
294+ // List went from 0 to 1 entry: the newly inserted node is the tail.
295+ NotifyTailChange ();
296+ }
288297}
289298
290299void LRUCacheShard::MaintainPoolSize () {
@@ -358,8 +367,8 @@ void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
358367 strict_capacity_limit_ = strict_capacity_limit;
359368}
360369
361- ErrorCode LRUCacheShard::DoInsertItemUnsafe (LRUHandle *e, LRUHandle **handle,
362- autovector<LRUHandle *> *last_reference_list) {
370+ ErrorCode
371+ LRUCacheShard::DoInsertItemUnsafe (LRUHandle *e, LRUHandle **handle, autovector<LRUHandle *> *last_reference_list) {
363372 // Free the space following strict LRU policy until enough space
364373 // is freed or the lru list is empty.
365374 EvictFromLRU (e->total_charge , last_reference_list);
@@ -679,6 +688,28 @@ size_t LRUCacheShard::GetOldestKeys(size_t count, std::vector<std::string> &out_
679688 return collected;
680689}
681690
691+ void LRUCacheShard::SetTailChangeCallback (uint32_t shard_id, const Cache::TailChangeCallback &callback) {
692+ std::lock_guard<std::mutex> l (mutex_);
693+ shard_id_ = shard_id;
694+ tail_change_callback_ = callback;
695+ // Notify immediately with current tail state so the caller gets the
696+ // initial value.
697+ NotifyTailChange ();
698+ }
699+
700+ void LRUCacheShard::NotifyTailChange () {
701+ if (!tail_change_callback_) {
702+ return ;
703+ }
704+ LRUHandle *tail = lru_.next ;
705+ if (tail == &lru_) {
706+ // LRU list is empty.
707+ tail_change_callback_ (shard_id_, nullptr );
708+ } else {
709+ tail_change_callback_ (shard_id_, tail->value );
710+ }
711+ }
712+
682713void LRUCacheShard::AppendPrintableOptions (std::string &str) const {
683714 const int kBufferSize = 200 ;
684715 char buffer[kBufferSize ];
@@ -739,16 +770,21 @@ size_t LRUCache::TEST_GetLRUSize() {
739770
740771double LRUCache::GetHighPriPoolRatio () { return GetShard (0 ).GetHighPriPoolRatio (); }
741772
742- size_t LRUCache::GetOldestKeysInShard (uint32_t shard_id,
743- size_t count,
744- std::vector<std::string> &out_keys) {
773+ size_t LRUCache::GetOldestKeysInShard (uint32_t shard_id, size_t count, std::vector<std::string> &out_keys) {
745774 uint32_t num_shards = GetNumShards ();
746775 if (shard_id >= num_shards || count == 0 ) {
747776 return 0 ;
748777 }
749778 return GetShard (shard_id).GetOldestKeys (count, out_keys);
750779}
751780
781+ void LRUCache::SetTailChangeCallback (TailChangeCallback callback) {
782+ uint32_t num_shards = GetNumShards ();
783+ for (uint32_t i = 0 ; i < num_shards; ++i) {
784+ GetShard (i).SetTailChangeCallback (i, callback);
785+ }
786+ }
787+
752788} // namespace lru_cache
753789
754790std::shared_ptr<Cache> LRUCacheOptions::MakeSharedCache () const {
0 commit comments