Skip to content

Commit 18c2523

Browse files
committed
.NET 8
1 parent 66c8579 commit 18c2523

13 files changed

Lines changed: 145 additions & 247 deletions

DigitalRuby.SimpleCache.Sandbox/CacheTestService.cs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,15 @@
33
/// <summary>
44
/// Test caching
55
/// </summary>
6-
public sealed class CacheTestService : BackgroundService
6+
/// <remarks>
7+
/// Constructor
8+
/// </remarks>
9+
/// <param name="cache">Cache</param>
10+
/// <param name="logger">Logger</param>
11+
public sealed class CacheTestService(ILayeredCache cache, ILogger<CacheTestService> logger) : BackgroundService
712
{
8-
private readonly ILayeredCache cache;
9-
private readonly ILogger logger;
10-
11-
/// <summary>
12-
/// Constructor
13-
/// </summary>
14-
/// <param name="cache">Cache</param>
15-
/// <param name="logger">Logger</param>
16-
public CacheTestService(ILayeredCache cache, ILogger<CacheTestService> logger)
17-
{
18-
this.cache = cache;
19-
this.logger = logger;
20-
}
13+
private readonly ILayeredCache cache = cache;
14+
private readonly ILogger logger = logger;
2115

2216
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2317
{
@@ -29,22 +23,22 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2923
{
3024
context.CacheParameters = duration;
3125
return Task.FromResult<string?>(value);
32-
}, stoppingToken);
26+
}, null, stoppingToken);
3327
logger.LogWarning("Cache get or create: {result}", result);
3428

35-
result = await cache.GetAsync<string>("test2");
29+
result = await cache.GetAsync<string>("test2", stoppingToken);
3630
logger.LogWarning("Key not exists: {result}", result);
3731

38-
result = await cache.GetAsync<string>(key);
32+
result = await cache.GetAsync<string>(key, stoppingToken);
3933
logger.LogWarning("Key exists: {result}", result);
4034

41-
await cache.DeleteAsync<string>(key);
35+
await cache.DeleteAsync<string>(key, stoppingToken);
4236

43-
result = await cache.GetAsync<string>(key);
37+
result = await cache.GetAsync<string>(key, stoppingToken);
4438
logger.LogWarning("Key exists after delete: {result}", result);
4539

46-
await cache.SetAsync<string>(key, value, duration);
47-
result = await cache.GetAsync<string>(key);
40+
await cache.SetAsync<string>(key, value, duration, stoppingToken);
41+
result = await cache.GetAsync<string>(key, stoppingToken);
4842
logger.LogWarning("Key exists after set: {result}", result);
4943

5044
}

DigitalRuby.SimpleCache.Sandbox/DigitalRuby.SimpleCache.Sandbox.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net6.0</TargetFramework>
5+
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
</PropertyGroup>

DigitalRuby.SimpleCache.Tests/DigitalRuby.SimpleCache.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77

