Use cache type directly instead of a new class, decouple binarystorage and storage

This commit is contained in:
bao-qian
2017-01-13 15:40:32 +00:00
parent a5aa305773
commit 4c6c310e0a
7 changed files with 70 additions and 86 deletions

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
namespace Wox.Infrastructure.Image
{
@@ -8,29 +10,35 @@ namespace Wox.Infrastructure.Image
public class ImageCache
{
private const int MaxCached = 200;
public ConcurrentDictionary<string, int> TopUsedImages = new ConcurrentDictionary<string, int>();
public ConcurrentDictionary<string, int> Usage = new ConcurrentDictionary<string, int>();
private readonly ConcurrentDictionary<string, ImageSource> _data = new ConcurrentDictionary<string, ImageSource>();
public void Add(string path)
public ImageSource this[string path]
{
if (TopUsedImages.ContainsKey(path))
get
{
TopUsedImages[path] = TopUsedImages[path] + 1;
}
else
{
TopUsedImages[path] = 1;
Usage.AddOrUpdate(path, 1, (k, v) => v + 1);
var i = _data[path];
return i;
}
set { _data[path] = value; }
}
public void Cleanup()
{
if (TopUsedImages.Count > MaxCached)
{
var images = TopUsedImages.OrderByDescending(o => o.Value)
.Take(MaxCached)
.ToDictionary(i => i.Key, i => i.Value);
TopUsedImages = new ConcurrentDictionary<string, int>(images);
}
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);
return contains;
}
}
}

View File

@@ -15,7 +15,8 @@ namespace Wox.Infrastructure.Image
{
public static class ImageLoader
{
private static readonly ConcurrentDictionary<string, ImageSource> ImageSources = new ConcurrentDictionary<string, ImageSource>();
private static readonly ImageCache ImageCache = new ImageCache();
private static readonly BinaryStorage<ConcurrentDictionary<string, int>> Storage;
private static readonly string[] ImageExtions =
@@ -29,19 +30,17 @@ namespace Wox.Infrastructure.Image
".ico"
};
private static readonly ImageCache _cache;
private static readonly BinaryStorage<ImageCache> _storage;
static ImageLoader()
{
_storage = new BinaryStorage<ImageCache>();
_cache = _storage.Load();
Storage = new BinaryStorage<ConcurrentDictionary<string, int>> ("ImageCache");
ImageCache.Usage = Storage.TryLoad(new ConcurrentDictionary<string, int>());
}
public static void Save()
{
_cache.Cleanup();
_storage.Save();
ImageCache.Cleanup();
Storage.Save(ImageCache.Usage);
}
private static ImageSource ShellIcon(string fileName)
@@ -78,7 +77,7 @@ namespace Wox.Infrastructure.Image
catch (System.Exception e)
{
Log.Exception(e);
return ImageSources[Constant.ErrorIcon];
return ImageCache[Constant.ErrorIcon];
}
}
@@ -88,22 +87,22 @@ namespace Wox.Infrastructure.Image
{
ImageSource img = new BitmapImage(new Uri(icon));
img.Freeze();
ImageSources[icon] = img;
ImageCache[icon] = img;
}
Task.Run(() =>
{
Stopwatch.Normal("Preload images from cache", () =>
{
_cache.TopUsedImages.AsParallel().Where(i => !ImageSources.ContainsKey(i.Key)).ForAll(i =>
ImageCache.Usage.AsParallel().Where(i => !ImageCache.ContainsKey(i.Key)).ForAll(i =>
{
var img = Load(i.Key);
if (img != null)
{
ImageSources[i.Key] = img;
ImageCache[i.Key] = img;
}
});
});
Log.Info($"Preload {_cache.TopUsedImages.Count} images from cache");
Log.Info($"Preload {ImageCache.Usage.Count} images from cache");
});
}
@@ -112,13 +111,11 @@ namespace Wox.Infrastructure.Image
ImageSource image;
if (string.IsNullOrEmpty(path))
{
image = ImageSources[Constant.ErrorIcon];
_cache.Add(Constant.ErrorIcon);
image = ImageCache[Constant.ErrorIcon];
}
else if (ImageSources.ContainsKey(path))
else if (ImageCache.ContainsKey(path))
{
image = ImageSources[path];
_cache.Add(path);
image = ImageCache[path];
}
else
{
@@ -146,7 +143,7 @@ namespace Wox.Infrastructure.Image
}
else
{
image = ImageSources[Constant.ErrorIcon];
image = ImageCache[Constant.ErrorIcon];
path = Constant.ErrorIcon;
}
}
@@ -159,12 +156,11 @@ namespace Wox.Infrastructure.Image
}
else
{
image = ImageSources[Constant.ErrorIcon];
image = ImageCache[Constant.ErrorIcon];
path = Constant.ErrorIcon;
}
}
ImageSources[path] = image;
_cache.Add(path);
ImageCache[path] = image;
image.Freeze();
}
return image;

View File

@@ -13,19 +13,20 @@ namespace Wox.Infrastructure.Storage
/// Normally, it has better performance, but not readable
/// You MUST mark implement class as Serializable
/// </summary>
public class BinaryStorage<T> : Storage<T> where T : new()
public class BinaryStorage<T> : Storage<T>
{
public BinaryStorage()
public BinaryStorage(string filename)
{
FileSuffix = ".dat";
FileSuffix = ".cache";
DirectoryName = "Cache";
DirectoryPath = Path.Combine(DirectoryPath, DirectoryName);
FileName = filename;
FilePath = Path.Combine(DirectoryPath, FileName + FileSuffix);
ValidateDirectory();
}
public override T Load()
public T TryLoad(T defaultData)
{
if (File.Exists(FilePath))
{
@@ -33,23 +34,25 @@ namespace Wox.Infrastructure.Storage
{
if (stream.Length > 0)
{
Deserialize(stream);
var d = Deserialize(stream, defaultData);
return d;
}
else
{
stream.Close();
LoadDefault();
Save(defaultData);
return defaultData;
}
}
}
else
{
LoadDefault();
Save(defaultData);
return defaultData;
}
return Data;
}
private void Deserialize(FileStream stream)
private T Deserialize(FileStream stream, T defaultData)
{
//http://stackoverflow.com/questions/2120055/binaryformatter-deserialize-gives-serializationexception
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
@@ -60,14 +63,15 @@ namespace Wox.Infrastructure.Storage
try
{
Data = (T) binaryFormatter.Deserialize(stream);
var t = (T) binaryFormatter.Deserialize(stream);
return t;
}
catch (System.Exception e)
{
Log.Error($"Broken cache file: {FilePath}");
Log.Exception(e);
stream.Close();
LoadDefault();
return defaultData;
}
finally
{
@@ -75,12 +79,6 @@ namespace Wox.Infrastructure.Storage
}
}
public override void LoadDefault()
{
Data = new T();
Save();
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly ayResult = null;
@@ -97,7 +95,7 @@ namespace Wox.Infrastructure.Storage
return ayResult;
}
public override void Save()
public void Save(T data)
{
using (var stream = new FileStream(FilePath, FileMode.Create))
{
@@ -108,7 +106,7 @@ namespace Wox.Infrastructure.Storage
try
{
binaryFormatter.Serialize(stream, Data);
binaryFormatter.Serialize(stream, data);
}
catch (SerializationException e)
{

View File

@@ -7,7 +7,7 @@ namespace Wox.Infrastructure.Storage
{
protected T Data;
protected Type DataType { get; }
public string FileName { get; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string FileSuffix { get; set; }
public string DirectoryPath { get; set; }