mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Maybe fix the race condition and add more logging.
This commit is contained in:
parent
f8d1fcf4e2
commit
02fe5a4fb3
6 changed files with 96 additions and 53 deletions
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
@ -30,7 +31,10 @@ public class CollectionCache : IDisposable
|
||||||
public readonly MetaCache Meta;
|
public readonly MetaCache Meta;
|
||||||
public readonly Dictionary<IMod, SingleArray<ModConflicts>> _conflicts = new();
|
public readonly Dictionary<IMod, SingleArray<ModConflicts>> _conflicts = new();
|
||||||
|
|
||||||
public bool Calculating;
|
public int Calculating = -1;
|
||||||
|
|
||||||
|
public string AnonymizedName
|
||||||
|
=> _collection.AnonymizedName;
|
||||||
|
|
||||||
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
||||||
=> _conflicts.Values;
|
=> _conflicts.Values;
|
||||||
|
|
@ -138,7 +142,7 @@ public class CollectionCache : IDisposable
|
||||||
=> _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
|
=> _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
|
||||||
|
|
||||||
/// <summary> Force a file to be resolved to a specific path regardless of conflicts. </summary>
|
/// <summary> Force a file to be resolved to a specific path regardless of conflicts. </summary>
|
||||||
private void ForceFileSync(Utf8GamePath path, FullPath fullPath)
|
internal void ForceFileSync(Utf8GamePath path, FullPath fullPath)
|
||||||
{
|
{
|
||||||
if (!CheckFullPath(path, fullPath))
|
if (!CheckFullPath(path, fullPath))
|
||||||
return;
|
return;
|
||||||
|
|
@ -149,7 +153,7 @@ public class CollectionCache : IDisposable
|
||||||
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
|
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ReloadModSync(IMod mod, bool addMetaChanges)
|
private void ReloadModSync(IMod mod, bool addMetaChanges)
|
||||||
{
|
{
|
||||||
RemoveModSync(mod, addMetaChanges);
|
RemoveModSync(mod, addMetaChanges);
|
||||||
AddModSync(mod, addMetaChanges);
|
AddModSync(mod, addMetaChanges);
|
||||||
|
|
@ -238,7 +242,7 @@ public class CollectionCache : IDisposable
|
||||||
{
|
{
|
||||||
++_collection.ChangeCounter;
|
++_collection.ChangeCounter;
|
||||||
if (mod.TotalManipulations > 0)
|
if (mod.TotalManipulations > 0)
|
||||||
AddMetaFiles();
|
AddMetaFiles(false);
|
||||||
|
|
||||||
_manager.MetaFileManager.ApplyDefaultFiles(_collection);
|
_manager.MetaFileManager.ApplyDefaultFiles(_collection);
|
||||||
}
|
}
|
||||||
|
|
@ -263,6 +267,8 @@ public class CollectionCache : IDisposable
|
||||||
if (!CheckFullPath(path, file))
|
if (!CheckFullPath(path, file))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (ResolvedFiles.TryAdd(path, new ModPath(mod, file)))
|
if (ResolvedFiles.TryAdd(path, new ModPath(mod, file)))
|
||||||
{
|
{
|
||||||
ModData.AddPath(mod, path);
|
ModData.AddPath(mod, path);
|
||||||
|
|
@ -281,6 +287,11 @@ public class CollectionCache : IDisposable
|
||||||
ModData.AddPath(mod, path);
|
ModData.AddPath(mod, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error($"[{Thread.CurrentThread.ManagedThreadId}] Error adding redirection {file} -> {path} for mod {mod.Name} to collection cache {AnonymizedName}:\n{ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Remove all empty conflict sets for a given mod with the given conflicts.
|
// Remove all empty conflict sets for a given mod with the given conflicts.
|
||||||
|
|
@ -374,8 +385,8 @@ public class CollectionCache : IDisposable
|
||||||
|
|
||||||
|
|
||||||
// Add all necessary meta file redirects.
|
// Add all necessary meta file redirects.
|
||||||
public void AddMetaFiles()
|
public void AddMetaFiles(bool fromFullCompute)
|
||||||
=> Meta.SetImcFiles();
|
=> Meta.SetImcFiles(fromFullCompute);
|
||||||
|
|
||||||
|
|
||||||
// Identify and record all manipulated objects for this entire collection.
|
// Identify and record all manipulated objects for this entire collection.
|
||||||
|
|
|
||||||
|
|
@ -81,17 +81,31 @@ public class CollectionCacheManager : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddChange(CollectionCache.ChangeData data)
|
public void AddChange(CollectionCache.ChangeData data)
|
||||||
|
{
|
||||||
|
if (data.Cache.Calculating == -1)
|
||||||
{
|
{
|
||||||
if (_framework.Framework.IsInFrameworkUpdateThread)
|
if (_framework.Framework.IsInFrameworkUpdateThread)
|
||||||
data.Apply();
|
data.Apply();
|
||||||
else
|
else
|
||||||
_changeQueue.Enqueue(data);
|
_changeQueue.Enqueue(data);
|
||||||
}
|
}
|
||||||
|
else if (data.Cache.Calculating == Environment.CurrentManagedThreadId)
|
||||||
|
{
|
||||||
|
data.Apply();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_changeQueue.Enqueue(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Only creates a new cache, does not update an existing one. </summary>
|
/// <summary> Only creates a new cache, does not update an existing one. </summary>
|
||||||
public bool CreateCache(ModCollection collection)
|
public bool CreateCache(ModCollection collection)
|
||||||
{
|
{
|
||||||
if (collection.HasCache || collection.Index == ModCollection.Empty.Index)
|
if (collection.Index == ModCollection.Empty.Index)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (collection._cache != null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
collection._cache = new CollectionCache(this, collection);
|
collection._cache = new CollectionCache(this, collection);
|
||||||
|
|
@ -115,27 +129,33 @@ public class CollectionCacheManager : IDisposable
|
||||||
if (collection.Index == 0)
|
if (collection.Index == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Penumbra.Log.Debug($"[{Thread.CurrentThread.ManagedThreadId}] Recalculating effective file list for {collection.AnonymizedName}");
|
Penumbra.Log.Debug($"[{Environment.CurrentManagedThreadId}] Recalculating effective file list for {collection.AnonymizedName}");
|
||||||
if (!collection.HasCache)
|
if (!collection.HasCache)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Error(
|
Penumbra.Log.Error(
|
||||||
$"[{Thread.CurrentThread.ManagedThreadId}] Recalculating effective file list for {collection.AnonymizedName} failed, no cache exists.");
|
$"[{Environment.CurrentManagedThreadId}] Recalculating effective file list for {collection.AnonymizedName} failed, no cache exists.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (collection._cache!.Calculating != -1)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error(
|
||||||
|
$"[{Environment.CurrentManagedThreadId}] Recalculating effective file list for {collection.AnonymizedName} failed, already in calculation on [{collection._cache!.Calculating}].");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
FullRecalculation(collection);
|
FullRecalculation(collection);
|
||||||
|
|
||||||
Penumbra.Log.Debug(
|
Penumbra.Log.Debug(
|
||||||
$"[{Thread.CurrentThread.ManagedThreadId}] Recalculation of effective file list for {collection.AnonymizedName} finished.");
|
$"[{Environment.CurrentManagedThreadId}] Recalculation of effective file list for {collection.AnonymizedName} finished.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FullRecalculation(ModCollection collection)
|
private void FullRecalculation(ModCollection collection)
|
||||||
{
|
{
|
||||||
var cache = collection._cache;
|
var cache = collection._cache;
|
||||||
if (cache == null || cache.Calculating)
|
if (cache is not { Calculating: -1 })
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cache.Calculating = true;
|
cache.Calculating = Environment.CurrentManagedThreadId;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cache.ResolvedFiles.Clear();
|
cache.ResolvedFiles.Clear();
|
||||||
|
|
@ -152,7 +172,7 @@ public class CollectionCacheManager : IDisposable
|
||||||
foreach (var mod in _modStorage)
|
foreach (var mod in _modStorage)
|
||||||
cache.AddModSync(mod, false);
|
cache.AddModSync(mod, false);
|
||||||
|
|
||||||
cache.AddMetaFiles();
|
cache.AddMetaFiles(true);
|
||||||
|
|
||||||
++collection.ChangeCounter;
|
++collection.ChangeCounter;
|
||||||
|
|
||||||
|
|
@ -160,7 +180,7 @@ public class CollectionCacheManager : IDisposable
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
cache.Calculating = false;
|
cache.Calculating = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,12 +349,19 @@ public class CollectionCacheManager : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CreateNecessaryCaches()
|
public void CreateNecessaryCaches()
|
||||||
{
|
{
|
||||||
Parallel.ForEach(_active.SpecialAssignments.Select(p => p.Value)
|
ModCollection[] caches;
|
||||||
|
// Lock to make sure no race conditions during CreateCache happen.
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
caches = _active.SpecialAssignments.Select(p => p.Value)
|
||||||
.Concat(_active.Individuals.Select(p => p.Collection))
|
.Concat(_active.Individuals.Select(p => p.Collection))
|
||||||
.Prepend(_active.Current)
|
.Prepend(_active.Current)
|
||||||
.Prepend(_active.Default)
|
.Prepend(_active.Default)
|
||||||
.Prepend(_active.Interface)
|
.Prepend(_active.Interface)
|
||||||
.Where(CreateCache), CalculateEffectiveFileListInternal);
|
.Where(CreateCache).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Parallel.ForEach(caches, CalculateEffectiveFileListInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnModDiscoveryStarted()
|
private void OnModDiscoveryStarted()
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,18 @@ public readonly struct ImcCache : IDisposable
|
||||||
public ImcCache()
|
public ImcCache()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public void SetFiles(ModCollection collection)
|
public void SetFiles(ModCollection collection, bool fromFullCompute)
|
||||||
{
|
{
|
||||||
foreach( var path in _imcFiles.Keys )
|
if (fromFullCompute)
|
||||||
collection._cache!.ForceFile( path, CreateImcPath( collection, path ) );
|
{
|
||||||
|
foreach (var path in _imcFiles.Keys)
|
||||||
|
collection._cache!.ForceFileSync(path, CreateImcPath(collection, path));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var path in _imcFiles.Keys)
|
||||||
|
collection._cache!.ForceFile(path, CreateImcPath(collection, path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset(ModCollection collection)
|
public void Reset(ModCollection collection)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public class MetaCache : IDisposable, IEnumerable<KeyValuePair<MetaManipulation,
|
||||||
_estCache.SetFiles(_manager);
|
_estCache.SetFiles(_manager);
|
||||||
_gmpCache.SetFiles(_manager);
|
_gmpCache.SetFiles(_manager);
|
||||||
_cmpCache.SetFiles(_manager);
|
_cmpCache.SetFiles(_manager);
|
||||||
_imcCache.SetFiles(_collection);
|
_imcCache.SetFiles(_collection, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
|
|
@ -167,8 +167,8 @@ public class MetaCache : IDisposable, IEnumerable<KeyValuePair<MetaManipulation,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Set the currently relevant IMC files for the collection cache. </summary>
|
/// <summary> Set the currently relevant IMC files for the collection cache. </summary>
|
||||||
public void SetImcFiles()
|
public void SetImcFiles(bool fromFullCompute)
|
||||||
=> _imcCache.SetFiles(_collection);
|
=> _imcCache.SetFiles(_collection, fromFullCompute);
|
||||||
|
|
||||||
public MetaList.MetaReverter TemporarilySetEqpFile()
|
public MetaList.MetaReverter TemporarilySetEqpFile()
|
||||||
=> _eqpCache.TemporarilySetFiles(_manager);
|
=> _eqpCache.TemporarilySetFiles(_manager);
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,12 @@ public partial class IndividualCollections
|
||||||
if (_actorService.Valid)
|
if (_actorService.Valid)
|
||||||
return ReadJObjectInternal(obj, storage);
|
return ReadJObjectInternal(obj, storage);
|
||||||
void Func()
|
void Func()
|
||||||
{
|
|
||||||
saver.DalamudFramework.RunOnFrameworkThread(() =>
|
|
||||||
{
|
{
|
||||||
if (ReadJObjectInternal(obj, storage))
|
if (ReadJObjectInternal(obj, storage))
|
||||||
saver.ImmediateSave(parent);
|
saver.ImmediateSave(parent);
|
||||||
IsLoaded = true;
|
IsLoaded = true;
|
||||||
Loaded.Invoke();
|
Loaded.Invoke();
|
||||||
_actorService.FinishedCreation -= Func;
|
_actorService.FinishedCreation -= Func;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_actorService.FinishedCreation += Func;
|
_actorService.FinishedCreation += Func;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ public sealed class ModManager : ModStorage, IDisposable
|
||||||
ScanMods();
|
ScanMods();
|
||||||
|
|
||||||
_communicator.ModDiscoveryFinished.Invoke();
|
_communicator.ModDiscoveryFinished.Invoke();
|
||||||
Penumbra.Log.Information("Rediscovered mods.");
|
Penumbra.Log.Information($"Rediscovered {Mods.Count} mods.");
|
||||||
|
|
||||||
if (ModBackup.MigrateModBackups)
|
if (ModBackup.MigrateModBackups)
|
||||||
ModBackup.MigrateZipToPmp(this);
|
ModBackup.MigrateZipToPmp(this);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue