Improve Library load and refresh performance

This commit is contained in:
MBucari 2023-03-10 18:17:24 -07:00
parent ef1edf1136
commit e1cd8b8f94
4 changed files with 45 additions and 25 deletions

View File

@ -95,7 +95,8 @@ namespace ApplicationServices
stop(); stop();
var putBreakPointHere = logOutput; var putBreakPointHere = logOutput;
ScanEnd?.Invoke(null, null); ScanEnd?.Invoke(null, null);
} GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
}
} }
#region FULL LIBRARY scan and import #region FULL LIBRARY scan and import
@ -166,6 +167,7 @@ namespace ApplicationServices
stop(); stop();
var putBreakPointHere = logOutput; var putBreakPointHere = logOutput;
ScanEnd?.Invoke(null, null); ScanEnd?.Invoke(null, null);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
} }
} }
@ -173,7 +175,7 @@ namespace ApplicationServices
{ {
var tasks = new List<Task<List<ImportItem>>>(); var tasks = new List<Task<List<ImportItem>>>();
using LogArchiver archiver await using LogArchiver archiver
= Log.Logger.IsDebugEnabled() = Log.Logger.IsDebugEnabled()
? new LogArchiver(System.IO.Path.Combine(Configuration.Instance.LibationFiles, "LibraryScans.zip")) ? new LogArchiver(System.IO.Path.Combine(Configuration.Instance.LibationFiles, "LibraryScans.zip"))
: default; : default;
@ -208,7 +210,19 @@ namespace ApplicationServices
var dtoItems = await apiExtended.GetLibraryValidatedAsync(libraryOptions, Configuration.Instance.ImportEpisodes); var dtoItems = await apiExtended.GetLibraryValidatedAsync(libraryOptions, Configuration.Instance.ImportEpisodes);
archiver?.AddFile($"{DateTime.Now:u} {account.MaskedLogEntry}.json", new JObject { { "Account", account.MaskedLogEntry }, { "ScannedDateTime", DateTime.Now.ToString("u") }, {"Items", JArray.FromObject(dtoItems) } }); if (archiver is not null)
{
var fileName = $"{DateTime.Now:u} {account.MaskedLogEntry}.json";
var scanFile = new JObject
{
{ "Account", account.MaskedLogEntry },
{ "ScannedDateTime", DateTime.Now.ToString("u") },
{ "Items", await Task.Run(() => JArray.FromObject(dtoItems)) }
};
await archiver.AddFileAsync(fileName, scanFile);
}
logTime($"post scanAccountAsync {account.AccountName} qty: {dtoItems.Count}"); logTime($"post scanAccountAsync {account.AccountName} qty: {dtoItems.Count}");

View File

@ -6,10 +6,11 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FileManager namespace FileManager
{ {
public class LogArchiver : IDisposable public sealed class LogArchiver : IAsyncDisposable
{ {
public Encoding Encoding { get; set; } public Encoding Encoding { get; set; }
public string FileName { get; } public string FileName { get; }
@ -38,21 +39,30 @@ namespace FileManager
e.Delete(); e.Delete();
} }
public void AddFile(string name, JObject contents, string comment = null) public async Task AddFileAsync(string name, JObject contents, string comment = null)
=> AddFile(name, Encoding.GetBytes(contents.ToString(Newtonsoft.Json.Formatting.Indented)), comment); {
ArgumentValidator.EnsureNotNull(contents, nameof(contents));
await AddFileAsync(name, Encoding.GetBytes(contents.ToString(Newtonsoft.Json.Formatting.Indented)), comment);
}
public void AddFile(string name, string contents, string comment = null) public async Task AddFileAsync(string name, string contents, string comment = null)
=> AddFile(name, Encoding.GetBytes(contents), comment); {
ArgumentValidator.EnsureNotNull(contents, nameof(contents));
await AddFileAsync(name, Encoding.GetBytes(contents), comment);
}
private readonly object lockOob = new(); public Task AddFileAsync(string name, ReadOnlyMemory<byte> contents, string comment = null)
public void AddFile(string name, ReadOnlySpan<byte> contents, string comment = null)
{ {
ArgumentValidator.EnsureNotNull(name, nameof(name)); ArgumentValidator.EnsureNotNull(name, nameof(name));
name = ReplacementCharacters.Barebones.ReplaceFilenameChars(name); name = ReplacementCharacters.Barebones.ReplaceFilenameChars(name);
return Task.Run(() => AddfileInternal(name, contents.Span, comment));
}
lock (lockOob) private readonly object lockObj = new();
private void AddfileInternal(string name, ReadOnlySpan<byte> contents, string comment)
{
lock (lockObj)
{ {
var entry = archive.CreateEntry(name, CompressionLevel.SmallestSize); var entry = archive.CreateEntry(name, CompressionLevel.SmallestSize);
@ -62,6 +72,6 @@ namespace FileManager
} }
} }
public void Dispose() => archive.Dispose(); public async ValueTask DisposeAsync() => await Task.Run(archive.Dispose);
} }
} }

