Skip to content

Commit 723eaa0

Browse files
committed
refactor: made _collections thread-safe
1 parent 101df50 commit 723eaa0

File tree

1 file changed

+44
-17
lines changed

1 file changed

+44
-17
lines changed

Penumbra/Collections/Manager/CollectionStorage.cs

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public void Delete(ModCollection collection)
7171
[
7272
ModCollection.Empty,
7373
];
74+
75+
private readonly Lock _collectionsLock = new();
7476

7577
/// <remarks> A list of all collections ever created still existing by their local id. </remarks>
7678
private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
@@ -79,8 +81,11 @@ private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
7981

8082
public readonly ModCollection DefaultNamed;
8183

82-
/// <remarks> Incremented by 1 because the empty collection gets Zero. </remarks>
83-
public LocalCollectionId CurrentCollectionId { get; private set; } = LocalCollectionId.Zero + 1;
84+
/// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
85+
private int _currentCollectionIdValue = 1;
86+
87+
/// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
88+
public LocalCollectionId CurrentCollectionId => new(_currentCollectionIdValue);
8489

8590
/// <summary> Default enumeration skips the empty collection. </summary>
8691
public IEnumerator<ModCollection> GetEnumerator()
@@ -162,8 +167,12 @@ public bool AddCollection(string name, ModCollection? duplicate)
162167
if (name.Length == 0)
163168
return false;
164169

165-
var newCollection = Create(name, _collections.Count, duplicate);
166-
_collections.Add(newCollection);
170+
ModCollection newCollection;
171+
lock (_collectionsLock)
172+
{
173+
newCollection = Create(name, _collections.Count, duplicate);
174+
_collections.Add(newCollection);
175+
}
167176
_saveService.ImmediateSave(new ModCollectionSave(_modStorage, newCollection));
168177
Penumbra.Messager.NotificationMessage($"Created new collection {newCollection.Identity.AnonymizedName}.", NotificationType.Success, false);
169178
_communicator.CollectionChange.Invoke(CollectionType.Inactive, null, newCollection, string.Empty);
@@ -189,10 +198,13 @@ public bool RemoveCollection(ModCollection collection)
189198

190199
Delete(collection);
191200
_saveService.ImmediateDelete(new ModCollectionSave(_modStorage, collection));
192-
_collections.RemoveAt(collection.Identity.Index);
193-
// Update indices.
194-
for (var i = collection.Identity.Index; i < Count; ++i)
195-
_collections[i].Identity.Index = i;
201+
lock (_collectionsLock)
202+
{
203+
_collections.RemoveAt(collection.Identity.Index);
204+
// Update indices.
205+
for (var i = collection.Identity.Index; i < Count; ++i)
206+
_collections[i].Identity.Index = i;
207+
}
196208

197209
Penumbra.Messager.NotificationMessage($"Deleted collection {collection.Identity.AnonymizedName}.", NotificationType.Success, false);
198210
_communicator.CollectionChange.Invoke(CollectionType.Inactive, collection, null, string.Empty);
@@ -316,38 +328,41 @@ private ModCollection SetDefaultNamedCollection()
316328
/// <summary> Move all settings in all collections to unused settings. </summary>
317329
private void OnModDiscoveryStarted()
318330
{
319-
foreach (var collection in this)
331+
var snapshot = GetModSnapShot();
332+
foreach (var collection in snapshot)
320333
collection.Settings.PrepareModDiscovery(_modStorage);
321334
}
322335

323336
/// <summary> Restore all settings in all collections to mods. </summary>
324337
private void OnModDiscoveryFinished()
325338
{
339+
var snapshot = GetModSnapShot();
326340
// Re-apply all mod settings.
327-
foreach (var collection in this)
341+
foreach (var collection in snapshot)
328342
collection.Settings.ApplyModSettings(collection, _saveService, _modStorage);
329343
}
330344

331345
/// <summary> Add or remove a mod from all collections, or re-save all collections where the mod has settings. </summary>
332346
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
333347
DirectoryInfo? newDirectory)
334348
{
349+
var snapshot = GetModSnapShot();
335350
switch (type)
336351
{
337352
case ModPathChangeType.Added:
338-
foreach (var collection in this)
353+
foreach (var collection in snapshot)
339354
collection.Settings.AddMod(mod);
340355
break;
341356
case ModPathChangeType.Deleted:
342-
foreach (var collection in this)
357+
foreach (var collection in snapshot)
343358
collection.Settings.RemoveMod(mod);
344359
break;
345360
case ModPathChangeType.Moved:
346-
foreach (var collection in this.Where(collection => collection.GetOwnSettings(mod.Index) != null))
361+
foreach (var collection in snapshot.Where(collection => collection.GetOwnSettings(mod.Index) != null))
347362
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
348363
break;
349364
case ModPathChangeType.Reloaded:
350-
foreach (var collection in this)
365+
foreach (var collection in snapshot)
351366
{
352367
if (collection.GetOwnSettings(mod.Index)?.Settings.FixAll(mod) ?? false)
353368
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
@@ -365,8 +380,9 @@ private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? gro
365380
type.HandlingInfo(out var requiresSaving, out _, out _);
366381
if (!requiresSaving)
367382
return;
368-
369-
foreach (var collection in this)
383+
384+
var snapshot = GetModSnapShot();
385+
foreach (var collection in snapshot)
370386
{
371387
if (collection.GetOwnSettings(mod.Index)?.HandleChanges(type, mod, group, option, movedToIdx) ?? false)
372388
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
@@ -380,11 +396,22 @@ private void OnModFileChanged(Mod mod, FileRegistry file)
380396
if (file.CurrentUsage == 0)
381397
return;
382398

383-
foreach (var collection in this)
399+
var snapshot = GetModSnapShot();
400+
foreach (var collection in snapshot)
384401
{
385402
var (settings, _) = collection.GetActualSettings(mod.Index);
386403
if (settings is { Enabled: true })
387404
collection.Counters.IncrementChange();
388405
}
389406
}
407+
408+
private ModCollection[] GetModSnapShot()
409+
{
410+
ModCollection[] snapshot;
411+
lock (_collectionsLock)
412+
{
413+
snapshot = _collections.Skip(1).ToArray();
414+
}
415+
return snapshot;
416+
}
390417
}

0 commit comments

Comments
 (0)