Gateway reverse raw paging reads ~32k rows per page on busy tags (ReverseRawReader sizing) #689

Closed
opened 2026-10-12 16:03:37 -04:00 by dohertj2 · 1 comment
Owner

Found by the #686 live AVEVA gate (2026-10-12, master 1f5d3100).

Symptom: paging an end-only ("latest N") or explicit-reverse HistoryRead-Raw on a busy Gateway tag degrades after the first few pages: from about page 5, every page reads ~32,770 rows from the gateway and takes 2–5 s, even when it returns 2 rows.

Repro: end-only read (StartTime unset, EndTime set) on SysTimeSec (1 Hz) with NumValuesPerNode = 3 or 500, paged to completion through the node manager.

Cause: ReverseRawReader sizes each segment request at about half of MaxTieClusterOverfetch (32,768 by default) rather than near the page size N, and carries that width forward in the continuation point.

Suggested fix: size the segment from N (and the observed density), keeping the MaxTieClusterOverfetch budget only as a ceiling for tie clusters. Add a test that counts rows requested per page on a dense tag.

Evidence: scratchpad/livegate-aveva-685.md (N1).

Found by the #686 live AVEVA gate (2026-10-12, master `1f5d3100`). **Symptom:** paging an end-only ("latest N") or explicit-reverse HistoryRead-Raw on a busy Gateway tag degrades after the first few pages: from about page 5, every page reads ~32,770 rows from the gateway and takes 2–5 s, even when it returns 2 rows. **Repro:** end-only read (StartTime unset, EndTime set) on `SysTimeSec` (1 Hz) with NumValuesPerNode = 3 or 500, paged to completion through the node manager. **Cause:** `ReverseRawReader` sizes each segment request at about half of `MaxTieClusterOverfetch` (32,768 by default) rather than near the page size N, and carries that width forward in the continuation point. **Suggested fix:** size the segment from N (and the observed density), keeping the `MaxTieClusterOverfetch` budget only as a ceiling for tie clusters. Add a test that counts rows requested per page on a dense tag. Evidence: `scratchpad/livegate-aveva-685.md` (N1).
Author
Owner

Fixed on master 15ccd9b7 (merge 88141d6e). The reverse walk moved into ReverseWalk.cs: segments are sized from the page size N (~N+8 target, ≤ 2N+18 per read; MaxTieClusterOverfetch is only the tie-cluster ceiling), it gallops up then bisects above a truncated read, never stepping below the 1 ms request granularity; a tie refusal is now "more than M rows within one millisecond" (exact for the ms-resolution Gateway). Reviewed twice (3,000–5,000-seed fuzz harness, 0 wrong results, worst page 70 reads).

Live AVEVA gate PASS: paged "latest N" on SysTimeSec asks for 40 rows/page at N=3 and 1,034 at N=500, ~150 ms per page (was 32,770 rows, 2–5 s); exact newest-first, no gaps/dups; a long-quiet tag's first page = 3 reads. Follow-ups: #692 (N=1 alternating empty pages, all backends), #694.

Fixed on master `15ccd9b7` (merge `88141d6e`). The reverse walk moved into `ReverseWalk.cs`: segments are sized from the page size N (~N+8 target, ≤ 2N+18 per read; `MaxTieClusterOverfetch` is only the tie-cluster ceiling), it gallops up then bisects above a truncated read, never stepping below the 1 ms request granularity; a tie refusal is now "more than M rows within one millisecond" (exact for the ms-resolution Gateway). Reviewed twice (3,000–5,000-seed fuzz harness, 0 wrong results, worst page 70 reads). **Live AVEVA gate PASS:** paged "latest N" on `SysTimeSec` asks for 40 rows/page at N=3 and 1,034 at N=500, ~150 ms per page (was 32,770 rows, 2–5 s); exact newest-first, no gaps/dups; a long-quiet tag's first page = 3 reads. Follow-ups: #692 (N=1 alternating empty pages, all backends), #694.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#689