diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 60a191a9c..8f57928cb 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -11,61 +11,65 @@ namespace Flow.Launcher.Infrastructure.Image public class ImageCache { private const int MaxCached = 50; - public ConcurrentDictionary Usage = new ConcurrentDictionary(); - private readonly ConcurrentDictionary _data = new ConcurrentDictionary(); + public ConcurrentDictionary Data { get; private set; } = new ConcurrentDictionary(); private const int permissibleFactor = 2; + public void Initialization(Dictionary 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(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; } /// @@ -73,7 +77,7 @@ namespace Flow.Launcher.Infrastructure.Image /// public int UniqueImagesInCache() { - return _data.Values.Distinct().Count(); + return Data.Values.Select(x => x.imageSource).Distinct().Count(); } } diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index a1b677a16..edfb88cbf 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -35,7 +35,7 @@ namespace Flow.Launcher.Infrastructure.Image _storage = new BinaryStorage>("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(ImageCache.Usage)); + _storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, y => y.usage)); } } private static ConcurrentDictionary LoadStorageToConcurrentDictionary() { - lock(_storage) + lock (_storage) { var loaded = _storage.TryLoad(new Dictionary()); @@ -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