Skip to content

Commit d4b6f61

Browse files
committed
bugfix: fixed a race condition potentially causing last write wins
1 parent 723eaa0 commit d4b6f61

File tree

1 file changed

+16
-11
lines changed

1 file changed

+16
-11
lines changed

Penumbra/Collections/Manager/CollectionStorage.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,38 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
3131

3232
public ModCollection Create(string name, int index, ModCollection? duplicate)
3333
{
34-
var newCollection = duplicate?.Duplicate(name, CurrentCollectionId, index)
35-
?? ModCollection.CreateEmpty(name, CurrentCollectionId, index, _modStorage.Count);
36-
Add(newCollection);
34+
var localId = AllocateNextId();
35+
var newCollection = duplicate?.Duplicate(name, localId, index)
36+
?? ModCollection.CreateEmpty(name, localId, index, _modStorage.Count);
37+
AddAtLocalId(newCollection, localId);
3738
return newCollection;
3839
}
3940

4041
public ModCollection CreateFromData(Guid id, string name, int version, Dictionary<string, ModSettings.SavedSettings> allSettings,
4142
IReadOnlyList<string> inheritances)
4243
{
44+
var localId = AllocateNextId();
4345
var newCollection = ModCollection.CreateFromData(_saveService, _modStorage,
44-
new ModCollectionIdentity(id, CurrentCollectionId, name, Count), version, allSettings, inheritances);
45-
Add(newCollection);
46+
new ModCollectionIdentity(id, localId, name, Count), version, allSettings, inheritances);
47+
AddAtLocalId(newCollection, localId);
4648
return newCollection;
4749
}
4850

4951
public ModCollection CreateTemporary(string name, int index, int globalChangeCounter)
5052
{
51-
var newCollection = ModCollection.CreateTemporary(name, CurrentCollectionId, index, globalChangeCounter);
52-
Add(newCollection);
53+
var localId = AllocateNextId();
54+
var newCollection = ModCollection.CreateTemporary(name, localId, index, globalChangeCounter);
55+
AddAtLocalId(newCollection, localId);
5356
return newCollection;
5457
}
5558

56-
/// <remarks> Atomically add to _collectionLocal and increments _currentCollectionIdValue. </remarks>
57-
private void Add(ModCollection newCollection)
59+
/// <remarks> Atomically add to _collectionLocal at the id given. </remarks>
60+
private void AddAtLocalId(ModCollection newCollection, LocalCollectionId id)
5861
{
59-
_collectionsByLocal.AddOrUpdate(CurrentCollectionId,
62+
_collectionsByLocal.AddOrUpdate(id,
6063
static (_, newColl) => newColl,
6164
static (_, _, newColl) => newColl,
6265
newCollection);
63-
Interlocked.Increment(ref _currentCollectionIdValue);
6466
}
6567

6668
public void Delete(ModCollection collection)
@@ -86,6 +88,9 @@ private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
8688

8789
/// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
8890
public LocalCollectionId CurrentCollectionId => new(_currentCollectionIdValue);
91+
92+
private LocalCollectionId AllocateNextId ()
93+
=> new(Interlocked.Increment(ref _currentCollectionIdValue));
8994

9095
/// <summary> Default enumeration skips the empty collection. </summary>
9196
public IEnumerator<ModCollection> GetEnumerator()

0 commit comments

Comments
 (0)