DigitalRuby.SimpleCache.Tests/FileCacheTests.cs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,10 @@ namespace DigitalRuby.SimpleCache.Tests;
33
/// <summary>
44
/// File cache tests
55
/// </summary>
6-
public sealed class FileCacheTests : IClockHandler, IDiskSpace
6+
public sealed class FileCacheTests : TimeProvider, IDiskSpace
77
{
8-
/// <inheritdoc />
9-
public DateTimeOffset UtcNow { get; set; }
10-
11-
/// <inheritdoc />
12-
Task IClockHandler.DelayAsync(TimeSpan interval, CancellationToken cancelToken)
13-
{
14-
return Task.CompletedTask;
15-
}
8+
public override DateTimeOffset GetUtcNow() => utcNow;
9+
private DateTimeOffset utcNow = DateTimeOffset.UtcNow;
1610

1711
/// <summary>
1812
/// Mock disk space
@@ -40,7 +34,7 @@ public async Task TestFileCache()
4034
const int testCount = 10;
4135
const string data = "74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F74956375-DD97-4857-816E-188BC8D4090F";
4236

43-
UtcNow = new DateTimeOffset(2022, 1, 1, 1, 1, 1, TimeSpan.Zero);
37+
utcNow = new DateTimeOffset(2022, 1, 1, 1, 1, 1, TimeSpan.Zero);
4438
using FileCache fileCache = new(new() { FreeSpaceThreshold = 20 }, new JsonLZ4Serializer(), this, this, new NullLogger<FileCache>());
4539

4640
var item = await fileCache.GetAsync<string>("key1");
@@ -51,8 +45,8 @@ public async Task TestFileCache()
5145
Assert.That(item, Is.Not.Null);
5246
Assert.That(item.Item, Is.EqualTo(data));
5347

54-
// step time, item should expire out
55-
UtcNow += TimeSpan.FromSeconds(6.0);
48+
// step time, item should expire out
49+
utcNow += TimeSpan.FromSeconds(6.0);
5650
await fileCache.CleanupFreeSpaceAsync();
5751
item = await fileCache.GetAsync<string>("key1");
5852
Assert.That(item, Is.Null);
@@ -69,7 +63,7 @@ public async Task TestFileCache()
6963
Stopwatch sw = Stopwatch.StartNew();
7064

7165
// put in a bunch of items
72-
List<Task> tasks = new();
66+
List<Task> tasks = [];
7367
for (int i = 0; i < testCount; i++)
7468
{
7569
int iCopy = i;
@@ -99,8 +93,8 @@ public async Task TestFileCache()
9993
Console.WriteLine("Read {0} items in {1} ms", testCount, sw.Elapsed.TotalMilliseconds);
10094
sw.Restart();
10195

102-
// step time, item should expire out
103-
UtcNow += TimeSpan.FromSeconds(6.0);
96+
// step time, item should expire out
97+
utcNow += TimeSpan.FromSeconds(6.0);
10498

10599
for (int i = 0; i < testCount; i++)
106100
{

DigitalRuby.SimpleCache.Tests/LayeredCacheTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/// Tests for layered cache
55
/// </summary>
66
[TestFixture]
7-
public sealed class LayeredCacheTests : IDiskSpace, IClockHandler, IOptions<MemoryCacheOptions>, Microsoft.Extensions.Internal.ISystemClock
7+
public sealed class LayeredCacheTests : TimeProvider, ISystemClock, IDiskSpace, IOptions<MemoryCacheOptions>
88
{
99
/// <summary>
1010
/// Setup
@@ -31,7 +31,7 @@ public void Setup()
3131
public async Task TestGetOrCreatePreventsCacheStorm()
3232
{
3333
ManualResetEvent evt = new(false);
34-
List<Task> tasks = new();
34+
List<Task> tasks = [];
3535
int cacheMiss = 0;
3636
for (int i = 0; i < 1000; i++)
3737
{
@@ -154,7 +154,7 @@ public async Task TestCachePrimitive()
154154
await layeredCache.SetAsync(testKey, 1, expire);
155155
foundValue = await layeredCache.GetAsync<int>(testKey);
156156
Assert.That(foundValue, Is.EqualTo(1));
157-
UtcNow += expire;
157+
UtcNow += expire; // cache should clear
158158
foundValue = await layeredCache.GetAsync<int>(testKey);
159159
Assert.That(foundValue, Is.EqualTo(0));
160160
}
@@ -236,7 +236,7 @@ public async Task TestNull()
236236
/// </summary>
237237
/// <param name="handle">Wait handle</param>
238238
/// <returns>Task</returns>
239-
private static Task AsTask(WaitHandle handle)
239+
private static Task<object> AsTask(WaitHandle handle)
240240
{
241241
TaskCompletionSource<object> tcs = new();
242242
TimeSpan timeout = TimeSpan.FromMinutes(1.0);
@@ -263,7 +263,7 @@ private static Task AsTask(WaitHandle handle)
263263
private static readonly TimeSpan expire = TimeSpan.FromSeconds(30.0);
264264

265265
private readonly ISerializer serializer = new JsonSerializer();
266-
private readonly Dictionary<string, long> fileSpaces = new();
266+
private readonly Dictionary<string, long> fileSpaces = [];
267267

268268
private MemoryCache memoryCache;
269269
private MemoryFileCache fileCache;
@@ -284,7 +284,7 @@ private static Task AsTask(WaitHandle handle)
284284
public DateTimeOffset UtcNow { get; set; }
285285

286286
/// <inheritdoc />
287-
Task IClockHandler.DelayAsync(System.TimeSpan interval, System.Threading.CancellationToken cancelToken) => Task.Delay(0, cancelToken);
287+
public override DateTimeOffset GetUtcNow() => UtcNow;
288288

289289
long IDiskSpace.GetFileSize(string fileName)
290290
{

DigitalRuby.SimpleCache/ClockHandler.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.

DigitalRuby.SimpleCache/DigitalRuby.SimpleCache.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
88
<GenerateDocumentationFile>true</GenerateDocumentationFile>
99
<IsPackable>true</IsPackable>
10-
<Version>1.0.17</Version>
10+
<Version>2.0.0</Version>
1111
<Title>Simple Cache</Title>
1212
<Authors>jjxtra</Authors>
1313
<Company>Digital Ruby, LLC</Company>
@@ -18,7 +18,7 @@
1818
<PackageReadmeFile>README.md</PackageReadmeFile>
1919
<RepositoryUrl>https://github.com/DigitalRuby/SimplePubSub</RepositoryUrl>
2020
<PackageTags>cache;simple;easy;ram;memory;file;disk;redis;distributed;idistributedcache;iconnectionmultiplexer;lock;distributedlock;stackexchange;stackoverflow;connectionmultiplexer;lazy;task;storm;lazycache;caching;invalidation;expiration;synchronization;powerful;layer;layers;layered;layeredcache</PackageTags>
21-
<PackageReleaseNotes>Use Random.Shared for cache jitter</PackageReleaseNotes>
21+
<PackageReleaseNotes>.NET 8</PackageReleaseNotes>
2222
<AssemblyVersion></AssemblyVersion>
2323
<FileVersion></FileVersion>
2424
<PackageLicenseExpression>MIT</PackageLicenseExpression>

DigitalRuby.SimpleCache/DistributedCache.cs

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,15 @@ public Task SetAsync(string key, DistributedCacheItem item, CancellationToken ca
9797
/// <summary>
9898
/// Distributed cache but all in memory (for testing)
9999
/// </summary>
100-
public sealed class DistributedMemoryCache : IDistributedCache, IDistributedLockFactory
100+
/// <remarks>
101+
/// Constructor
102+
/// </remarks>
103+
/// <param name="clock">Clock</param>
104+
public sealed class DistributedMemoryCache(TimeProvider clock) : IDistributedCache, IDistributedLockFactory
101105
{
102-
private readonly Microsoft.Extensions.Internal.ISystemClock clock;
106+
private readonly TimeProvider clock = clock;
103107

104-
/// <summary>
105-
/// Constructor
106-
/// </summary>
107-
/// <param name="clock">Clock</param>
108-
public DistributedMemoryCache(Microsoft.Extensions.Internal.ISystemClock clock) => this.clock = clock;
109-
110-
internal sealed class FakeDistributedLock : IAsyncDisposable
108+
internal sealed class FakeDistributedLock : IAsyncDisposable
111109
{
112110
public ValueTask DisposeAsync()
113111
{
@@ -133,9 +131,9 @@ public Task DeleteAsync(string key, CancellationToken cancelToken = default)
133131
/// <inheritdoc />
134132
public Task<DistributedCacheItem> GetAsync(string key, CancellationToken cancelToken = default)
135133
{
136-
if (items.TryGetValue(key, out var item) && item.Item1 > clock.UtcNow)
134+
if (items.TryGetValue(key, out var item) && item.Item1 > clock.GetUtcNow())
137135
{
138-
return Task.FromResult(new DistributedCacheItem { Bytes = item.Item2, Expiry = item.Item1 - clock.UtcNow });
136+
return Task.FromResult(new DistributedCacheItem { Bytes = item.Item2, Expiry = item.Item1 - clock.GetUtcNow() });
139137
}
140138
return Task.FromResult<DistributedCacheItem>(default);
141139
}
@@ -145,7 +143,7 @@ public Task SetAsync(string key, DistributedCacheItem item, CancellationToken ca
145143
{
146144
if (item.Bytes is not null)
147145
{
148-
DateTimeOffset expire = clock.UtcNow + item.Expiry ?? throw new ArgumentException("Null expiry not allowed");
146+
DateTimeOffset expire = clock.GetUtcNow() + item.Expiry ?? throw new ArgumentException("Null expiry not allowed");
149147
items[key] = new(expire, item.Bytes);
150148
}
151149
return Task.CompletedTask;
@@ -306,20 +304,13 @@ private void RegisterChangeQueue()
306304
}
307305
}
308306

309-
private class DistributedLock : IAsyncDisposable
307+
private class DistributedLock(IConnectionMultiplexer connection, string lockKey, string lockToken) : IAsyncDisposable
310308
{
311-
private readonly IConnectionMultiplexer connection;
312-
private readonly string lockKey;
313-
private readonly string lockToken;
314-
315-
public DistributedLock(IConnectionMultiplexer connection, string lockKey, string lockToken)
316-
{
317-
this.connection = connection;
318-
this.lockKey = lockKey;
319-
this.lockToken = lockToken;
320-
}
309+
private readonly IConnectionMultiplexer connection = connection;
310+
private readonly string lockKey = lockKey;
311+
private readonly string lockToken = lockToken;
321312

322-
public async ValueTask DisposeAsync()
313+
public async ValueTask DisposeAsync()
323314
{
324315
await connection.GetDatabase().LockReleaseAsync(lockKey, lockToken);
325316
}

0 commit comments

Comments
 (0)