fix(centralui): bound FlowDebugService script cache (review 2026-10-21 07/M-2)
This commit is contained in:
@@ -107,6 +107,13 @@ public sealed class FlowDebugService : IFlowDebugService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<int, InstanceScripts> _scriptCache = new();
|
private readonly Dictionary<int, InstanceScripts> _scriptCache = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ceiling on <see cref="_scriptCache"/> entries (review 2026-10-21 07/M-2). Only the most
|
||||||
|
/// recently selected instance is ever read back, so a small bound loses nothing; reaching it
|
||||||
|
/// drops the whole cache before the new entry goes in.
|
||||||
|
/// </summary>
|
||||||
|
internal const int ScriptCacheCapacity = 8;
|
||||||
|
|
||||||
/// <summary>One instance's flattened scripts: the unique name the site keys on, the raw resolved scripts, and the picker projection.</summary>
|
/// <summary>One instance's flattened scripts: the unique name the site keys on, the raw resolved scripts, and the picker projection.</summary>
|
||||||
private sealed record InstanceScripts(
|
private sealed record InstanceScripts(
|
||||||
string UniqueName,
|
string UniqueName,
|
||||||
@@ -484,6 +491,10 @@ public sealed class FlowDebugService : IFlowDebugService
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var loaded = new InstanceScripts(instance.UniqueName, scripts, options);
|
var loaded = new InstanceScripts(instance.UniqueName, scripts, options);
|
||||||
|
if (_scriptCache.Count >= ScriptCacheCapacity && !_scriptCache.ContainsKey(instanceId))
|
||||||
|
{
|
||||||
|
_scriptCache.Clear();
|
||||||
|
}
|
||||||
_scriptCache[instanceId] = loaded;
|
_scriptCache[instanceId] = loaded;
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,6 +677,24 @@ public sealed class FlowDebugServiceTests : IDisposable
|
|||||||
Assert.False(options.Single(o => o.CanonicalName == "Mod.Tick").IsWriteKind);
|
Assert.False(options.Single(o => o.CanonicalName == "Mod.Tick").IsWriteKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Verifies the per-circuit script cache stays bounded however many instances are browsed (review 2026-10-21 07/M-2).</summary>
|
||||||
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetInstanceScripts_BrowsingManyInstances_KeepsCacheBounded()
|
||||||
|
{
|
||||||
|
var svc = CreateService(reply: null);
|
||||||
|
for (var id = 100; id < 100 + 3 * FlowDebugService.ScriptCacheCapacity; id++)
|
||||||
|
{
|
||||||
|
WireFlattened(id, "Sim" + id, new ResolvedScript { CanonicalName = "Manual", Code = "x", TriggerType = "Call" });
|
||||||
|
await svc.GetInstanceScriptsAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cache = (System.Collections.IDictionary)typeof(FlowDebugService)
|
||||||
|
.GetField("_scriptCache", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
|
||||||
|
.GetValue(svc)!;
|
||||||
|
Assert.True(cache.Count <= FlowDebugService.ScriptCacheCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Verifies that requesting scripts for an unknown instance yields an empty result.</summary>
|
/// <summary>Verifies that requesting scripts for an unknown instance yields an empty result.</summary>
|
||||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
Reference in New Issue
Block a user