View File

@ -88,13 +88,7 @@ namespace LibationAvalonia.ViewModels
internal void BindToGrid(List<LibraryBook> dbBooks) internal void BindToGrid(List<LibraryBook> dbBooks)
{ {
GridEntries = new(SOURCE) GridEntries = new(SOURCE) { Filter = CollectionFilter };
{
Filter = CollectionFilter
};
GridEntries.CollectionChanged += (_, _)
=> VisibleCountChanged?.Invoke(this, GridEntries.OfType<LibraryBookEntry>().Count());
var geList = dbBooks var geList = dbBooks
.Where(lb => lb.Book.IsProduct()) .Where(lb => lb.Book.IsProduct())
@ -122,6 +116,9 @@ namespace LibationAvalonia.ViewModels
//Create the filtered-in list before adding entries to avoid a refresh //Create the filtered-in list before adding entries to avoid a refresh
FilteredInGridEntries = QueryResults(geList, FilterString); FilteredInGridEntries = QueryResults(geList, FilterString);
SOURCE.AddRange(geList.OrderByDescending(e => e.DateAdded)); SOURCE.AddRange(geList.OrderByDescending(e => e.DateAdded));
VisibleCountChanged?.Invoke(this, GridEntries.OfType<LibraryBookEntry>().Count());
GridEntries.CollectionChanged += (_, _)
=> VisibleCountChanged?.Invoke(this, GridEntries.OfType<LibraryBookEntry>().Count());
} }
/// <summary> /// <summary>
@ -134,7 +131,7 @@ namespace LibationAvalonia.ViewModels
//Add absent entries to grid, or update existing entry //Add absent entries to grid, or update existing entry
var allEntries = SOURCE.BookEntries(); var allEntries = SOURCE.BookEntries();
var seriesEntries = SOURCE.SeriesEntries().ToList(); var seriesEntries = SOURCE.SeriesEntries().ToList();
var parentedEpisodes = dbBooks.ParentedEpisodes(); var parentedEpisodes = dbBooks.ParentedEpisodes().ToList();
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
@ -177,7 +174,6 @@ namespace LibationAvalonia.ViewModels
#endregion #endregion
await Filter(FilterString); await Filter(FilterString);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
} }
private void RemoveBooks(IEnumerable<LibraryBookEntry> removedBooks, IEnumerable<SeriesEntry> removedSeries) private void RemoveBooks(IEnumerable<LibraryBookEntry> removedBooks, IEnumerable<SeriesEntry> removedSeries)

View File

@ -266,7 +266,7 @@ namespace LibationWinForms.GridView
var allEntries = bindingList.AllItems().BookEntries(); var allEntries = bindingList.AllItems().BookEntries();
var seriesEntries = bindingList.AllItems().SeriesEntries().ToList(); var seriesEntries = bindingList.AllItems().SeriesEntries().ToList();
var parentedEpisodes = dbBooks.ParentedEpisodes(); var parentedEpisodes = dbBooks.ParentedEpisodes().ToList();
foreach (var libraryBook in dbBooks.OrderBy(e => e.DateAdded)) foreach (var libraryBook in dbBooks.OrderBy(e => e.DateAdded))
{ {
@ -276,8 +276,8 @@ namespace LibationWinForms.GridView
AddOrUpdateBook(libraryBook, existingEntry); AddOrUpdateBook(libraryBook, existingEntry);
else if(parentedEpisodes.Any(lb => lb == libraryBook)) else if(parentedEpisodes.Any(lb => lb == libraryBook))
//Only try to add or update is this LibraryBook is a know child of a parent //Only try to add or update is this LibraryBook is a know child of a parent
AddOrUpdateEpisode(libraryBook, existingEntry, seriesEntries, dbBooks); AddOrUpdateEpisode(libraryBook, existingEntry, seriesEntries, dbBooks);
} }
bindingList.SuspendFilteringOnUpdate = false; bindingList.SuspendFilteringOnUpdate = false;