Skip to content

Commit fd05912

Browse files
committed
Use FastCache.Cached as new image cache instead of implement it ourselves
1 parent b2a3ebc commit fd05912

File tree

3 files changed

+38
-52
lines changed

3 files changed

+38
-52
lines changed

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
<ItemGroup>
5151
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
52+
<PackageReference Include="FastCache.Cached" Version="1.8.2" />
5253
<PackageReference Include="Fody" Version="6.5.5">
5354
<PrivateAssets>all</PrivateAssets>
5455
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

Flow.Launcher.Infrastructure/Image/ImageCache.cs

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
using System.Linq;
55
using System.Threading;
66
using System.Windows.Media;
7+
using FastCache;
8+
using FastCache.Services;
79

810
namespace Flow.Launcher.Infrastructure.Image
911
{
10-
[Serializable]
1112
public class ImageUsage
1213
{
13-
1414
public int usage;
1515
public ImageSource imageSource;
1616

@@ -23,95 +23,77 @@ public ImageUsage(int usage, ImageSource image)
2323

2424
public class ImageCache
2525
{
26-
private const int MaxCached = 50;
27-
public ConcurrentDictionary<(string, bool), ImageUsage> Data { get; } = new();
28-
private const int permissibleFactor = 2;
29-
private SemaphoreSlim semaphore = new(1, 1);
26+
private const int MaxCached = 150;
3027

3128
public void Initialize(Dictionary<(string, bool), int> usage)
3229
{
3330
foreach (var key in usage.Keys)
3431
{
35-
Data[key] = new ImageUsage(usage[key], null);
32+
Cached<ImageUsage>.Save(key, new ImageUsage(usage[key], null), TimeSpan.MaxValue, MaxCached);
3633
}
3734
}
3835

3936
public ImageSource this[string path, bool isFullImage = false]
4037
{
4138
get
4239
{
43-
if (!Data.TryGetValue((path, isFullImage), out var value))
40+
if (!Cached<ImageUsage>.TryGet((path, isFullImage), out var value))
4441
{
4542
return null;
4643
}
47-
value.usage++;
48-
return value.imageSource;
4944

45+
value.Value.usage++;
46+
return value.Value.imageSource;
5047
}
5148
set
5249
{
53-
Data.AddOrUpdate(
54-
(path, isFullImage),
55-
new ImageUsage(0, value),
56-
(k, v) =>
57-
{
58-
v.imageSource = value;
59-
v.usage++;
60-
return v;
61-
}
62-
);
63-
64-
SliceExtra();
65-
66-
async void SliceExtra()
50+
if (Cached<ImageUsage>.TryGet((path, isFullImage), out var cached))
6751
{
68-
// To prevent the dictionary from drastically increasing in size by caching images, the dictionary size is not allowed to grow more than the permissibleFactor * maxCached size
69-
// This is done so that we don't constantly perform this resizing operation and also maintain the image cache size at the same time
70-
if (Data.Count > permissibleFactor * MaxCached)
71-
{
72-
await semaphore.WaitAsync().ConfigureAwait(false);
73-
// To delete the images from the data dictionary based on the resizing of the Usage Dictionary
74-
// Double Check to avoid concurrent remove
75-
if (Data.Count > permissibleFactor * MaxCached)
76-
foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key))
77-
Data.TryRemove(key, out _);
78-
semaphore.Release();
79-
}
52+
cached.Value.imageSource = value;
53+
cached.Value.usage++;
8054
}
55+
56+
Cached<ImageUsage>.Save((path, isFullImage), new ImageUsage(0, value), TimeSpan.MaxValue,
57+
MaxCached);
8158
}
8259
}
8360

8461
public bool ContainsKey(string key, bool isFullImage)
8562
{
86-
return key is not null && Data.ContainsKey((key, isFullImage)) && Data[(key, isFullImage)].imageSource != null;
63+
return Cached<ImageUsage>.TryGet((key, isFullImage), out _);
8764
}
8865

8966
public bool TryGetValue(string key, bool isFullImage, out ImageSource image)
9067
{
91-
if (key is not null)
92-
{
93-
bool hasKey = Data.TryGetValue((key, isFullImage), out var imageUsage);
94-
image = hasKey ? imageUsage.imageSource : null;
95-
return hasKey;
96-
}
97-
else
68+
if (Cached<ImageUsage>.TryGet((key, isFullImage), out var value))
9869
{
99-
image = null;
100-
return false;
70+
image = value.Value.imageSource;
71+
value.Value.usage++;
72+
return image != null;
10173
}
74+
75+
image = null;
76+
return false;
10277
}
10378

10479
public int CacheSize()
10580
{
106-
return Data.Count;
81+
return CacheManager.TotalCount<(string, bool), ImageUsage>();
10782
}
10883

10984
/// <summary>
11085
/// return the number of unique images in the cache (by reference not by checking images content)
11186
/// </summary>
11287
public int UniqueImagesInCache()
11388
{
114-
return Data.Values.Select(x => x.imageSource).Distinct().Count();
89+
return CacheManager.EnumerateEntries<(string, bool), ImageUsage>().Select(x => x.Value.imageSource)
90+
.Distinct()
91+
.Count();
92+
}
93+
94+
public IEnumerable<Cached<(string, bool), ImageUsage>> EnumerateEntries()
95+
{
96+
return CacheManager.EnumerateEntries<(string, bool), ImageUsage>();
11597
}
11698
}
11799
}

Flow.Launcher.Infrastructure/Image/ImageLoader.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static async Task InitializeAsync()
4949
{
5050
await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () =>
5151
{
52-
foreach (var ((path, isFullImage), _) in ImageCache.Data)
52+
foreach (var ((path, isFullImage), _) in usage)
5353
{
5454
await LoadAsync(path, isFullImage);
5555
}
@@ -65,7 +65,7 @@ public static async Task Save()
6565

6666
try
6767
{
68-
_storage.SaveAsync(ImageCache.Data
68+
await _storage.SaveAsync(ImageCache.EnumerateEntries()
6969
.ToDictionary(
7070
x => x.Key,
7171
x => x.Value.usage));
@@ -125,9 +125,12 @@ private static async ValueTask<ImageResult> LoadInternalAsync(string path, bool
125125
return new ImageResult(MissingImage, ImageType.Error);
126126
}
127127

128-
if (ImageCache.ContainsKey(path, loadFullImage))
128+
// extra scope for use of same variable name
129129
{
130-
return new ImageResult(ImageCache[path, loadFullImage], ImageType.Cache);
130+
if (ImageCache.TryGetValue(path, loadFullImage, out var imageSource))
131+
{
132+
return new ImageResult(imageSource, ImageType.Cache);
133+
}
131134
}
132135

133136
if (Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out var uriResult)

0 commit comments

Comments
 (0)