Skip to content

Commit

Permalink
Expanded Object Pool Sizes & Handling to Prevent Backup Construction
Browse files Browse the repository at this point in the history
  • Loading branch information
DelnarErsike committed Mar 1, 2024
1 parent 67f141c commit 04ffe24
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 44 deletions.
28 changes: 18 additions & 10 deletions Chummer/Backend/Datastructures/PropertyDependencyGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,32 @@ public override HashSet<string> GetWithAllDependents(T objParentInstance, string
public HashSet<string> GetWithAllDependents(T objParentInstance, string objKey, bool blnUsePool)
{
HashSet<string> setReturn = blnUsePool ? Utils.StringHashSetPool.Get() : new HashSet<string>();

if (NodeDictionary.TryGetValue(objKey, out DependencyGraphNode<string, T> objLoopNode))
try
{
if (setReturn.Add(objLoopNode.MyObject))
if (NodeDictionary.TryGetValue(objKey, out DependencyGraphNode<string, T> objLoopNode))
{
foreach (DependencyGraphNodeWithCondition<string, T> objNode in objLoopNode.UpStreamNodes)
if (setReturn.Add(objLoopNode.MyObject))
{
if (objNode.DependencyCondition?.Invoke(objParentInstance) != false)
foreach (DependencyGraphNodeWithCondition<string, T> objNode in objLoopNode.UpStreamNodes)
{
CollectDependents(objParentInstance, objNode.Node.MyObject, setReturn);
if (objNode.DependencyCondition?.Invoke(objParentInstance) != false)
{
CollectDependents(objParentInstance, objNode.Node.MyObject, setReturn);
}
}
}
}
}
else
setReturn.Add(objKey);
else
setReturn.Add(objKey);

return setReturn;
return setReturn;
}
catch
{
if (blnUsePool)
Utils.StringHashSetPool.Return(ref setReturn);
throw;
}
}

