Added some other task handling for collection caches.

This commit is contained in:
Ottermandias 2023-05-27 15:43:37 +02:00
parent 0243e7a633
commit e98003eb09
11 changed files with 110 additions and 36 deletions

View file

@ -122,26 +122,40 @@ public class CollectionCache : IDisposable
return ret;
}
public void ForceFile(Utf8GamePath path, FullPath fullPath)
=> _manager.AddChange(ChangeData.ForcedFile(this, path, fullPath));
public void RemovePath(Utf8GamePath path)
=> _manager.AddChange(ChangeData.ForcedFile(this, path, FullPath.Empty));
public void ReloadMod(IMod mod, bool addMetaChanges)
=> _manager.AddChange(ChangeData.ModReload(this, mod, addMetaChanges));
public void AddMod(IMod mod, bool addMetaChanges)
=> _manager.AddChange(ChangeData.ModAddition(this, mod, addMetaChanges));
public void RemoveMod(IMod mod, bool addMetaChanges)
=> _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
/// <summary> Force a file to be resolved to a specific path regardless of conflicts. </summary>
internal void ForceFile(Utf8GamePath path, FullPath fullPath)
private void ForceFileSync(Utf8GamePath path, FullPath fullPath)
{
if (!CheckFullPath(path, fullPath))
return;
_manager.ForceFile(this, path, fullPath);
if (ResolvedFiles.Remove(path, out var modPath))
ModData.RemovePath(modPath.Mod, path);
if (fullPath.FullName.Length > 0)
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
}
/// <summary> Force a file resolve to be removed. </summary>
internal void RemovePath(Utf8GamePath path)
=> _manager.ForceFile(this, path, FullPath.Empty);
public void ReloadMod(IMod mod, bool addMetaChanges)
internal void ReloadModSync(IMod mod, bool addMetaChanges)
{
RemoveMod(mod, addMetaChanges);
AddMod(mod, addMetaChanges);
RemoveModSync(mod, addMetaChanges);
AddModSync(mod, addMetaChanges);
}
public void RemoveMod(IMod mod, bool addMetaChanges)
internal void RemoveModSync(IMod mod, bool addMetaChanges)
{
var conflicts = Conflicts(mod);
var (paths, manipulations) = ModData.RemoveMod(mod);
@ -168,7 +182,7 @@ public class CollectionCache : IDisposable
{
if (conflict.HasPriority)
{
ReloadMod(conflict.Mod2, false);
ReloadModSync(conflict.Mod2, false);
}
else
{
@ -185,8 +199,8 @@ public class CollectionCache : IDisposable
}
// Add all files and possibly manipulations of a given mod according to its settings in this collection.
public void AddMod(IMod mod, bool addMetaChanges)
/// <summary> Add all files and possibly manipulations of a given mod according to its settings in this collection. </summary>
internal void AddModSync(IMod mod, bool addMetaChanges)
{
if (mod.Index >= 0)
{
@ -421,4 +435,55 @@ public class CollectionCache : IDisposable
Penumbra.Log.Error($"The redirected path is too long to add the redirection\n\t{path}\n\t--> {fullPath}");
return false;
}
public readonly record struct ChangeData
{
public readonly CollectionCache Cache;
public readonly Utf8GamePath Path;
public readonly FullPath FullPath;
public readonly IMod Mod;
public readonly byte Type;
public readonly bool AddMetaChanges;
private ChangeData(CollectionCache cache, Utf8GamePath p, FullPath fp, IMod m, byte t, bool a)
{
Cache = cache;
Path = p;
FullPath = fp;
Mod = m;
Type = t;
AddMetaChanges = a;
}
public static ChangeData ModRemoval(CollectionCache cache, IMod mod, bool addMetaChanges)
=> new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 0, addMetaChanges);
public static ChangeData ModAddition(CollectionCache cache, IMod mod, bool addMetaChanges)
=> new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 1, addMetaChanges);
public static ChangeData ModReload(CollectionCache cache, IMod mod, bool addMetaChanges)
=> new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 2, addMetaChanges);
public static ChangeData ForcedFile(CollectionCache cache, Utf8GamePath p, FullPath fp)
=> new(cache, p, fp, Mods.Mod.ForcedFiles, 3, false);
public void Apply()
{
switch (Type)
{
case 0:
Cache.RemoveModSync(Mod, AddMetaChanges);
break;
case 1:
Cache.AddModSync(Mod, AddMetaChanges);
break;
case 2:
Cache.ReloadModSync(Mod, AddMetaChanges);
break;
case 3:
Cache.ForceFileSync(Path, FullPath);
break;
}
}
}
}

View file

