Skip to content

Commit c71264d

Browse files
committed
Prevent flooding the thread pool by eviction callbacks
1 parent 30595bd commit c71264d

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

FastCache/FastCache.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public void EvictExpired()
6363
//Eviction already started by another thread? forget it, lets move on
6464
if (Monitor.TryEnter(_cleanUpTimer)) //use the timer-object for our lock, it's local, private and instance-type, so its ok
6565
{
66+
List<TKey> evictedKeys = null; // Batch eviction callbacks
6667
try
6768
{
6869
//cache current tick count in a var to prevent calling it every iteration inside "IsExpired()" in a tight loop.
@@ -75,15 +76,21 @@ public void EvictExpired()
7576
{
7677
if (p.Value.IsExpired(currTime)) //call IsExpired with "currTime" to avoid calling Environment.TickCount64 multiple times
7778
{
78-
_dict.TryRemove(p);
79-
OnEviction(p.Key);
79+
if (_dict.TryRemove(p) && _itemEvicted != null) // collect key for later batch processing (only if callback exists)
80+
{
81+
evictedKeys ??= new List<TKey>(); //lazy initialize the list
82+
evictedKeys.Add(p.Key);
83+
}
8084
}
8185
}
8286
}
8387
finally
8488
{
8589
Monitor.Exit(_cleanUpTimer);
8690
}
91+
92+
// Trigger batched eviction callbacks outside the loop to prevent flooding the thread pool
93+
OnEviction(evictedKeys);
8794
}
8895
}
8996

@@ -163,7 +170,7 @@ public bool TryGet(TKey key, out TValue value)
163170
*
164171
* */
165172

166-
OnEviction(key);
173+
Task.Run(() => OnEviction(key));
167174

168175
return false;
169176
}
@@ -203,7 +210,7 @@ private TValue GetOrAddCore(TKey key, Func<TValue> valueFactory, TimeSpan ttl)
203210
if (!wasAdded) //performance hack: skip expiration check if a brand item was just added
204211
{
205212
if (ttlValue.ModifyIfExpired(valueFactory, ttl))
206-
OnEviction(key);
213+
Task.Run(() => OnEviction(key));
207214
}
208215

209216
return ttlValue.Value;
@@ -288,6 +295,25 @@ private void OnEviction(TKey key)
288295
});
289296
}
290297

298+
// same as OnEviction(TKey) but for batching
299+
private void OnEviction(List<TKey> keys)
300+
{
301+
if (keys == null || keys.Count == 0) return;
302+
if (_itemEvicted == null) return;
303+
304+
Task.Run(() => //run on thread pool to avoid blocking
305+
{
306+
try
307+
{
308+
foreach (var key in keys)
309+
{
310+
_itemEvicted(key);
311+
}
312+
}
313+
catch { } //to prevent any exceptions from crashing the thread
314+
});
315+
}
316+
291317
private class TtlValue
292318
{
293319
public TValue Value { get; private set; }

0 commit comments

Comments
 (0)