@@ -28,7 +28,7 @@ namespace BitFaster.Caching.Lru
2828 /// 5. When warm is full, warm tail is moved to warm head or cold depending on WasAccessed.
2929 /// 6. When cold is full, cold tail is moved to warm head or removed from dictionary on depending on WasAccessed.
3030 /// </remarks>
31- public class ConcurrentLruCore < K , V , I , P , T > : ICache < K , V > , IAsyncCache < K , V > , IBoundedPolicy , ITimePolicy , IEnumerable < KeyValuePair < K , V > >
31+ public class ConcurrentLruCore < K , V , I , P , T > : ICache < K , V > , IAsyncCache < K , V > , IEnumerable < KeyValuePair < K , V > >
3232 where I : LruItem < K , V >
3333 where P : struct , IItemPolicy < K , V , I >
3434 where T : struct , ITelemetryPolicy < K , V >
@@ -53,8 +53,6 @@ public class ConcurrentLruCore<K, V, I, P, T> : ICache<K, V>, IAsyncCache<K, V>,
5353 // if mutate methods are called. Therefore, field must be mutable to maintain count.
5454 protected T telemetryPolicy ;
5555
56- private readonly CachePolicy policy ;
57-
5856 public ConcurrentLruCore (
5957 int concurrencyLevel ,
6058 ICapacityPartition capacity ,
@@ -85,8 +83,6 @@ public ConcurrentLruCore(
8583 this . itemPolicy = itemPolicy ;
8684 this . telemetryPolicy = telemetryPolicy ;
8785 this . telemetryPolicy . SetEventSource ( this ) ;
88-
89- this . policy = new CachePolicy ( this , this ) ;
9086 }
9187
9288 // No lock count: https://arbel.net/2013/02/03/best-practices-for-using-concurrentdictionary/
@@ -102,6 +98,8 @@ public ConcurrentLruCore(
10298 ///<inheritdoc/>
10399 public ICacheEvents < K , V > Events => new Proxy ( this ) ;
104100
101+ public CachePolicy Policy => CreatePolicy ( this ) ;
102+
105103 public int HotCount => this . hotCount ;
106104
107105 public int WarmCount => this . warmCount ;
@@ -113,12 +111,6 @@ public ConcurrentLruCore(
113111 /// </summary>
114112 public ICollection < K > Keys => this . dictionary . Keys ;
115113
116- public CachePolicy Policy => this . policy ;
117-
118- public bool CanExpire => this . itemPolicy . CanDiscard ( ) ;
119-
120- public TimeSpan TimeToLive => this . itemPolicy . TimeToLive ;
121-
122114 /// <summary>Returns an enumerator that iterates through the cache.</summary>
123115 /// <returns>An enumerator for the cache.</returns>
124116 /// <remarks>
@@ -350,11 +342,11 @@ public void Trim(int itemCount)
350342 TrimLiveItems ( itemsRemoved , itemCount , capacity ) ;
351343 }
352344
353- public void TrimExpired ( )
345+ private void TrimExpired ( )
354346 {
355347 if ( this . itemPolicy . CanDiscard ( ) )
356348 {
357- TrimAllDiscardedItems ( ) ;
349+ this . TrimAllDiscardedItems ( ) ;
358350 }
359351 }
360352
@@ -631,14 +623,20 @@ IEnumerator IEnumerable.GetEnumerator()
631623 return ( ( ConcurrentLruCore < K , V , I , P , T > ) this ) . GetEnumerator ( ) ;
632624 }
633625
626+ private static CachePolicy CreatePolicy ( ConcurrentLruCore < K , V , I , P , T > lru )
627+ {
628+ var p = new Proxy ( lru ) ;
629+ return new CachePolicy ( p , p ) ;
630+ }
631+
634632 // To get JIT optimizations, policies must be structs.
635633 // If the structs are returned directly via properties, they will be copied. Since
636634 // telemetryPolicy is a mutable struct, copy is bad. One workaround is to store the
637635 // state within the struct in an object. Since the struct points to the same object
638636 // it becomes immutable. However, this object is then somewhere else on the
639637 // heap, which slows down the policies with hit counter logic in benchmarks. Likely
640638 // this approach keeps the structs data members in the same CPU cache line as the LRU.
641- private class Proxy : ICacheMetrics , ICacheEvents < K , V >
639+ private class Proxy : ICacheMetrics , ICacheEvents < K , V > , IBoundedPolicy , ITimePolicy
642640 {
643641 private readonly ConcurrentLruCore < K , V , I , P , T > lru ;
644642
@@ -659,11 +657,27 @@ public Proxy(ConcurrentLruCore<K, V, I, P, T> lru)
659657
660658 public bool IsEnabled => ( lru . telemetryPolicy as ICacheMetrics ) . IsEnabled ;
661659
660+ public int Capacity => lru . Capacity ;
661+
662+ public bool CanExpire => lru . itemPolicy . CanDiscard ( ) ;
663+
664+ public TimeSpan TimeToLive => lru . itemPolicy . TimeToLive ;
665+
662666 public event EventHandler < ItemRemovedEventArgs < K , V > > ItemRemoved
663667 {
664668 add { this . lru . telemetryPolicy . ItemRemoved += value ; }
665669 remove { this . lru . telemetryPolicy . ItemRemoved -= value ; }
666670 }
671+
672+ public void Trim ( int itemCount )
673+ {
674+ lru . Trim ( itemCount ) ;
675+ }
676+
677+ public void TrimExpired ( )
678+ {
679+ lru . TrimExpired ( ) ;
680+ }
667681 }
668682 }
669683}
0 commit comments