@ -15,7 +15,6 @@ using Penumbra.Meta;
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.String.Classes;
namespace Penumbra.Collections.Cache;
@ -30,7 +29,7 @@ public class CollectionCacheManager : IDisposable
internal readonly MetaFileManager MetaFileManager;
private readonly ConcurrentQueue<(CollectionCache, Utf8GamePath, FullPath)> _forcedFileQueue = new();
private readonly ConcurrentQueue<CollectionCache.ChangeData> _changeQueue = new();
private int _count;
@ -81,6 +80,14 @@ public class CollectionCacheManager : IDisposable
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters;
}
public void AddChange(CollectionCache.ChangeData data)
{
if (_framework.Framework.IsInFrameworkUpdateThread)
data.Apply();
else
_changeQueue.Enqueue(data);
}
/// <summary> Only creates a new cache, does not update an existing one. </summary>
public bool CreateCache(ModCollection collection)
{
@ -102,9 +109,6 @@ public class CollectionCacheManager : IDisposable
=> _framework.RegisterImportant(nameof(CalculateEffectiveFileList) + collection.Name,
() => CalculateEffectiveFileListInternal(collection));
public void ForceFile(CollectionCache cache, Utf8GamePath path, FullPath fullPath)
=> _forcedFileQueue.Enqueue((cache, path, fullPath));
private void CalculateEffectiveFileListInternal(ModCollection collection)
{
// Skip the empty collection.
@ -143,10 +147,10 @@ public class CollectionCacheManager : IDisposable
.Concat(_tempMods.Mods.TryGetValue(collection, out var list)
? list
: Array.Empty<TemporaryMod>()))
cache.AddMod(tempMod, false);
cache.AddModSync(tempMod, false);
foreach (var mod in _modStorage)
cache.AddMod(mod, false);
cache.AddModSync(mod, false);
cache.AddMetaFiles();
@ -351,12 +355,7 @@ public class CollectionCacheManager : IDisposable
/// </summary>
private void OnFramework(Framework _)
{
while (_forcedFileQueue.TryDequeue(out var tuple))
{
if (tuple.Item1.ResolvedFiles.Remove(tuple.Item2, out var modPath))
tuple.Item1.ModData.RemovePath(modPath.Mod, tuple.Item2);
if (tuple.Item3.FullName.Length > 0)
tuple.Item1.ResolvedFiles.Add(tuple.Item2, new ModPath(Mod.ForcedFiles, tuple.Item3));
}
while (_changeQueue.TryDequeue(out var changeData))
changeData.Apply();
}
}

View file

@ -3,9 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
using OtterGui;
using Penumbra.Mods.Manager;
namespace Penumbra.Mods;
namespace Penumbra.Mods.Editor;
/// <summary> Utility to create and apply a zipped backup of a mod. </summary>
public class ModBackup
@ -80,7 +81,7 @@ public class ModBackup
return;
CreatingBackup = true;
await Task.Run(Create);
await AsyncTask.Run(Create);
CreatingBackup = false;
}

View file

@ -41,7 +41,7 @@ public class ModNormalizer
Step = 0;
TotalSteps = mod.TotalFileCount + 5;
Worker = Task.Run(NormalizeSync);
Worker = TrackedTask.Run(NormalizeSync);
}
private void NormalizeSync()

View file

@ -1,6 +1,7 @@
using System;
using System.IO;
using Penumbra.Communication;
using Penumbra.Mods.Editor;
using Penumbra.Services;
namespace Penumbra.Mods.Manager;

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Penumbra.Communication;
using Penumbra.Mods.Editor;
using Penumbra.Services;
namespace Penumbra.Mods.Manager;

View file

@ -52,10 +52,14 @@ public class Penumbra : IDalamudPlugin
try
{
var startTimer = new StartTracker();
using var timer = startTimer.Measure(StartTimeType.Total);
using var timer = startTimer.Measure(StartTimeType.Total);
_services = ServiceManager.CreateProvider(this, pluginInterface, Log, startTimer);
ChatService = _services.GetRequiredService<ChatService>();
_validityChecker = _services.GetRequiredService<ValidityChecker>();
var startup = _services.GetRequiredService<DalamudServices>().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s)
? s.ToString()
: "Unknown";
Log.Information($"Loading Penumbra Version {_validityChecker.Version}, Commit #{_validityChecker.CommitHash} with Waiting For Plugins: {startup}...");
_services.GetRequiredService<BackupService>(); // Initialize because not required anywhere else.
_config = _services.GetRequiredService<Configuration>();
_characterUtility = _services.GetRequiredService<CharacterUtility>();
@ -114,7 +118,7 @@ public class Penumbra : IDalamudPlugin
private void SetupInterface()
{
Task.Run(() =>
AsyncTask.Run(() =>
{
using var tInterface = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.Interface);
var system = _services.GetRequiredService<PenumbraWindowSystem>();

View file

@ -9,6 +9,7 @@ using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.Interop.Services;
using Penumbra.Mods;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.UI.Classes;
using Penumbra.Util;

View file

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using OtterGui;
using Penumbra.Util;
namespace Penumbra.Services;
@ -58,7 +59,7 @@ public abstract class AsyncServiceWrapper<T>
protected AsyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func<T> factory)
{
Name = name;
_task = Task.Run(() =>
_task = TrackedTask.Run(() =>
{
using var timer = tracker.Measure(type);
var service = factory();
@ -84,7 +85,7 @@ public abstract class AsyncServiceWrapper<T>
protected AsyncServiceWrapper(string name, Func<T> factory)
{
Name = name;
_task = Task.Run(() =>
_task = TrackedTask.Run(() =>
{
var service = factory();
if (_isDisposed)

View file

@ -12,6 +12,7 @@ using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Api.Enums;
using Penumbra.Mods;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI.AdvancedWindow;