docs(historian): #686 open-ended and reverse raw reads on every backend
This commit is contained in:
@@ -620,6 +620,35 @@ paging time-based:
|
||||
> anomaly. The ceiling exists to bound server-side memory on pathological data, not to cap normal
|
||||
> operation.
|
||||
|
||||
**Open-ended and reverse raw reads (#669, #686).** With `NumValuesPerNode > 0` one bound may be unset (Part 11): a
|
||||
start-only read pages **forward** to an open upper bound; an end-only read pages **backward** from `EndTime` — the reverse
|
||||
window `(MinValue, EndTime]`, newest first, so the first page is the `NumValuesPerNode` values at or before `EndTime`. An
|
||||
explicit `StartTime > EndTime` is the reverse window `(EndTime, StartTime]`, newest first. These semantics hold on **every**
|
||||
backend:
|
||||
|
||||
- **SqlServer / QuestDB** report `IHistorianDataSource.SupportsReverseRaw = true` and are sent the reverse window directly
|
||||
(`… > lo AND … <= hi ORDER BY time DESC`).
|
||||
- **Gateway** (the default backend) reports `false` — the gateway's `ReadRaw` streams ascending only and rejects
|
||||
`start > end` with `InvalidArgument`. The server never sends it one (and the source refuses one unsent, not counted as a
|
||||
health failure): it **walks the window back in bounded forward reads** (`ReverseRawReader`). It reads one segment
|
||||
`(segLo, segHi]` forward — requested `[segLo, segHi + resolution]` and filtered on the samples' own timestamps, which also
|
||||
drops the rows AVEVA fabricates at a query's start — keeps it newest-first, and steps to the next older segment until the
|
||||
page is full or the window is exhausted. Segments start at **1 minute** and grow ×4 while sparse, so "the last N values"
|
||||
of a live tag is normally one small read and sparse history is found in a few dozen tiny ones. Each segment read asks for
|
||||
at most `MaxTieClusterOverfetch + 1` rows; a read that comes back full may be truncated (its newest rows are the ones
|
||||
needed), so it is discarded and the segment re-read at a quarter of the width — **never answered from a truncated
|
||||
read**. A single-timestamp tie cluster larger than `MaxTieClusterOverfetch` cannot be served newest-first this way and
|
||||
the node is refused **`BadTooManyOperations`** (a request limit, not a backend fault). The walk stops at the **Unix epoch**
|
||||
(AVEVA holds nothing earlier): a walked-back read returns no sample before 1970. Paging is unchanged — a reverse cursor
|
||||
resumes as a fresh walk from its resume point.
|
||||
- **Null** reports `true` (empty in either direction).
|
||||
|
||||
> ⚠️ **Client-visible (#686).** Since #669 an end-only capped raw read, and any explicit reverse raw read, on the Gateway
|
||||
> backend failed the node (`BadHistoryOperationUnsupported`) and was counted as a historian backend failure (the gateway
|
||||
> refused `start > end`). Before #669 an end-only read on Gateway returned the **oldest** N values ascending. Both now return
|
||||
> the Part 11 answer — the latest values at or before `EndTime`, newest first. **Events differ:** an end-only events read on
|
||||
> Gateway still keeps its forward meaning and an explicit reverse events read is refused (see below).
|
||||
|
||||
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