fix(historian): #691.4 review — uncapped Gateway events reads no longer pre-size to int.MaxValue

GatewayHistorianDataSource.ReadEventsAsync sized its result list to
maxEvents, which is int.MaxValue for NumValuesPerNode = 0: every
uncapped Gateway events read (forward on master, and the new walked
reverse one) threw 'Array dimensions exceeded' and counted as a backend
failure. Capacity is bounded at 1024. The events walk delegate moved to
ReverseEventsReader so it is tested over the real Gateway source
(forward uncapped, reverse uncapped, reverse capped).
This commit is contained in:
Joseph Doherty
2026-10-12 17:20:41 -04:00
parent d277f34a96
commit ccda27d220
6 changed files with 142 additions and 18 deletions
@@ -5311,22 +5311,9 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
// Walk for one more than the fetch: finding it is the "more events exist" signal a source gives with its
// continuation point (the walk itself cannot flag truncation).
var want = numValuesPerNode == 0 ? 0u : (uint)Math.Min(uint.MaxValue - 1L, (long)fetch + 1);
var budget = Math.Max(1, MaxTieClusterOverfetch);
var walkSource = sourceName;
var (rows, next) = await ReverseWalk.WalkAsync<HistoricalEvent>(
async (s, e, cap, token) =>
{
var r = await source.ReadEventsAsync(walkSource, s, e, cap == 0 ? int.MaxValue : cap, reverse: false, token)
.ConfigureAwait(false);
return new ForwardSegmentRead<HistoricalEvent>(r.Events, r.ContinuationPoint is not null);
},
ev => ev.EventTimeUtc.Ticks, EventIdTieOrder.Instance, startUtc, endUtc, want, budget,
source.TimestampResolutionTicks, Clock.GetUtcNow().UtcDateTime, walkHint,
at => new HistoryReadLimitExceededException(budget,
$"A reverse events read of '{walkSource}' at {at:O} found more than {budget} events at one " +
"timestamp; the backend reads forward only, so the latest of them cannot be selected. Increase " +
"ServerHistorian:MaxTieClusterOverfetch."),
ct)
var (rows, next) = await ReverseEventsReader.ReadAsync(
source, sourceName, startUtc, endUtc, want, MaxTieClusterOverfetch, Clock.GetUtcNow().UtcDateTime,
walkHint, ct)
.ConfigureAwait(false);
walkHint = next;
var more = want > 0 && rows.Count > fetch;