/// <summary>
Expand Down
15 changes: 6 additions & 9 deletions Chummer/Backend/Static/Extensions/WinFormsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1922,7 +1922,7 @@ private static void PopulateWithListItemsCore(this ListBox lsbThis, IEnumerable<
token.ThrowIfCancellationRequested();
if (lsbThis.DataSource != null)
{
// Assign new binding context because to avoid weirdness when switching DataSource
// Assign new binding context to avoid weirdness when switching DataSource
lsbThis.BindingContext = new BindingContext();
}
else
Expand All @@ -1937,12 +1937,11 @@ private static void PopulateWithListItemsCore(this ListBox lsbThis, IEnumerable<
}

blnDoReturnList = false;
s_dicListItemListAssignments.AddOrUpdate(lsbThis, lstItemsToSet, (x, y) =>
lsbThis.DataSource = s_dicListItemListAssignments.AddOrUpdate(lsbThis, lstItemsToSet, (x, y) =>
{
Utils.ListItemListPool.Return(ref y);
return lstItemsToSet;
});
lsbThis.DataSource = lstItemsToSet;
}
finally
{
Expand Down Expand Up @@ -1991,7 +1990,7 @@ private static void PopulateWithListItemsCore(this ComboBox cboThis, IEnumerable
token.ThrowIfCancellationRequested();
if (cboThis.DataSource != null)
{
// Assign new binding context because to avoid weirdness when switching DataSource
// Assign new binding context to avoid weirdness when switching DataSource
cboThis.BindingContext = new BindingContext();
}
else
Expand All @@ -2006,12 +2005,11 @@ private static void PopulateWithListItemsCore(this ComboBox cboThis, IEnumerable
}

blnDoReturnList = false;
s_dicListItemListAssignments.AddOrUpdate(cboThis, lstItemsToSet, (x, y) =>
cboThis.DataSource = s_dicListItemListAssignments.AddOrUpdate(cboThis, lstItemsToSet, (x, y) =>
{
Utils.ListItemListPool.Return(ref y);
return lstItemsToSet;
});
cboThis.DataSource = lstItemsToSet;
}
finally
{
Expand Down Expand Up @@ -2060,7 +2058,7 @@ private static void PopulateWithListItemsCore(this ElasticComboBox cboThis, IEnu
token.ThrowIfCancellationRequested();
if (cboThis.DataSource != null)
{
// Assign new binding context because to avoid weirdness when switching DataSource
// Assign new binding context to avoid weirdness when switching DataSource
cboThis.BindingContext = new BindingContext();
}
else
Expand All @@ -2075,12 +2073,11 @@ private static void PopulateWithListItemsCore(this ElasticComboBox cboThis, IEnu
}

blnDoReturnList = false;
s_dicListItemListAssignments.AddOrUpdate(cboThis, lstItemsToSet, (x, y) =>
cboThis.DataSource = s_dicListItemListAssignments.AddOrUpdate(cboThis, lstItemsToSet, (x, y) =>
{
Utils.ListItemListPool.Return(ref y);
return lstItemsToSet;
});
cboThis.DataSource = lstItemsToSet;
}
finally
{
Expand Down
8 changes: 4 additions & 4 deletions Chummer/Backend/Static/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ public static Task<Bitmap> GetStockIconBitmapsForSystemIconAsync(Icon objIcon, C
/// </summary>
public static int MaxParallelBatchSize { get; } = Environment.ProcessorCount * 2;

public static int DefaultPoolSize { get; } = Math.Max(MaxParallelBatchSize, 32);
public static int DefaultPoolSize { get; } = Math.Max(MaxParallelBatchSize, byte.MaxValue + 1);

private static readonly Lazy<string> s_strGetStartupPath = new Lazy<string>(
() => IsUnitTest ? AppDomain.CurrentDomain.SetupInformation.ApplicationBase : Application.StartupPath);
Expand Down Expand Up @@ -2616,14 +2616,14 @@ public static string GetTempPath()
/// </summary>
[CLSCompliant(false)]
public static SafeObjectPool<List<ListItem>> ListItemListPool { get; }
= new SafeObjectPool<List<ListItem>>(Math.Max(MaxParallelBatchSize, 64), () => new List<ListItem>(), x => x.Clear());
= new SafeObjectPool<List<ListItem>>(Math.Max(MaxParallelBatchSize, ushort.MaxValue + 1), () => new List<ListItem>(), x => x.Clear());

/// <summary>
/// Memory Pool for empty hash sets of strings. A bit slower up-front than a simple allocation, but reduces memory allocations when used a lot, which saves on CPU used for Garbage Collection.
/// </summary>
[CLSCompliant(false)]
public static SafeObjectPool<HashSet<string>> StringHashSetPool { get; }
= new SafeObjectPool<HashSet<string>>(() => new HashSet<string>(), x => x.Clear());
= new SafeObjectPool<HashSet<string>>(Math.Max(MaxParallelBatchSize, ushort.MaxValue + 1), () => new HashSet<string>(), x => x.Clear());

/// <summary>
/// Memory Pool for stopwatches. A bit slower up-front than a simple allocation, but reduces memory allocations when used a lot, which saves on CPU used for Garbage Collection.
Expand All @@ -2647,7 +2647,7 @@ public static string GetTempPath()
/// </summary>
[CLSCompliant(false)]
public static SafeDisposableObjectPool<DebuggableSemaphoreSlim> SemaphorePool { get; }
= new SafeDisposableObjectPool<DebuggableSemaphoreSlim>(Math.Max(MaxParallelBatchSize, 256), () => new DebuggableSemaphoreSlim());
= new SafeDisposableObjectPool<DebuggableSemaphoreSlim>(Math.Max(MaxParallelBatchSize, ushort.MaxValue + 1), () => new DebuggableSemaphoreSlim());

/// <summary>
/// RecyclableMemoryStreamManager to be used for all RecyclableMemoryStream constructors.
Expand Down
27 changes: 6 additions & 21 deletions Chummer/Forms/Utility Forms/MasterIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,6 @@ public MasterIndex()
_objGenericFormClosingCancellationTokenSource.Dispose();
_objLoadContentLocker.Dispose();
foreach (ListItem objExistingItem in _lstItems)
((MasterIndexEntry) objExistingItem.Value).Dispose();
Utils.ListItemListPool.Return(ref _lstFileNamesWithItems);
Utils.ListItemListPool.Return(ref _lstItems);
};
Expand Down Expand Up @@ -461,12 +459,6 @@ private async Task LoadContent(CancellationToken token = default)
try
{
_dicCachedNotes.Clear();
foreach (object objUncastedExistingEntry in _lstItems.Select(x => x.Value))
{
if (objUncastedExistingEntry is MasterIndexEntry objExistingEntry)
objExistingEntry.Dispose();
}

_lstItems.Clear();
_lstFileNamesWithItems.Clear();
if (_objSelectedSetting == null)
Expand Down Expand Up @@ -625,7 +617,6 @@ string strNotes
if (objExistingItem.Value is MasterIndexEntry objLoopEntry)
{
objLoopEntry.FileNames.UnionWith(objEntry.FileNames);
objEntry.Dispose();
}
else
{
Expand Down Expand Up @@ -945,15 +936,15 @@ private async void lstItems_SelectedIndexChanged(object sender, EventArgs e)
}
}

private sealed class MasterIndexEntry : IDisposable
private sealed class MasterIndexEntry
{
private HashSet<string> _setFileNames;

public MasterIndexEntry(string strDisplayName, string strFileName, SourceString objSource, SourceString objDisplaySource, string strEnglishNameOnPage, string strTranslatedNameOnPage)
{
DisplayName = strDisplayName;
_setFileNames = Utils.StringHashSetPool.Get();
_setFileNames.Add(strFileName);
FileNames = new HashSet<string>
{
strFileName
};
Source = objSource;
DisplaySource = objDisplaySource;
EnglishNameOnPage = strEnglishNameOnPage;
Expand All @@ -962,18 +953,12 @@ public MasterIndexEntry(string strDisplayName, string strFileName, SourceString

internal string DisplayName { get; }

internal HashSet<string> FileNames => _setFileNames;
internal HashSet<string> FileNames { get; }

internal SourceString Source { get; }
internal SourceString DisplaySource { get; }
internal string EnglishNameOnPage { get; }
internal string TranslatedNameOnPage { get; }

/// <inheritdoc />
public void Dispose()
{
Utils.StringHashSetPool.Return(ref _setFileNames);
}
}

private async void cmdEditCharacterSetting_Click(object sender, EventArgs e)
Expand Down

0 comments on commit 04ffe24

Please sign in to comment.