@@ -9,7 +9,7 @@ namespace Jitbit.Utils
99 /// <summary>
1010 /// faster MemoryCache alternative. basically a concurrent dictionary with expiration
1111 /// </summary>
12- public class FastCache < TKey , TValue > : IEnumerable < KeyValuePair < TKey , TValue > >
12+ public class FastCache < TKey , TValue > : IEnumerable < KeyValuePair < TKey , TValue > > , IDisposable
1313 {
1414 private readonly ConcurrentDictionary < TKey , TtlValue > _dict = new ConcurrentDictionary < TKey , TtlValue > ( ) ;
1515
@@ -25,10 +25,21 @@ public FastCache(int cleanupJobInterval = 10000)
2525
2626 void _EvictExpired ( object state )
2727 {
28- foreach ( var p in _dict )
28+ //overlapped execution? forget it, lets move on
29+ if ( Monitor . TryEnter ( this ) )
2930 {
30- if ( p . Value . IsExpired ( ) )
31- _dict . TryRemove ( p . Key , out _ ) ;
31+ try
32+ {
33+ foreach ( var p in _dict )
34+ {
35+ if ( p . Value . IsExpired ( ) )
36+ _dict . TryRemove ( p . Key , out _ ) ;
37+ }
38+ }
39+ finally
40+ {
41+ Monitor . Exit ( this ) ;
42+ }
3243 }
3344 }
3445 }
@@ -137,7 +148,7 @@ public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory, TimeSpan ttl)
137148 if ( TryGet ( key , out var value ) )
138149 return value ;
139150
140- return _dict . GetOrAdd ( key , k => new TtlValue ( valueFactory ( key ) , ttl ) ) . Value ;
151+ return _dict . GetOrAdd ( key , ( k , v ) => new TtlValue ( valueFactory ( k ) , v ) , ttl ) . Value ;
141152 }
142153
143154 /// <summary>
@@ -180,5 +191,19 @@ public bool IsExpired()
180191 return difference > 0 ;
181192 }
182193 }
194+
195+ //IDispisable members
196+ private bool _disposedValue ;
197+ public void Dispose ( ) => Dispose ( true ) ;
198+ protected virtual void Dispose ( bool disposing )
199+ {
200+ if ( ! _disposedValue )
201+ {
202+ if ( disposing )
203+ _cleanUpTimer . Dispose ( ) ;
204+
205+ _disposedValue = true ;
206+ }
207+ }
183208 }
184209}
0 commit comments