Refactor GetAllEntries methods for clarity and maintainability
d
This commit is contained in:
parent
6c5773df24
commit
bcbb7610ad
@ -21,8 +21,8 @@ namespace DataLayer
|
|||||||
.AsNoTrackingWithIdentityResolution()
|
.AsNoTrackingWithIdentityResolution()
|
||||||
.GetLibrary()
|
.GetLibrary()
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Where(lb => !lb.Book.IsEpisodeParent() || includeParents)
|
.Where(c => !c.Book.IsEpisodeParent() || includeParents)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
public static LibraryBook GetLibraryBook_Flat_NoTracking(this LibationContext context, string productId)
|
public static LibraryBook GetLibraryBook_Flat_NoTracking(this LibationContext context, string productId)
|
||||||
=> context
|
=> context
|
||||||
@ -91,7 +91,7 @@ namespace DataLayer
|
|||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
public static IEnumerable<LibraryBook> FindChildren(this IEnumerable<LibraryBook> bookList, LibraryBook parent)
|
public static List<LibraryBook> FindChildren(this IEnumerable<LibraryBook> bookList, LibraryBook parent)
|
||||||
=> bookList
|
=> bookList
|
||||||
.Where(
|
.Where(
|
||||||
lb =>
|
lb =>
|
||||||
|
|||||||
@ -40,30 +40,17 @@ namespace LibationUiBase.GridView
|
|||||||
|
|
||||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
||||||
|
|
||||||
(int numPer, int rem) = int.DivRem(products.Length, parallelism);
|
(int batchSize, int rem) = int.DivRem(products.Length, parallelism);
|
||||||
if (rem != 0) numPer++;
|
if (rem != 0) batchSize++;
|
||||||
|
|
||||||
var tasks = new Task<IGridEntry[]>[parallelism];
|
|
||||||
var syncContext = SynchronizationContext.Current;
|
var syncContext = SynchronizationContext.Current;
|
||||||
|
|
||||||
for (int i = 0; i < parallelism; i++)
|
//Asynchronously create an ILibraryBookEntry for every book in the library
|
||||||
|
var tasks = products.Chunk(batchSize).Select(batch => Task.Run(() =>
|
||||||
{
|
{
|
||||||
int start = i * numPer;
|
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||||
tasks[i] = Task.Run(() =>
|
return batch.Select(lb => new LibraryBookEntry<TStatus>(lb) as IGridEntry);
|
||||||
{
|
}));
|
||||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
|
||||||
|
|
||||||
int length = int.Min(numPer, products.Length - start);
|
|
||||||
if (length < 1) return Array.Empty<IGridEntry>();
|
|
||||||
|
|
||||||
var result = new IGridEntry[length];
|
|
||||||
|
|
||||||
for (int j = 0; j < length; j++)
|
|
||||||
result[j] = new LibraryBookEntry<TStatus>(products[start + j]);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (await Task.WhenAll(tasks)).SelectMany(a => a).ToList();
|
return (await Task.WhenAll(tasks)).SelectMany(a => a).ToList();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using DataLayer;
|
using DataLayer;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -62,53 +61,54 @@ namespace LibationUiBase.GridView
|
|||||||
var seriesBooks = libraryBooks.Where(lb => lb.Book.IsEpisodeParent()).ToArray();
|
var seriesBooks = libraryBooks.Where(lb => lb.Book.IsEpisodeParent()).ToArray();
|
||||||
var allEpisodes = libraryBooks.Where(lb => lb.Book.IsEpisodeChild()).ToArray();
|
var allEpisodes = libraryBooks.Where(lb => lb.Book.IsEpisodeChild()).ToArray();
|
||||||
|
|
||||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
|
||||||
|
|
||||||
var tasks = new Task[parallelism];
|
|
||||||
var syncContext = SynchronizationContext.Current;
|
|
||||||
|
|
||||||
var q = new BlockingCollection<(int, LibraryBook episode)>();
|
|
||||||
|
|
||||||
var seriesEntries = new ISeriesEntry[seriesBooks.Length];
|
var seriesEntries = new ISeriesEntry[seriesBooks.Length];
|
||||||
var seriesEpisodes = new ConcurrentBag<ILibraryBookEntry>[seriesBooks.Length];
|
var seriesEpisodes = new ILibraryBookEntry[seriesBooks.Length][];
|
||||||
|
|
||||||
for (int i = 0; i < parallelism; i++)
|
var syncContext = SynchronizationContext.Current;
|
||||||
{
|
var options = new ParallelOptions { MaxDegreeOfParallelism = int.Max(1, Environment.ProcessorCount - 1) };
|
||||||
tasks[i] = Task.Run(() =>
|
|
||||||
{
|
|
||||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
|
||||||
|
|
||||||
while (q.TryTake(out var entry, -1))
|
//Asynchronously create an ILibraryBookEntry for every episode in the library
|
||||||
{
|
await Parallel.ForEachAsync(getAllEpisodes(), options, createEpisodeEntry);
|
||||||
var parent = seriesEntries[entry.Item1];
|
|
||||||
var episodeBag = seriesEpisodes[entry.Item1];
|
|
||||||
episodeBag.Add(new LibraryBookEntry<TStatus>(entry.episode, parent));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i <seriesBooks.Length; i++)
|
//Match all episode entries to their corresponding parents
|
||||||
{
|
for (int i = seriesEntries.Length - 1; i >= 0; i--)
|
||||||
var series = seriesBooks[i];
|
|
||||||
seriesEntries[i] = new SeriesEntry<TStatus>(series, Enumerable.Empty<LibraryBook>());
|
|
||||||
seriesEpisodes[i] = new ConcurrentBag<ILibraryBookEntry>();
|
|
||||||
|
|
||||||
foreach (var ep in allEpisodes.FindChildren(series))
|
|
||||||
q.Add((i, ep));
|
|
||||||
}
|
|
||||||
|
|
||||||
q.CompleteAdding();
|
|
||||||
|
|
||||||
await Task.WhenAll(tasks);
|
|
||||||
|
|
||||||
for (int i = 0; i < seriesBooks.Length; i++)
|
|
||||||
{
|
{
|
||||||
var series = seriesEntries[i];
|
var series = seriesEntries[i];
|
||||||
series.Children.AddRange(seriesEpisodes[i].OrderByDescending(c => c.SeriesOrder));
|
|
||||||
|
//Sort episodes by series order descending, then add them to their parent's entry
|
||||||
|
Array.Sort(seriesEpisodes[i], (a, b) => -a.SeriesOrder.CompareTo(b.SeriesOrder));
|
||||||
|
series.Children.AddRange(seriesEpisodes[i]);
|
||||||
series.UpdateLibraryBook(series.LibraryBook);
|
series.UpdateLibraryBook(series.LibraryBook);
|
||||||
}
|
}
|
||||||
|
|
||||||
return seriesEntries.Where(s => s.Children.Count != 0).ToList();
|
return seriesEntries.Where(s => s.Children.Count != 0).Cast<ISeriesEntry>().ToList();
|
||||||
|
|
||||||
|
//Create a LibraryBookEntry for a single episode
|
||||||
|
ValueTask createEpisodeEntry((int seriesIndex, int episodeIndex, LibraryBook episode) data, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||||
|
var parent = seriesEntries[data.seriesIndex];
|
||||||
|
seriesEpisodes[data.seriesIndex][data.episodeIndex] = new LibraryBookEntry<TStatus>(data.episode, parent);
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Enumeration all series episodes, along with the index to its seriesEntries entry
|
||||||
|
//and an index to its seriesEpisodes entry
|
||||||
|
IEnumerable<(int seriesIndex, int episodeIndex, LibraryBook episode)> getAllEpisodes()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < seriesBooks.Length; i++)
|
||||||
|
{
|
||||||
|
var series = seriesBooks[i];
|
||||||
|
var childEpisodes = allEpisodes.FindChildren(series);
|
||||||
|
|
||||||
|
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||||
|
seriesEntries[i] = new SeriesEntry<TStatus>(series, []);
|
||||||
|
seriesEpisodes[i] = new ILibraryBookEntry[childEpisodes.Count];
|
||||||
|
|
||||||
|
for (int j = 0; j < childEpisodes.Count; j++)
|
||||||
|
yield return (i, j, childEpisodes[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveChild(ILibraryBookEntry lbe)
|
public void RemoveChild(ILibraryBookEntry lbe)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user