From f0fb1c0f83dc538cc84b431123c9d9aa69751776 Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Wed, 22 Jan 2020 18:06:59 -0600 Subject: [PATCH] Config transaction objects now reued to minimize GC pressure --- IPA.Loader/Config/Stores/GeneratedStore.cs | 61 +++++++++++++++------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/IPA.Loader/Config/Stores/GeneratedStore.cs b/IPA.Loader/Config/Stores/GeneratedStore.cs index daae8b8a..4c261989 100644 --- a/IPA.Loader/Config/Stores/GeneratedStore.cs +++ b/IPA.Loader/Config/Stores/GeneratedStore.cs @@ -126,6 +126,7 @@ namespace IPA.Config.Stores { private readonly IGeneratedStore generated; private bool inChangeTransaction = false; + private bool changedInTransaction = false; internal static ConstructorInfo Ctor = typeof(Impl).GetConstructor(new[] { typeof(IGeneratedStore) }); public Impl(IGeneratedStore store) => generated = store; @@ -173,41 +174,61 @@ namespace IPA.Config.Stores internal static MethodInfo ImplChangeTransactionMethod = typeof(Impl).GetMethod(nameof(ImplChangeTransaction)); public static IDisposable ImplChangeTransaction(IGeneratedStore s, IDisposable nest) => FindImpl(s).ChangeTransaction(nest); - // TODO: use some fixed pool of these, because their lifetimes are hella short + // TODO: improve trasactionals so they don't always save in every case public IDisposable ChangeTransaction(IDisposable nest, bool takeWrite = true) - => new ChangeTransactionObj(this, !inChangeTransaction, nest, takeWrite && !WriteSyncObject.IsWriteLockHeld); + => GetFreeTransaction().InitWith(this, !inChangeTransaction, nest, takeWrite && !WriteSyncObject.IsWriteLockHeld); + + private ChangeTransactionObj GetFreeTransaction() + => freeTransactionObjs.Count > 0 ? freeTransactionObjs.Pop() + : new ChangeTransactionObj(); + // TODO: maybe sometimes clean this? + private static readonly Stack freeTransactionObjs = new Stack(); private sealed class ChangeTransactionObj : IDisposable { - private readonly Impl impl; - private readonly bool owns; - private readonly bool ownsWrite; - private readonly IDisposable nested; + private struct Data + { + public readonly Impl impl; + public readonly bool owns; + public readonly bool ownsWrite; + public readonly IDisposable nested; - public ChangeTransactionObj(Impl impl, bool owning, IDisposable nest, bool takeWrite) + public Data(Impl impl, bool owning, bool takeWrite, IDisposable nest) + { + this.impl = impl; owns = owning; ownsWrite = takeWrite; nested = nest; + } + } + private Data data; + + public ChangeTransactionObj InitWith(Impl impl, bool owning, IDisposable nest, bool takeWrite) { - this.impl = impl; - nested = nest; - if (owns = owning) + data = new Data(impl, owning, takeWrite, nest); + + if (data.owns) impl.inChangeTransaction = true; - if (ownsWrite = takeWrite) + if (data.ownsWrite) impl.TakeWrite(); + + return this; } - public void Dispose() + public void Dispose() => Dispose(true); + private void Dispose(bool addToStore) { - if (owns) + if (data.owns) { - impl.inChangeTransaction = false; - impl.InvokeChanged(); + data.impl.inChangeTransaction = false; + data.impl.InvokeChanged(); } - nested?.Dispose(); - if (ownsWrite) - impl.ReleaseWrite(); - GC.SuppressFinalize(this); + data.nested?.Dispose(); + if (data.ownsWrite) + data.impl.ReleaseWrite(); + + if (addToStore) + freeTransactionObjs.Push(this); } - ~ChangeTransactionObj() => Dispose(); + ~ChangeTransactionObj() => Dispose(false); } public static Impl FindImpl(IGeneratedStore store)