…er clear/rollback
Senders cache designated-timestamp ColumnBuffer refs and derive
bookkeeping from their table buffers. rollbackUncommittedColumns()
(failed at()) and QwpTableBuffer.clear() close those columns, leaving
dangling refs that NPE on the next at() and corrupt pending accounting.
- Invalidate WebSocket timestamp caches in rollbackRow(); cancelRow()
now routes through it.
- Add QwpTableBuffer.Owner: clear() notifies the owning sender before
releasing columns. WebSocket subtracts the buffer's exact accounted
share (committedBytes - new baselineBytes, seed offsets excluded);
UDP resets transient row state, datagram estimate, and headroom
state (its base-estimate cache is keyed by column count alone).
- Unify flush snapshot anchoring at post-reset storage so per-table
contributions are exact under any reset/switch/flush history.
Hot path unchanged. Regressions: clear between rows (both units, both
senders), non-current/mid-row clear, accounting locality, stale
headroom estimate.
A QWP/WebSocket sender could become unusable after rejecting an oversized row that introduced the table’s designated timestamp column. The rollback removed the column, but the sender kept a cached reference to it, so the next timestamped row failed with a
NullPointerException.The sender now discards cached timestamp state when a row is rolled back, allowing ingestion to continue after an oversized-row error. Clearing a sender-owned
QwpTableBufferthrough the test-only accessors now performs equivalent cleanup and reconciles WebSocket row/byte accounting and UDP datagram-size estimates, so the buffer can be reused safely.