@@ -133,7 +133,7 @@ public void AddOrUpdate(K key, V value)
133133
134134 public void Clear ( )
135135 {
136- this . Trim ( this . Count ) ;
136+ Trim ( int . MaxValue ) ;
137137
138138 lock ( maintenanceLock )
139139 {
@@ -145,15 +145,16 @@ public void Clear()
145145
146146 public void Trim ( int itemCount )
147147 {
148- itemCount = Math . Min ( itemCount , this . Count ) ;
149- var candidates = new List < LfuNode < K , V > > ( itemCount ) ;
150-
151- // TODO: this is LRU order eviction, Caffeine is based on frequency
148+ List < LfuNode < K , V > > candidates ;
152149 lock ( maintenanceLock )
153150 {
154- // flush all buffers
155151 Maintenance ( ) ;
156152
153+ int lruCount = this . windowLru . Count + this . probationLru . Count + this . protectedLru . Count ;
154+ itemCount = Math . Min ( itemCount , lruCount ) ;
155+ candidates = new ( itemCount ) ;
156+
157+ // Note: this is LRU order eviction, Caffeine is based on frequency
157158 // walk in lru order, get itemCount keys to evict
158159 TakeCandidatesInLruOrder ( this . probationLru , candidates , itemCount ) ;
159160 TakeCandidatesInLruOrder ( this . protectedLru , candidates , itemCount ) ;
@@ -608,12 +609,6 @@ private void OnWrite(LfuNode<K, V> node)
608609
609610 private void PromoteProbation ( LfuNode < K , V > node )
610611 {
611- if ( node . list == null )
612- {
613- // Ignore stale accesses for an entry that is no longer present
614- return ;
615- }
616-
617612 this . probationLru . Remove ( node ) ;
618613 this . protectedLru . AddLast ( node ) ;
619614 node . Position = Position . Protected ;
@@ -699,6 +694,22 @@ private void EvictFromMain(LfuNode<K, V> candidateNode)
699694 break ;
700695 }
701696
697+ if ( candidate . node . WasRemoved )
698+ {
699+ var evictee = candidate . node ;
700+ candidate . Next ( ) ;
701+ Evict ( evictee ) ;
702+ continue ;
703+ }
704+
705+ if ( victim . node . WasRemoved )
706+ {
707+ var evictee = victim . node ;
708+ victim . Next ( ) ;
709+ Evict ( evictee ) ;
710+ continue ;
711+ }
712+
702713 // Evict the entry with the lowest frequency
703714 if ( candidate . freq > victim . freq )
704715 {
@@ -749,7 +760,17 @@ private bool AdmitCandidate(K candidateKey, K victimKey)
749760
750761 private void Evict ( LfuNode < K , V > evictee )
751762 {
752- this . dictionary . TryRemove ( evictee . Key , out var _ ) ;
763+ evictee . WasRemoved = true ;
764+ evictee . WasDeleted = true ;
765+
766+ // This handles the case where the same key exists in the write buffer both
767+ // as added and removed. Remove via KVP ensures we don't remove added nodes.
768+ var kvp = new KeyValuePair < K , N > ( evictee . Key , ( N ) evictee ) ;
769+ #if NET6_0_OR_GREATER
770+ this . dictionary . TryRemove ( kvp ) ;
771+ #else
772+ ( ( ICollection < KeyValuePair < K , N > > ) this . dictionary ) . Remove ( kvp ) ;
773+ #endif
753774 evictee . list . Remove ( evictee ) ;
754775 Disposer < V > . Dispose ( evictee . Value ) ;
755776 this . metrics . evictedCount ++ ;
0 commit comments