Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/EventHorizon.cs
T
Joseph Doherty 826312befe docs: fill missing XML docs and strip tracking IDs from src comments
Clears CommentChecker findings in src/ (3,280 -> 209, the remainder being false
positives like PLC-5/IEEE-754/M0.0) by adding missing summaries/params/returns,
normalising inheritdoc usage, and removing Gitea/review tracking IDs while keeping
the rationale they annotated. Comment-only: comment-stripped sources are identical
to the parent commit.
2026-10-15 06:14:58 -04:00

44 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
/// <summary>
/// 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 — ~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 &gt; 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;
}
}