fix(historian): address code review on Raw HistoryRead paging
C1 (critical): a boundary tie cluster larger than NumValuesPerNode could silently truncate a resumed read to GoodNoData, permanently dropping the un-emitted ties — the (timestamp, skip) cursor cannot advance past a single timestamp the fixed-(start,end,cap) backend keeps re-returning. Now detected and failed LOUDLY per node with BadHistoryOperationUnsupported + a log naming the tag/timestamp/cap; documented in Historian.md with the larger-cap remedy. Regression test Raw_tie_cluster_larger_than_page_fails_loudly_not_silently. I3: build HistoryData before Save() so a projection failure can never orphan a stored continuation cursor. N1 (YAGNI): drop the never-produced HistoryReadKind enum + Processed-only Aggregate/IntervalTicks fields from HistoryContinuationState — only Raw pages. N3: ComputeResumeCursor guards its documented non-empty precondition. I1: document InMemoryHistoryContinuationStore's eventual-consistency (test double). Build clean, 182/182 OpcUaServer tests pass.
This commit is contained in:
@@ -137,6 +137,17 @@ paging time-based:
|
||||
SourceTimestamp *inclusive* and drops the boundary samples already emitted, so samples sharing
|
||||
the boundary timestamp are neither duplicated nor skipped.
|
||||
|
||||
> **Paging limitation — oversized tie clusters.** The tie-safe cursor is a `(timestamp, skip)`
|
||||
> pair, and the single-shot backend only accepts `(start, end, cap)` — it cannot skip. So if **more
|
||||
> samples share one `SourceTimestamp` than `NumValuesPerNode`** (a tie cluster larger than the page
|
||||
> cap), the cursor cannot advance past that timestamp: every resume re-reads the same first `cap`
|
||||
> ties. Rather than silently truncate the read to `GoodNoData` (which would permanently drop the
|
||||
> un-emitted ties), the resume read fails that node **loudly** with
|
||||
> `BadHistoryOperationUnsupported` and logs the tag + timestamp + cap. The operator's remedy is to
|
||||
> re-issue the read with a larger `NumValuesPerNode`. For a single tag's raw history this is a data
|
||||
> anomaly (raw samples normally carry strictly increasing distinct timestamps); a fully cursor-based
|
||||
> fix that pages *within* a single timestamp is a possible follow-up.
|
||||
|
||||
Continuation points are bound to the OPC UA session (the SDK's
|
||||
`ServerConfiguration.MaxHistoryContinuationPoints` cap, default 100, with oldest-eviction; points
|
||||
are disposed when the session closes). Resuming an unknown / evicted / released point returns
|
||||
|
||||
Reference in New Issue
Block a user