@@ -28,7 +28,7 @@ namespace BitFaster.Caching.Lru
28
28
/// 5. When warm is full, warm tail is moved to warm head or cold depending on WasAccessed.
29
29
/// 6. When cold is full, cold tail is moved to warm head or removed from dictionary on depending on WasAccessed.
30
30
/// </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 > >
32
32
where I : LruItem < K , V >
33
33
where P : struct , IItemPolicy < K , V , I >
34
34
where T : struct , ITelemetryPolicy < K , V >
@@ -53,8 +53,6 @@ public class ConcurrentLruCore<K, V, I, P, T> : ICache<K, V>, IAsyncCache<K, V>,
53
53
// if mutate methods are called. Therefore, field must be mutable to maintain count.
54
54
protected T telemetryPolicy ;
55
55
56
- private readonly CachePolicy policy ;
57
-
58
56
public ConcurrentLruCore (
59
57
int concurrencyLevel ,
60
58
ICapacityPartition capacity ,
@@ -85,8 +83,6 @@ public ConcurrentLruCore(
85
83
this . itemPolicy = itemPolicy ;
86
84
this . telemetryPolicy = telemetryPolicy ;
87
85
this . telemetryPolicy . SetEventSource ( this ) ;
88
-
89
- this . policy = new CachePolicy ( this , this ) ;
90
86
}
91
87
92
88
// No lock count: https://arbel.net/2013/02/03/best-practices-for-using-concurrentdictionary/
@@ -102,6 +98,8 @@ public ConcurrentLruCore(
102
98
///<inheritdoc/>
103
99
public ICacheEvents < K , V > Events => new Proxy ( this ) ;
104
100
101
+ public CachePolicy Policy => CreatePolicy ( this ) ;
102
+
105
103
public int HotCount => this . hotCount ;
106
104
107
105
public int WarmCount => this . warmCount ;
@@ -113,12 +111,6 @@ public ConcurrentLruCore(
113
111
/// </summary>
114
112
public ICollection < K > Keys => this . dictionary . Keys ;
115
113
116
- public CachePolicy Policy => this . policy ;
117
-
118
- public bool CanExpire => this . itemPolicy . CanDiscard ( ) ;
119
-
120
- public TimeSpan TimeToLive => this . itemPolicy . TimeToLive ;
121
-
122
114
/// <summary>Returns an enumerator that iterates through the cache.</summary>
123
115
/// <returns>An enumerator for the cache.</returns>
124
116
/// <remarks>
@@ -350,11 +342,11 @@ public void Trim(int itemCount)
350
342
TrimLiveItems ( itemsRemoved , itemCount , capacity ) ;
351
343
}
352
344
353
- public void TrimExpired ( )
345
+ private void TrimExpired ( )
354
346
{
355
347
if ( this . itemPolicy . CanDiscard ( ) )
356
348
{
357
- TrimAllDiscardedItems ( ) ;
349
+ this . TrimAllDiscardedItems ( ) ;
358
350
}
359
351
}
360
352
@@ -631,14 +623,20 @@ IEnumerator IEnumerable.GetEnumerator()
631
623
return ( ( ConcurrentLruCore < K , V , I , P , T > ) this ) . GetEnumerator ( ) ;
632
624
}
633
625
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
+
634
632
// To get JIT optimizations, policies must be structs.
635
633
// If the structs are returned directly via properties, they will be copied. Since
636
634
// telemetryPolicy is a mutable struct, copy is bad. One workaround is to store the
637
635
// state within the struct in an object. Since the struct points to the same object
638
636
// it becomes immutable. However, this object is then somewhere else on the
639
637
// heap, which slows down the policies with hit counter logic in benchmarks. Likely
640
638
// 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
642
640
{
643
641
private readonly ConcurrentLruCore < K , V , I , P , T > lru ;
644
642
@@ -659,11 +657,27 @@ public Proxy(ConcurrentLruCore<K, V, I, P, T> lru)
659
657
660
658
public bool IsEnabled => ( lru . telemetryPolicy as ICacheMetrics ) . IsEnabled ;
661
659
660
+ public int Capacity => lru . Capacity ;
661
+
662
+ public bool CanExpire => lru . itemPolicy . CanDiscard ( ) ;
663
+
664
+ public TimeSpan TimeToLive => lru . itemPolicy . TimeToLive ;
665
+
662
666
public event EventHandler < ItemRemovedEventArgs < K , V > > ItemRemoved
663
667
{
664
668
add { this . lru . telemetryPolicy . ItemRemoved += value ; }
665
669
remove { this . lru . telemetryPolicy . ItemRemoved -= value ; }
666
670
}
671
+
672
+ public void Trim ( int itemCount )
673
+ {
674
+ lru . Trim ( itemCount ) ;
675
+ }
676
+
677
+ public void TrimExpired ( )
678
+ {
679
+ lru . TrimExpired ( ) ;
680
+ }
667
681
}
668
682
}
669
683
}
0 commit comments