perf(historian): exact tag lookup and a non-thrashing presence cache (lmxopcua#746)
Every Gateway HistoryRead was preceded by a BrowseTagNames catalog stream keyed by a glob filter (a name with '*' or '?' streamed every match), and the 4096-entry presence cache evicted an arbitrary entry (Keys.First()) when full, so a sweep over more tags thrashed it. The presence check is now one exact unary GetTagMetadata (null = absent). Only the deployed gateway's known misparse of a missing tag (Internal / Unknown / InvalidDataException) falls back to the exact-name catalog check; any other failure propagates and never becomes absence. The positive TTL is 5 minutes (was 60 s); a full cache drops expired entries first, else the one closest to expiry. Wire tests cover the working, the misparsing and the refusing gateway. Rebased from the unpushed remed/lane-H2 branch (originally authored 2026-10-22 in session_01Ub9hGmYLQvn9XETzw7CMsT) onto current master. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
+8
-3
@@ -839,11 +839,16 @@ data.
|
||||
refusing; doubling the look-back allowance does not skip that final usable budget. Reverse paging retries a crowded segment
|
||||
with a smaller in-window budget derived from the learned ceiling and the observed pre-window rows.
|
||||
|
||||
**Missing tags (#653).** Gateway Raw, Processed and AtTime first check the tag catalog. An empty exact-name catalog result or an explicit
|
||||
**Missing tags (#653).** Gateway Raw, Processed and AtTime first check that the tag exists. An absent tag or an explicit
|
||||
`NotFound` returns no data without a history RPC: Raw is empty; AtTime and Processed return null/`BadNoData` at the
|
||||
requested times or bucket timestamps. Unsupported aggregate validation still runs first. A bounded per-data-source cache
|
||||
holds at most 4,096 tag names, with **5 seconds** for absence and **60 seconds** for presence, so newly provisioned tags become
|
||||
visible after the short negative expiry. Catalog faults and cancellation never become missing-tag cache entries. The adapter drains the filtered catalog stream and checks exact names, avoiding older gateways that misparse a missing `GetTagMetadata` response as `Internal`. Empty
|
||||
holds at most 4,096 tag names, with **5 seconds** for absence and **5 minutes** for presence (was 60 s), so newly provisioned tags become
|
||||
visible after the short negative expiry; when full it drops expired entries first, else the one closest to expiry (it used to drop an
|
||||
arbitrary one, which thrashed a sweep over more than 4,096 tags). Lookup faults and cancellation never become missing-tag cache entries.
|
||||
The check is **one exact unary `GetTagMetadata`** (null = absent). The deployed gateway misparses that reply for a *missing* tag and
|
||||
answers `Internal`; only that answer (or `Unknown` / the parser's `InvalidDataException`) falls back to the filtered catalog stream
|
||||
(`BrowseTagNames`, drained, exact-name compare — the filter is a glob, so a name with `*`/`?` streams every match but still answers
|
||||
exactly). Any other failure propagates and is never turned into absence. Empty
|
||||
AtTime/Processed requests need no check. Events and modified-history capability checks are unaffected.
|
||||
|
||||
**Stopped-tag reverse discovery (#696).** On a strict Gateway, a truncated remainder probe retains its oldest-row evidence
|
||||
|
||||
Reference in New Issue
Block a user