3c3513ea3e
Item 1: IHistorianDataSource.MaxRawValuesPerRead (Gateway: learned ceiling - 16 = L; 0 elsewhere, guard-tested). RawPageLimit plans every raw page on top of #692's lookahead: with L > 0 the read (page P + boundary ties k + lookahead) is <= L, P = min(N, L - k - 1) (uncapped: L - k - 1); no room => straight to the tie-cluster over-fetch (never an uncapped or underflowing request). One re-plan + re-read when the read taught a new limit or was refused for crowding pre-window rows (HistoryReadLimitExceededException.PreWindowRows): the page shrinks by them. Over-fetch bound min(MaxTieClusterOverfetch, L - 1); slice size never 0. Review fixes: F1 a window starting at/before the epoch counts AVEVA's synthetic row as pre-window (a ceiling-truncated read was reported complete); F2 the page path disables ReverseRawReader's own re-run (cold end-only ceiling 20/N=3000 cost 3,023 reads, now <= 40); F3 crowded look-back re-read around, not refused; F4 the #687 crowding re-read room at least doubles (up to 8 re-reads), so a cluster of hundreds just before a resume point no longer fails on a default gateway; a crowding refusal that leaves no room is BadTooManyOperations, never a tick-by-tick cursor. Item 2: ServerHistorian:EventReadHorizon (default 00:00:00 = exact, unchanged). When set, every fresh HistoryReadEvents window's earlier bound is raised to now - horizon (both directions, all backends). Lossy by design; documented. Item 3 (native TimeAverage/Total re-check) stays blocked on historiangw#27.
44 lines
2.6 KiB
C#
44 lines
2.6 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
|
||
|
||
/// <summary>
|
||
/// Gitea #694 item 2: the opt-in <c>ServerHistorian:EventReadHorizon</c> — HistoryReadEvents never reads events older than
|
||
/// <c>now − horizon</c>. Off (<see cref="TimeSpan.Zero"/>, the default) a read is exact down to whatever its window says,
|
||
/// which on the Gateway means a reverse / end-only read walked back with forward reads proves "nothing older" with one
|
||
/// read down to the Unix epoch (#691) — ~3.8 s live on <c>Runtime.dbo.Events</c>, and an unfiltered one can hit the
|
||
/// gateway's 30 s SQL timeout. A forward read whose StartTime is far in the past costs the same on that table. The
|
||
/// horizon bounds both, at a stated price: events older than it are not returned, in either direction, on any backend.
|
||
/// </summary>
|
||
internal static class EventHorizon
|
||
{
|
||
/// <summary>
|
||
/// Raises the EARLIER bound of a fresh events window to the horizon's floor (<c>now − horizon</c>, inclusive): the
|
||
/// start of a forward <c>[start, end)</c> window, the exclusive lower end of a reverse <c>(end, start]</c> one.
|
||
/// </summary>
|
||
/// <param name="startUtc">The window start (the later bound of a reverse read).</param>
|
||
/// <param name="endUtc">The window end (the exclusive earlier bound of a reverse read).</param>
|
||
/// <param name="reverse">Whether the read is newest-first (<c>start > end</c>).</param>
|
||
/// <param name="horizon">The horizon; non-positive = none (nothing changes).</param>
|
||
/// <param name="nowUtc">Now.</param>
|
||
/// <returns><c>false</c> when the whole window lies before the floor — the read is empty and must not be sent.</returns>
|
||
public static bool TryClamp(ref DateTime startUtc, ref DateTime endUtc, bool reverse, TimeSpan horizon, DateTime nowUtc)
|
||
{
|
||
if (horizon <= TimeSpan.Zero) return true;
|
||
var floor = nowUtc.Ticks - DateTime.MinValue.Ticks > horizon.Ticks
|
||
? new DateTime(nowUtc.Ticks - horizon.Ticks, DateTimeKind.Utc)
|
||
: new DateTime(0, DateTimeKind.Utc);
|
||
if (floor.Ticks == 0) return true;
|
||
|
||
if (reverse)
|
||
{
|
||
if (startUtc < floor) return false; // (end, start] lies wholly before the floor
|
||
var below = floor.AddTicks(-1); // exclusive lower end ⇒ the floor instant itself is read
|
||
if (endUtc < below) endUtc = below;
|
||
return true;
|
||
}
|
||
|
||
if (endUtc <= floor) return false; // [start, end) lies wholly before the floor
|
||
if (startUtc < floor) startUtc = floor;
|
||
return true;
|
||
}
|
||
}
|