Skip to content

Commit a18edfe

Browse files
committed
Added "Touch" method for sliding expiration support.
1 parent eff422a commit a18edfe

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

FastCache/FastCache.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,19 @@ public TValue GetOrAdd<TArg>(TKey key, Func<TKey, TArg, TValue> valueFactory, Ti
274274
public TValue GetOrAdd(TKey key, TValue value, TimeSpan ttl)
275275
=> GetOrAddCore(key, static (_, v) => v, value, (long)ttl.TotalMilliseconds);
276276

277+
/// <summary>
278+
/// Resets the TTL for an existing (non-expired) item, essentially implementing "sliding expiration"
279+
/// </summary>
280+
/// <param name="key">The key to touch</param>
281+
/// <param name="ttl">The new TTL to set</param>
282+
public void Touch(TKey key, TimeSpan ttl)
283+
{
284+
if (_dict.TryGetValue(key, out var ttlValue))
285+
{
286+
ttlValue.ResetExpiration(ttl);
287+
}
288+
}
289+
277290
/// <summary>
278291
/// Tries to remove item with the specified key
279292
/// </summary>
@@ -368,6 +381,11 @@ public TtlValue(TValue value, TimeSpan ttl)
368381
[MethodImpl(MethodImplOptions.AggressiveInlining)]
369382
public bool IsExpired(long currTime) => currTime > TickCountWhenToKill;
370383

384+
public void ResetExpiration(TimeSpan ttl)
385+
{
386+
TickCountWhenToKill = Environment.TickCount64 + (long)ttl.TotalMilliseconds;
387+
}
388+
371389
/// <summary>
372390
/// Updates the value and TTL only if the item is expired, using a factory function
373391
/// </summary>

UnitTests/UnitTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,5 +244,19 @@ public async Task TestTtlExtended()
244244
Assert.IsTrue(_cache.TryGet(42, out int result2)); //still not evicted
245245
Assert.AreEqual(42, result2);
246246
}
247+
248+
[TestMethod]
249+
public async Task TestTouch()
250+
{
251+
using var _cache = new FastCache<int, int>();
252+
_cache.AddOrUpdate(42, 42, TimeSpan.FromMilliseconds(200));
253+
254+
await Task.Delay(150);
255+
_cache.Touch(42, TimeSpan.FromMilliseconds(200)); //reset TTL
256+
257+
await Task.Delay(150); //300ms total, would have expired without Touch
258+
Assert.IsTrue(_cache.TryGet(42, out int v));
259+
Assert.AreEqual(42, v);
260+
}
247261
}
248262
}

0 commit comments

Comments
 (0)