mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
refactor Image Cache to single dictionary
This commit is contained in:
parent
d3d69be9c2
commit
bf271b9da7
2 changed files with 37 additions and 37 deletions
|
|
@ -11,61 +11,65 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
public class ImageCache
|
||||
{
|
||||
private const int MaxCached = 50;
|
||||
public ConcurrentDictionary<string, int> Usage = new ConcurrentDictionary<string, int>();
|
||||
private readonly ConcurrentDictionary<string, ImageSource> _data = new ConcurrentDictionary<string, ImageSource>();
|
||||
public ConcurrentDictionary<string, (int usage, ImageSource imageSource)> Data { get; private set; } = new ConcurrentDictionary<string, (int, ImageSource)>();
|
||||
private const int permissibleFactor = 2;
|
||||
|
||||
public void Initialization(Dictionary<string, int> usage)
|
||||
{
|
||||
foreach (var key in usage.Keys)
|
||||
{
|
||||
Data[key] = (usage[key], null);
|
||||
}
|
||||
}
|
||||
|
||||
public ImageSource this[string path]
|
||||
{
|
||||
get
|
||||
{
|
||||
Usage.AddOrUpdate(path, 1, (k, v) => v + 1);
|
||||
var i = _data[path];
|
||||
return i;
|
||||
if (Data.TryGetValue(path, out var value))
|
||||
{
|
||||
value.usage++;
|
||||
return value.imageSource;
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
_data[path] = value;
|
||||
Data.AddOrUpdate(path, (1, value), (k, v) =>
|
||||
{
|
||||
v.imageSource = value;
|
||||
v.usage++;
|
||||
return v;
|
||||
});
|
||||
|
||||
// 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
|
||||
// This is done so that we don't constantly perform this resizing operation and also maintain the image cache size at the same time
|
||||
if (_data.Count > permissibleFactor * MaxCached)
|
||||
if (Data.Count > permissibleFactor * MaxCached)
|
||||
{
|
||||
// This function resizes the Usage dictionary, taking the top 'maxCached' number of items and filtering the image icons that are not accessed frequently.
|
||||
Cleanup();
|
||||
|
||||
// To delete the images from the data dictionary based on the resizing of the Usage Dictionary.
|
||||
foreach (var key in _data.Keys)
|
||||
|
||||
|
||||
foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key))
|
||||
{
|
||||
int dictValue;
|
||||
if (!Usage.TryGetValue(key, out dictValue) && !(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon)))
|
||||
if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon)))
|
||||
{
|
||||
ImageSource imgSource;
|
||||
_data.TryRemove(key, out imgSource);
|
||||
Data.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
var images = Usage
|
||||
.OrderByDescending(o => o.Value)
|
||||
.Take(MaxCached)
|
||||
.ToDictionary(i => i.Key, i => i.Value);
|
||||
Usage = new ConcurrentDictionary<string, int>(images);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
var contains = _data.ContainsKey(key);
|
||||
var contains = Data.ContainsKey(key);
|
||||
return contains;
|
||||
}
|
||||
|
||||
public int CacheSize()
|
||||
{
|
||||
return _data.Count;
|
||||
return Data.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -73,7 +77,7 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
/// </summary>
|
||||
public int UniqueImagesInCache()
|
||||
{
|
||||
return _data.Values.Distinct().Count();
|
||||
return Data.Values.Select(x => x.imageSource).Distinct().Count();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
_storage = new BinaryStorage<Dictionary<string, int>>("Image");
|
||||
_hashGenerator = new ImageHashGenerator();
|
||||
|
||||
ImageCache.Usage = LoadStorageToConcurrentDictionary();
|
||||
var usage = LoadStorageToConcurrentDictionary();
|
||||
|
||||
foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon })
|
||||
{
|
||||
|
|
@ -48,12 +48,12 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
{
|
||||
Stopwatch.Normal("|ImageLoader.Initialize|Preload images cost", () =>
|
||||
{
|
||||
ImageCache.Usage.AsParallel().ForAll(x =>
|
||||
ImageCache.Data.AsParallel().ForAll(x =>
|
||||
{
|
||||
Load(x.Key);
|
||||
});
|
||||
});
|
||||
Log.Info($"|ImageLoader.Initialize|Number of preload images is <{ImageCache.Usage.Count}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
|
||||
Log.Info($"|ImageLoader.Initialize|Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -61,14 +61,13 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
{
|
||||
lock (_storage)
|
||||
{
|
||||
ImageCache.Cleanup();
|
||||
_storage.Save(new Dictionary<string, int>(ImageCache.Usage));
|
||||
_storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, y => y.usage));
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<string, int> LoadStorageToConcurrentDictionary()
|
||||
{
|
||||
lock(_storage)
|
||||
lock (_storage)
|
||||
{
|
||||
var loaded = _storage.TryLoad(new Dictionary<string, int>());
|
||||
|
||||
|
|
@ -222,13 +221,10 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null;
|
||||
if (hash != null)
|
||||
{
|
||||
int ImageCacheValue;
|
||||
|
||||
if (GuidToKey.TryGetValue(hash, out string key))
|
||||
{ // image already exists
|
||||
if (ImageCache.Usage.TryGetValue(path, out ImageCacheValue))
|
||||
{
|
||||
img = ImageCache[key];
|
||||
}
|
||||
img = ImageCache[key] ?? img;
|
||||
}
|
||||
else
|
||||
{ // new guid
|
||||
|
|
|
|||
Loading…
Reference in a new issue