Improve FilePathCache performance
This commit is contained in:
parent
eda100b7ac
commit
736fbbf82f
@ -1,10 +1,11 @@
|
|||||||
using System;
|
using FileManager;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FileManager;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace LibationFileManager
|
namespace LibationFileManager
|
||||||
@ -32,6 +33,10 @@ namespace LibationFileManager
|
|||||||
{
|
{
|
||||||
Cache = JsonConvert.DeserializeObject<FileCacheV2<CacheEntry>>(File.ReadAllText(jsonFileV2))
|
Cache = JsonConvert.DeserializeObject<FileCacheV2<CacheEntry>>(File.ReadAllText(jsonFileV2))
|
||||||
?? throw new NullReferenceException("File exists but deserialize is null. This will never happen when file is healthy.");
|
?? throw new NullReferenceException("File exists but deserialize is null. This will never happen when file is healthy.");
|
||||||
|
|
||||||
|
//Once per startup, launch a task to validate existence of files in the cache.
|
||||||
|
//This is fire-and-forget. Since it is never awaited, it will no exceptions will be thrown to the caller.
|
||||||
|
Task.Run(ValidateAllFiles);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -42,6 +47,23 @@ namespace LibationFileManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ValidateAllFiles()
|
||||||
|
{
|
||||||
|
bool cacheChanged = false;
|
||||||
|
foreach (var id in Cache.GetIDs())
|
||||||
|
{
|
||||||
|
foreach (var entry in Cache.GetIdEntries(id))
|
||||||
|
{
|
||||||
|
if (!File.Exists(entry.Path))
|
||||||
|
{
|
||||||
|
cacheChanged |= Remove(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cacheChanged)
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool Exists(string id, FileType type) => GetFirstPath(id, type) is not null;
|
public static bool Exists(string id, FileType type) => GetFirstPath(id, type) is not null;
|
||||||
|
|
||||||
public static List<(FileType fileType, LongPath path)> GetFiles(string id)
|
public static List<(FileType fileType, LongPath path)> GetFiles(string id)
|
||||||
@ -111,10 +133,20 @@ namespace LibationFileManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Insert(string id, string path)
|
public static void Insert(string id, params string[] paths)
|
||||||
{
|
{
|
||||||
var type = FileTypes.GetFileTypeFromPath(path);
|
var newEntries
|
||||||
Insert(new CacheEntry(id, type, path));
|
= paths
|
||||||
|
.Select(path => new CacheEntry(id, FileTypes.GetFileTypeFromPath(path), path))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
lock (locker)
|
||||||
|
Cache.AddRange(id, newEntries);
|
||||||
|
|
||||||
|
if (Inserted is not null)
|
||||||
|
newEntries.ForEach(e => Inserted?.Invoke(null, e));
|
||||||
|
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Insert(CacheEntry entry)
|
public static void Insert(CacheEntry entry)
|
||||||
@ -150,9 +182,11 @@ namespace LibationFileManager
|
|||||||
private class FileCacheV2<TEntry>
|
private class FileCacheV2<TEntry>
|
||||||
{
|
{
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private readonly ConcurrentDictionary<string, List<TEntry>> Dictionary = new();
|
private readonly ConcurrentDictionary<string, HashSet<TEntry>> Dictionary = new();
|
||||||
private static object lockObject = new();
|
private static object lockObject = new();
|
||||||
|
|
||||||
|
public List<string> GetIDs() => Dictionary.Keys.ToList();
|
||||||
|
|
||||||
public List<TEntry> GetIdEntries(string id)
|
public List<TEntry> GetIdEntries(string id)
|
||||||
{
|
{
|
||||||
static List<TEntry> empty() => new();
|
static List<TEntry> empty() => new();
|
||||||
@ -162,23 +196,34 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
public void Add(string id, TEntry entry)
|
public void Add(string id, TEntry entry)
|
||||||
{
|
{
|
||||||
Dictionary.AddOrUpdate(id, [entry], (id, entries) => { entries.Add(entry); return entries; });
|
Dictionary.AddOrUpdate<TEntry>(id,
|
||||||
|
(_, e) => [e], //Add new Dictionary Value
|
||||||
|
(id, existingEntries, newEntry) => //Update existing Dictionary Value
|
||||||
|
{
|
||||||
|
existingEntries.Add(entry);
|
||||||
|
return existingEntries;
|
||||||
|
},
|
||||||
|
entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange(string id, IEnumerable<TEntry> entries)
|
public void AddRange(string id, IEnumerable<TEntry> entries)
|
||||||
{
|
{
|
||||||
Dictionary.AddOrUpdate(id, entries.ToList(), (id, entries) =>
|
Dictionary.AddOrUpdate<IEnumerable<TEntry>>(id,
|
||||||
|
(_, e) => e.ToHashSet(), //Add new Dictionary Value
|
||||||
|
(id, existingEntries, newEntries) => //Update existing Dictionary Value
|
||||||
{
|
{
|
||||||
entries.AddRange(entries);
|
foreach (var entry in newEntries)
|
||||||
return entries;
|
existingEntries.Add(entry);
|
||||||
});
|
return existingEntries;
|
||||||
|
},
|
||||||
|
entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(string id, TEntry entry)
|
public bool Remove(string id, TEntry entry)
|
||||||
{
|
{
|
||||||
lock (lockObject)
|
lock (lockObject)
|
||||||
{
|
{
|
||||||
if (Dictionary.TryGetValue(id, out List<TEntry>? entries))
|
if (Dictionary.TryGetValue(id, out HashSet<TEntry>? entries))
|
||||||
{
|
{
|
||||||
var removed = entries?.Remove(entry) ?? false;
|
var removed = entries?.Remove(entry) ?? false;
|
||||||
if (removed && entries?.Count == 0)
|
if (removed && entries?.Count == 0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user