@@ -37,18 +37,18 @@ public class ConcurrentLfu<K, V> : ICache<K, V>, IBoundedPolicy
3737
3838 public const int BufferSize = 128 ;
3939
40- private readonly ConcurrentDictionary < K , LinkedListNode < LfuNode < K , V > > > dictionary ;
40+ private readonly ConcurrentDictionary < K , LfuNode < K , V > > dictionary ;
4141
42- private readonly StripedBuffer < LinkedListNode < LfuNode < K , V > > > readBuffer ;
43- private readonly StripedBuffer < LinkedListNode < LfuNode < K , V > > > writeBuffer ;
42+ private readonly StripedBuffer < LfuNode < K , V > > readBuffer ;
43+ private readonly StripedBuffer < LfuNode < K , V > > writeBuffer ;
4444
4545 private readonly CacheMetrics metrics = new CacheMetrics ( ) ;
4646
4747 private readonly CmSketch < K > cmSketch ;
4848
49- private readonly LinkedList < LfuNode < K , V > > windowLru ;
50- private readonly LinkedList < LfuNode < K , V > > probationLru ;
51- private readonly LinkedList < LfuNode < K , V > > protectedLru ;
49+ private readonly LfuNodeList < K , V > windowLru ;
50+ private readonly LfuNodeList < K , V > probationLru ;
51+ private readonly LfuNodeList < K , V > protectedLru ;
5252
5353 private readonly LfuCapacityPartition capacity ;
5454
@@ -58,7 +58,7 @@ public class ConcurrentLfu<K, V> : ICache<K, V>, IBoundedPolicy
5858 private readonly IScheduler scheduler ;
5959
6060#if NETSTANDARD2_0
61- private readonly LinkedListNode < LfuNode < K , V > > [ ] localDrainBuffer = new LinkedListNode < LfuNode < K , V > > [ TakeBufferSize ] ;
61+ private readonly LfuNode < K , V > [ ] localDrainBuffer = new LfuNode < K , V > [ TakeBufferSize ] ;
6262#endif
6363
6464 public ConcurrentLfu ( int capacity )
@@ -70,16 +70,16 @@ public ConcurrentLfu(int concurrencyLevel, int capacity, IScheduler scheduler)
7070 {
7171 var comparer = EqualityComparer < K > . Default ;
7272
73- this . dictionary = new ConcurrentDictionary < K , LinkedListNode < LfuNode < K , V > > > ( concurrencyLevel , capacity , comparer ) ;
73+ this . dictionary = new ConcurrentDictionary < K , LfuNode < K , V > > ( concurrencyLevel , capacity , comparer ) ;
7474
75- this . readBuffer = new StripedBuffer < LinkedListNode < LfuNode < K , V > > > ( concurrencyLevel , BufferSize ) ;
76- this . writeBuffer = new StripedBuffer < LinkedListNode < LfuNode < K , V > > > ( concurrencyLevel , BufferSize ) ;
75+ this . readBuffer = new StripedBuffer < LfuNode < K , V > > ( concurrencyLevel , BufferSize ) ;
76+ this . writeBuffer = new StripedBuffer < LfuNode < K , V > > ( concurrencyLevel , BufferSize ) ;
7777
7878 this . cmSketch = new CmSketch < K > ( 1 , comparer ) ;
7979 this . cmSketch . EnsureCapacity ( capacity ) ;
80- this . windowLru = new LinkedList < LfuNode < K , V > > ( ) ;
81- this . probationLru = new LinkedList < LfuNode < K , V > > ( ) ;
82- this . protectedLru = new LinkedList < LfuNode < K , V > > ( ) ;
80+ this . windowLru = new LfuNodeList < K , V > ( ) ;
81+ this . probationLru = new LfuNodeList < K , V > ( ) ;
82+ this . protectedLru = new LfuNodeList < K , V > ( ) ;
8383
8484 this . capacity = new LfuCapacityPartition ( capacity ) ;
8585
@@ -109,7 +109,7 @@ public void AddOrUpdate(K key, V value)
109109 return ;
110110 }
111111
112- var node = new LinkedListNode < LfuNode < K , V > > ( new LfuNode < K , V > ( key , value ) ) ;
112+ var node = new LfuNode < K , V > ( key , value ) ;
113113 if ( this . dictionary . TryAdd ( key , node ) )
114114 {
115115 AfterWrite ( node ) ;
@@ -133,7 +133,7 @@ public void Clear()
133133 public void Trim ( int itemCount )
134134 {
135135 itemCount = Math . Min ( itemCount , this . Count ) ;
136- var candidates = new List < LinkedListNode < LfuNode < K , V > > > ( itemCount ) ;
136+ var candidates = new List < LfuNode < K , V > > ( itemCount ) ;
137137
138138 // TODO: this is LRU order eviction, Caffeine void evictFromMain(int candidates) is based on frequency
139139 lock ( maintenanceLock )
@@ -146,7 +146,7 @@ public void Trim(int itemCount)
146146
147147 foreach ( var candidate in candidates )
148148 {
149- this . TryRemove ( candidate . Value . Key ) ;
149+ this . TryRemove ( candidate . Key ) ;
150150 }
151151 }
152152
@@ -159,11 +159,11 @@ public V GetOrAdd(K key, Func<K, V> valueFactory)
159159 return value ;
160160 }
161161
162- var node = new LinkedListNode < LfuNode < K , V > > ( new LfuNode < K , V > ( key , valueFactory ( key ) ) ) ;
162+ var node = new LfuNode < K , V > ( key , valueFactory ( key ) ) ;
163163 if ( this . dictionary . TryAdd ( key , node ) )
164164 {
165165 AfterWrite ( node ) ;
166- return node . Value . Value ;
166+ return node . Value ;
167167 }
168168 }
169169 }
@@ -178,7 +178,7 @@ public bool TryGet(K key, out V value)
178178 {
179179 TryScheduleDrain ( ) ;
180180 }
181- value = node . Value . Value ;
181+ value = node . Value ;
182182 return true ;
183183 }
184184
@@ -192,7 +192,7 @@ public bool TryRemove(K key)
192192 {
193193 if ( this . dictionary . TryRemove ( key , out var node ) )
194194 {
195- node . Value . WasRemoved = true ;
195+ node . WasRemoved = true ;
196196 AfterWrite ( node ) ;
197197 return true ;
198198 }
@@ -204,7 +204,7 @@ public bool TryUpdate(K key, V value)
204204 {
205205 if ( this . dictionary . TryGetValue ( key , out var node ) )
206206 {
207- node . Value . Value = value ;
207+ node . Value = value ;
208208
209209 // It's ok for this to be lossy, since the node is already tracked
210210 // and we will just lose ordering/hit count, but not orphan the node.
@@ -225,11 +225,11 @@ public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
225225 {
226226 foreach ( var kvp in this . dictionary )
227227 {
228- yield return new KeyValuePair < K , V > ( kvp . Key , kvp . Value . Value . Value ) ;
228+ yield return new KeyValuePair < K , V > ( kvp . Key , kvp . Value . Value ) ;
229229 }
230230 }
231231
232- private static void TakeCandidatesInLruOrder ( LinkedList < LfuNode < K , V > > lru , List < LinkedListNode < LfuNode < K , V > > > candidates , int itemCount )
232+ private static void TakeCandidatesInLruOrder ( LfuNodeList < K , V > lru , List < LfuNode < K , V > > candidates , int itemCount )
233233 {
234234 var curr = lru . First ;
235235
@@ -240,7 +240,7 @@ private static void TakeCandidatesInLruOrder(LinkedList<LfuNode<K, V>> lru, List
240240 }
241241 }
242242
243- private void AfterWrite ( LinkedListNode < LfuNode < K , V > > node )
243+ private void AfterWrite ( LfuNode < K , V > node )
244244 {
245245 var spinner = new SpinWait ( ) ;
246246
@@ -351,16 +351,14 @@ private void DrainBuffers()
351351 }
352352 }
353353
354- const int takeBufferSize = 1024 ;
355-
356354 private bool Maintenance ( )
357355 {
358356 this . drainStatus . Set ( DrainStatus . ProcessingToIdle ) ;
359357
360358 bool wasDrained = false ;
361359
362360#if ! NETSTANDARD2_0
363- var localDrainBuffer = ArrayPool < LinkedListNode < LfuNode < K , V > > > . Shared . Rent ( TakeBufferSize ) ;
361+ var localDrainBuffer = ArrayPool < LfuNode < K , V > > . Shared . Rent ( TakeBufferSize ) ;
364362#endif
365363 int maxSweeps = 1 ;
366364 int count = 0 ;
@@ -374,7 +372,7 @@ private bool Maintenance()
374372
375373 for ( int i = 0 ; i < count ; i ++ )
376374 {
377- this . cmSketch . Increment ( localDrainBuffer [ i ] . Value . Key ) ;
375+ this . cmSketch . Increment ( localDrainBuffer [ i ] . Key ) ;
378376 }
379377
380378 for ( int i = 0 ; i < count ; i ++ )
@@ -393,7 +391,7 @@ private bool Maintenance()
393391 }
394392
395393#if ! NETSTANDARD2_0
396- ArrayPool < LinkedListNode < LfuNode < K , V > > > . Shared . Return ( localDrainBuffer ) ;
394+ ArrayPool < LfuNode < K , V > > . Shared . Return ( localDrainBuffer ) ;
397395#endif
398396
399397 // TODO: hill climb
@@ -411,18 +409,18 @@ private bool Maintenance()
411409 return wasDrained ;
412410 }
413411
414- private void OnAccess ( LinkedListNode < LfuNode < K , V > > node )
412+ private void OnAccess ( LfuNode < K , V > node )
415413 {
416414 // there was a cache hit even if the item was removed or is not yet added.
417415 this . metrics . requestHitCount ++ ;
418416
419417 // Node is added to read buffer while it is removed by maintenance, or it is read before it has been added.
420- if ( node . List == null )
418+ if ( node . list == null )
421419 {
422420 return ;
423421 }
424422
425- switch ( node . Value . Position )
423+ switch ( node . Position )
426424 {
427425 case Position . Window :
428426 this . windowLru . MoveToEnd ( node ) ;
@@ -436,27 +434,27 @@ private void OnAccess(LinkedListNode<LfuNode<K, V>> node)
436434 }
437435 }
438436
439- private void OnWrite ( LinkedListNode < LfuNode < K , V > > node )
437+ private void OnWrite ( LfuNode < K , V > node )
440438 {
441439 // Nodes can be removed while they are in the write buffer, in which case they should
442440 // not be added back into the LRU.
443- if ( node . Value . WasRemoved )
441+ if ( node . WasRemoved )
444442 {
445- if ( node . List != null )
443+ if ( node . list != null )
446444 {
447- node . List . Remove ( node ) ;
445+ node . list . Remove ( node ) ;
448446 }
449447
450448 return ;
451449 }
452450
453- this . cmSketch . Increment ( node . Value . Key ) ;
451+ this . cmSketch . Increment ( node . Key ) ;
454452
455453 // node can already be in one of the queues due to update
456- switch ( node . Value . Position )
454+ switch ( node . Position )
457455 {
458456 case Position . Window :
459- if ( node . List == null )
457+ if ( node . list == null )
460458 {
461459 this . windowLru . AddLast ( node ) ;
462460 TryEvict ( ) ;
@@ -490,42 +488,42 @@ private void TryEvict()
490488 if ( this . protectedLru . Count < capacity . Protected )
491489 {
492490 this . protectedLru . AddLast ( candidate ) ;
493- candidate . Value . Position = Position . Protected ;
491+ candidate . Position = Position . Protected ;
494492 return ;
495493 }
496494
497495 this . probationLru . AddLast ( candidate ) ;
498- candidate . Value . Position = Position . Probation ;
496+ candidate . Position = Position . Probation ;
499497
500498 // remove either candidate or probation.first
501499 if ( this . probationLru . Count > capacity . Probation )
502500 {
503- var c = this . cmSketch . EstimateFrequency ( candidate . Value . Key ) ;
504- var p = this . cmSketch . EstimateFrequency ( this . probationLru . First . Value . Key ) ;
501+ var c = this . cmSketch . EstimateFrequency ( candidate . Key ) ;
502+ var p = this . cmSketch . EstimateFrequency ( this . probationLru . First . Key ) ;
505503
506504 // TODO: random factor?
507505 var victim = ( c > p ) ? this . probationLru . First : candidate ;
508506
509- this . dictionary . TryRemove ( victim . Value . Key , out var _ ) ;
510- victim . List . Remove ( victim ) ;
507+ this . dictionary . TryRemove ( victim . Key , out var _ ) ;
508+ victim . list . Remove ( victim ) ;
511509
512510 this . metrics . evictedCount ++ ;
513511 }
514512 }
515513 }
516514
517- private void PromoteProbation ( LinkedListNode < LfuNode < K , V > > node )
515+ private void PromoteProbation ( LfuNode < K , V > node )
518516 {
519517 this . probationLru . Remove ( node ) ;
520518 this . protectedLru . AddLast ( node ) ;
521- node . Value . Position = Position . Protected ;
519+ node . Position = Position . Protected ;
522520
523521 if ( this . protectedLru . Count > capacity . Protected )
524522 {
525523 var demoted = this . protectedLru . First ;
526524 this . protectedLru . RemoveFirst ( ) ;
527525
528- demoted . Value . Position = Position . Probation ;
526+ demoted . Position = Position . Probation ;
529527 this . probationLru . AddLast ( demoted ) ;
530528 }
531529 }
0 commit comments