perf(focas): cache equipment-tag parsed addresses (no per-call reparse)
Equipment tags resolved at runtime via FocasEquipmentTagParser were not seeded in _parsedAddressesByTagName so both ReadAsync and WriteAsync re-parsed the raw TagConfig JSON address string on every hot-path call. Promoted the field to ConcurrentDictionary (read + write thread safety) and introduced ResolveParsedAddress(GetOrAdd) so the first call stores the parse result and all subsequent calls are a cache hit. Authored tags seeded at InitializeAsync compile and work unchanged.
This commit is contained in:
@@ -64,4 +64,35 @@ public class FocasEquipmentTagTests
|
||||
r[0].StatusCode.ShouldNotBe(FocasStatusMapper.BadNodeIdUnknown);
|
||||
r[0].Value.ShouldBe((sbyte)42);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regression guard for Driver.FOCAS-008 equipment-tag path: the parsed
|
||||
/// <see cref="FocasAddress"/> for a resolver-produced (equipment) tag must be
|
||||
/// cached after the first read so subsequent reads and writes skip re-parsing
|
||||
/// the raw TagConfig JSON on every call.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Equipment_tag_parsed_address_is_cached_after_first_read()
|
||||
{
|
||||
var equipRef = """{"deviceHostAddress":"focas://10.0.0.5:8193","address":"R100","dataType":"Byte"}""";
|
||||
var factory = new FakeFocasClientFactory
|
||||
{
|
||||
Customise = () => new FakeFocasClient { Values = { ["R100"] = (sbyte)7 } },
|
||||
};
|
||||
var drv = new FocasDriver(new FocasDriverOptions
|
||||
{
|
||||
Devices = [new FocasDeviceOptions("focas://10.0.0.5:8193")],
|
||||
Tags = [],
|
||||
Probe = new FocasProbeOptions { Enabled = false },
|
||||
}, "focas-eq-cache", factory);
|
||||
await drv.InitializeAsync("{}", CancellationToken.None);
|
||||
|
||||
// Before any read the parsed address must NOT be in the cache.
|
||||
drv.IsParsedAddressCached(equipRef).ShouldBeFalse();
|
||||
|
||||
// After a successful read the parsed address MUST be cached.
|
||||
var r = await drv.ReadAsync([equipRef], CancellationToken.None);
|
||||
r[0].StatusCode.ShouldBe(FocasStatusMapper.Good);
|
||||
drv.IsParsedAddressCached(equipRef).ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user