Skip to content

Commit 0f8e1df

Browse files
authored
Merge pull request #206 from TurnerSoftware/remove-abstract-cacheentry
Remove Abstract CacheEntry / Use C# Records
2 parents 912a95b + b4878fe commit 0f8e1df

4 files changed

Lines changed: 72 additions & 97 deletions

File tree

src/CacheTower.Serializers.Protobuf/ProtobufCacheSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private static class SerializerConfig<T>
3434
{
3535
static SerializerConfig()
3636
{
37-
if (typeof(T).IsSubclassOf(typeof(CacheEntry)))
37+
if (typeof(ICacheEntry).IsAssignableFrom(typeof(T)))
3838
{
3939
RuntimeTypeModel.Default.Add(typeof(T))
4040
.Add(1, nameof(CacheEntry<object>.Expiry))

src/CacheTower/CacheEntry.cs

Lines changed: 64 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,84 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Runtime.CompilerServices;
4-
using System.Text;
53
using CacheTower.Internal;
64

7-
namespace CacheTower
5+
namespace CacheTower;
6+
7+
/// <summary>
8+
/// Container for the cache entry expiry date.
9+
/// </summary>
10+
public interface ICacheEntry
811
{
912
/// <summary>
10-
/// Container for the cache entry expiry date.
13+
/// The expiry date for the cache entry.
1114
/// </summary>
12-
public abstract class CacheEntry
13-
{
14-
/// <summary>
15-
/// The expiry date for the cache entry.
16-
/// </summary>
17-
public DateTime Expiry { get; }
18-
19-
/// <summary>
20-
/// Creates a new <see cref="CacheEntry"/> with the given expiry date.
21-
/// </summary>
22-
/// <param name="expiry">The expiry date of the cache entry. This will be rounded down to the second.</param>
23-
protected CacheEntry(DateTime expiry)
24-
{
25-
//Force the resolution of the expiry date to be to the second
26-
Expiry = new DateTime(
27-
expiry.Year, expiry.Month, expiry.Day, expiry.Hour, expiry.Minute, expiry.Second, DateTimeKind.Utc
28-
);
29-
}
15+
DateTime Expiry { get; }
16+
}
3017

31-
/// <summary>
32-
/// Calculates the stale date for the cache entry using the provided <paramref name="cacheSettings"/>.
33-
/// </summary>
34-
/// <remarks>
35-
/// If <see cref="CacheSettings.StaleAfter"/> is not configured, the stale date is the expiry date.
36-
/// </remarks>
37-
/// <param name="cacheSettings">The cache settings to use for the calculation.</param>
38-
/// <returns>The date that the cache entry can be considered stale.</returns>
39-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
40-
public DateTime GetStaleDate(CacheSettings cacheSettings)
41-
{
42-
if (cacheSettings.StaleAfter.HasValue)
43-
{
44-
return Expiry - cacheSettings.TimeToLive + cacheSettings.StaleAfter!.Value;
45-
}
46-
else
47-
{
48-
return Expiry;
49-
}
50-
}
51-
}
18+
/// <summary>
19+
/// Container for the cached value and its expiry date.
20+
/// </summary>
21+
/// <typeparam name="T"></typeparam>
22+
public interface ICacheEntry<T> : ICacheEntry
23+
{
24+
/// <summary>
25+
/// The cached value.
26+
/// </summary>
27+
T? Value { get; }
28+
}
5229

30+
/// <summary>
31+
/// Extension methods for <see cref="ICacheEntry"/>.
32+
/// </summary>
33+
public static class CacheEntryExtensions
34+
{
5335
/// <summary>
54-
/// Container for both the cached value and its expiry date.
36+
/// Calculates the stale date for an <see cref="ICacheEntry"/> based on the <paramref name="cacheEntry"/>'s expiry and <paramref name="cacheSettings"/>.
5537
/// </summary>
56-
/// <typeparam name="T"></typeparam>
57-
public class CacheEntry<T> : CacheEntry, IEquatable<CacheEntry<T?>?>
38+
/// <remarks>
39+
/// When <see cref="CacheSettings.StaleAfter"/> is <see langword="null"/>, this will return the <paramref name="cacheEntry"/>'s expiry.
40+
/// </remarks>
41+
/// <param name="cacheEntry">The cache entry to get the stale date for.</param>
42+
/// <param name="cacheSettings">The cache settings to use as part of the stale date calculation.</param>
43+
/// <returns></returns>
44+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
45+
public static DateTime GetStaleDate(this ICacheEntry cacheEntry, CacheSettings cacheSettings)
5846
{
59-
/// <summary>
60-
/// The cached value.
61-
/// </summary>
62-
public T? Value { get; }
63-
64-
/// <summary>
65-
/// Creates a new <see cref="CacheEntry"/> with the given <paramref name="value"/> and an expiry adjusted to the <paramref name="timeToLive"/>.
66-
/// </summary>
67-
/// <param name="value">The value to cache.</param>
68-
/// <param name="timeToLive">The amount of time before the cache entry expires.</param>
69-
internal CacheEntry(T? value, TimeSpan timeToLive) : this(value, DateTimeProvider.Now + timeToLive) { }
70-
/// <summary>
71-
/// Creates a new <see cref="CacheEntry"/> with the given <paramref name="value"/> and <paramref name="expiry"/>.
72-
/// </summary>
73-
/// <param name="value">The value to cache.</param>
74-
/// <param name="expiry">The expiry date of the cache entry. This will be rounded down to the second.</param>
75-
public CacheEntry(T? value, DateTime expiry) : base(expiry)
47+
if (cacheSettings.StaleAfter.HasValue)
7648
{
77-
Value = value;
49+
return cacheEntry.Expiry - cacheSettings.TimeToLive + cacheSettings.StaleAfter!.Value;
7850
}
79-
80-
/// <inheritdoc/>
81-
public bool Equals(CacheEntry<T?>? other)
51+
else
8252
{
83-
if (other == null)
84-
{
85-
return false;
86-
}
87-
88-
return Equals(Value, other.Value) &&
89-
Expiry == other.Expiry;
53+
return cacheEntry.Expiry;
9054
}
55+
}
56+
}
9157

92-
/// <inheritdoc/>
93-
public override bool Equals(object? obj)
94-
{
95-
if (obj is CacheEntry<T?> objOfType)
96-
{
97-
return Equals(objOfType);
98-
}
58+
/// <summary>
59+
/// Container for both the cached value and its expiry date.
60+
/// </summary>
61+
/// <typeparam name="T"></typeparam>
62+
/// <param name="Value">The value to cache.</param>
63+
/// <param name="Expiry">The expiry date of the cache entry. This will be rounded down to the second.</param>
64+
public sealed record CacheEntry<T>(T? Value, DateTime Expiry) : ICacheEntry<T>
65+
{
66+
/// <summary>
67+
/// The cached value.
68+
/// </summary>
69+
public T? Value { get; } = Value;
9970

100-
return false;
101-
}
71+
/// <summary>
72+
/// The expiry date for the cache entry.
73+
/// </summary>
74+
public DateTime Expiry { get; } = new DateTime(
75+
Expiry.Year, Expiry.Month, Expiry.Day, Expiry.Hour, Expiry.Minute, Expiry.Second, DateTimeKind.Utc
76+
);
10277

103-
/// <inheritdoc/>
104-
public override int GetHashCode()
105-
{
106-
return (Value?.GetHashCode() ?? 1) ^ Expiry.GetHashCode();
107-
}
108-
}
78+
/// <summary>
79+
/// Creates a new <see cref="ICacheEntry"/> with the given <paramref name="value"/> and an expiry adjusted to the <paramref name="timeToLive"/>.
80+
/// </summary>
81+
/// <param name="value">The value to cache.</param>
82+
/// <param name="timeToLive">The amount of time before the cache entry expires.</param>
83+
internal CacheEntry(T? value, TimeSpan timeToLive) : this(value, DateTimeProvider.Now + timeToLive) { }
10984
}

src/CacheTower/Internal/CacheEntryKeyLock.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace CacheTower.Internal;
77

88
internal readonly struct CacheEntryKeyLock
99
{
10-
private readonly Dictionary<string, TaskCompletionSource<CacheEntry>?> keyLocks = new(StringComparer.Ordinal);
10+
private readonly Dictionary<string, TaskCompletionSource<ICacheEntry>?> keyLocks = new(StringComparer.Ordinal);
1111

1212
public CacheEntryKeyLock() { }
1313

@@ -28,15 +28,15 @@ public bool AcquireLock(string cacheKey)
2828
}
2929
}
3030

31-
public Task<CacheEntry> WaitAsync(string cacheKey)
31+
public Task<ICacheEntry> WaitAsync(string cacheKey)
3232
{
33-
TaskCompletionSource<CacheEntry>? completionSource;
33+
TaskCompletionSource<ICacheEntry>? completionSource;
3434

3535
lock (keyLocks)
3636
{
3737
if (!keyLocks.TryGetValue(cacheKey, out completionSource) || completionSource == null)
3838
{
39-
completionSource = new TaskCompletionSource<CacheEntry>();
39+
completionSource = new TaskCompletionSource<ICacheEntry>();
4040
keyLocks[cacheKey] = completionSource;
4141
}
4242
}
@@ -45,7 +45,7 @@ public Task<CacheEntry> WaitAsync(string cacheKey)
4545
}
4646

4747
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48-
private bool TryRemove(string cacheKey, out TaskCompletionSource<CacheEntry>? completionSource)
48+
private bool TryRemove(string cacheKey, out TaskCompletionSource<ICacheEntry>? completionSource)
4949
{
5050
lock (keyLocks)
5151
{
@@ -62,7 +62,7 @@ private bool TryRemove(string cacheKey, out TaskCompletionSource<CacheEntry>? co
6262
}
6363
}
6464

65-
public void ReleaseLock(string cacheKey, CacheEntry cacheEntry)
65+
public void ReleaseLock(string cacheKey, ICacheEntry cacheEntry)
6666
{
6767
if (TryRemove(cacheKey, out var completionSource))
6868
{

src/CacheTower/Providers/Memory/MemoryCacheLayer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace CacheTower.Providers.Memory
1717
/// <inheritdoc cref="ICacheLayer"/>
1818
public class MemoryCacheLayer : ILocalCacheLayer
1919
{
20-
private readonly ConcurrentDictionary<string, CacheEntry> Cache = new(StringComparer.Ordinal);
20+
private readonly ConcurrentDictionary<string, ICacheEntry> Cache = new(StringComparer.Ordinal);
2121

2222
/// <inheritdoc/>
2323
public ValueTask CleanupAsync()

0 commit comments

Comments
 (0)