Skip to content

P4b: invert non-row bounded tokens to sync TdsCore step_token driver - #199

Draft
Saurabh Singh (saurabh500) wants to merge 2 commits into
dev/saurabh/sans-io-p4a-tdscore-row-driverfrom
dev/saurabh/sans-io-p4b-nonrow-receive
Draft

P4b: invert non-row bounded tokens to sync TdsCore step_token driver#199
Saurabh Singh (saurabh500) wants to merge 2 commits into
dev/saurabh/sans-io-p4a-tdscore-row-driverfrom
dev/saurabh/sans-io-p4b-nonrow-receive

Conversation

@saurabh500

Copy link
Copy Markdown
Contributor

P4b — Invert the non-row RECEIVE / token-consume paths to a sans-I/O sync core

Base: dev/saurabh/sans-io-p4a-tdscore-row-driver (frozen P4a tip 07099e0c). Draft; do not merge — coordinator will verify from git ground truth + a real nextest and append to stack #192.

Mirrors P4a's row inversion for the non-row receive path. Every guaranteed-bounded category-(a) non-row token is now parsed by a pure-sync body over PacketBuffer, driven by one async shell that owns the sole refill .await. Value-carrying / login tokens stay on an explicit async seam. Zero behavior change; public API frozen async-only.

What changed

  • TokenStep + TdsCore::step_token (io/tds_core.rs) — peeks the token byte, ensures the length-bounded body, and parses in place; returns NeedBytes on entry underflow (nothing consumed, restartable) or AsyncToken(tt) for seamed tokens.
  • io/sync_token.rs (new) — the pure-sync parse leaf: one production parse body per category-(a) token (DONE/DONEINPROC/DONEPROC, RETURNSTATUS, ORDER, ERROR, INFO, ENVCHANGE), byte-for-byte mirroring the async parsers.
  • drive_token_over_buffer + resolve_header_token (io/token_stream.rs) — the single async shell; rewires the three production receive_token sites in network_transport.rs.
  • Oracle retainedreceive_token_internal is gated #[cfg(any(test, fuzzing))] as a differential byte-identity oracle; grep-proven no production path reaches it (its only non-test callers are #[cfg(fuzzing)]).

Scope honesty (deferred work)

COLMETADATA / RETURNVALUE / SESSIONSTATE / FEATUREEXTACK (category-(b), value/PLP-carrying) and the login/handshake tokens (LOGINACK/TABNAME/COLINFO/SSPI/FEDAUTHINFO) remain on the AsyncToken async seam. Their pure-sync inversion is deferred to a later, parent-gated layer that would introduce a sanctioned mid-token TokenPauseState cursor. The receive path is not fully sync after P4b — this is stated in the tds_core.rs module doc and enforced by leaving those tokens on the seam. No new resumable machine is introduced here.

Two folded P4a-hardening items (carried here, not in #198)

  1. RowStep::AsyncColumn load-bearing doc comment (io/tds_core.rs) — bakes in the exact rationale that yielding an unbounded PLP column preserves L4b bounded residency and must never be collapsed into NeedBytes{shortfall}.
  2. Strict production-path eager-PLP residency-CEILING test (tdscore_step_row_eager_plp_residency_ceiling_on_production_driver) — decodes a >8192 B eager-PLP LOB through drive_row_over_buffer (production) and asserts peak PacketBuffer residency stays ≲ one buffer/chunk via a #[cfg(test)] peak_length high-water hook (off the public surface). It FAILS if AsyncColumn is ever collapsed to a collect-whole / NeedBytes(full-len) path.

Note: P4a's own eager-PLP residency guarantee is asserted one layer up (here, in P4b) rather than in #198, to keep the frozen P4a tip 07099e0c stable. A reviewer of #198 should not be confused about why that assertion lives in P4b.

Tests (through the new sync driver)

  • DONE/DONEINPROC/DONEPROC, ERROR/INFO, ORDER, ENVCHANGE — swept at every interior split vs the oracle (byte-identical resume, no consume-on-shortfall, no hang).
  • COLMETADATA split across a refill boundary — proves the AsyncToken seam handles a token spanning a refill.
  • COLMETADATA → ROW handoff — proves the seam hands off to the row driver over the shared buffer.

Gate (from this worktree)

  • cargo nextest run -p mssql-tds --lib --no-fail-fast → fail-set == exactly the 7 known cert fixtures (Compare-Object of sorted fail-name sets == EMPTY), no hang.
  • cargo bfmt + cargo bclippy (-D warnings) clean; scripts/bfmt.ps1 + scripts/bclippy.ps1 clean incl. mssql-py-core; cargo build --all-features in mssql-py-core OK.
  • Public-API diff-scan == EMPTY (all new symbols pub(crate)/cfg(test)).

Mirror P4a's row inversion for the non-row receive path: parse the bounded
category-(a) tokens (DONE/DONEINPROC/DONEPROC, RETURNSTATUS, ORDER, ERROR,
INFO, ENVCHANGE) with a pure-sync body over PacketBuffer and drive them from
one async shell that owns the sole refill .await.

- Add TokenStep + TdsCore::step_token (tds_core.rs) and the sync parse leaf
  sync_token.rs (one production parse body per (a) token).
- Add drive_token_over_buffer + resolve_header_token (token_stream.rs); rewire
  the three production receive_token call sites in network_transport.rs.
- Retain receive_token_internal as a #[cfg(any(test, fuzzing))] oracle; the
  value-carrying (b) tokens (COLMETADATA/RETURNVALUE/SESSIONSTATE/
  FEATUREEXTACK) and login tokens stay on the AsyncToken async seam; their
  pure-sync inversion is deferred to a later parent-gated TokenPauseState layer.
- Fold two P4a-hardening items: strengthen the RowStep::AsyncColumn doc with the
  load-bearing bounded-residency rationale, and add a strict production-path
  eager-PLP residency-ceiling test on drive_row_over_buffer (cfg(test)
  peak_length hook on PacketBuffer, off the public surface).
- Add refill-boundary differential tests: DONE family, ERROR/INFO, ORDER,
  ENVCHANGE swept at every split vs the oracle, COLMETADATA across a refill via
  the seam, and a COLMETADATA -> ROW handoff.

Public API frozen (all new symbols pub(crate)/cfg(test)).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e2c378f8-3ba1-4b48-9ebe-5a4ea2bd2761
Replace the magic 8192 constant with the working buffer's real capacity read
from the production reader, so the eager-PLP residency ceiling asserts against
the actual in-test 2 x negotiated-packet cap. Regress-on-flip verified: forcing
whole-value residency at the eager-PLP path fails the test (guard trip on the
fixed cap; the explicit peak <= buffer_capacity assertion on a growable cap).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e2c378f8-3ba1-4b48-9ebe-5a4ea2bd2761
@saurabh500
Saurabh Singh (saurabh500) marked this pull request as ready for review August 10, 2026 06:38
@saurabh500
Saurabh Singh (saurabh500) requested a review from a team as a code owner August 10, 2026 06:38
Copilot AI balanced review requested due to automatic review settings August 10, 2026 06:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Moves bounded non-row token parsing into the synchronous TdsCore path while retaining async seams for value-carrying tokens.

Changes:

  • Adds synchronous token classification and parsing.
  • Rewires production token reception through one async refill driver.
  • Adds differential and PLP residency tests.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
mssql-tds/src/io/token_stream.rs Adds token drivers and boundary tests.
mssql-tds/src/io/tds_core.rs Adds synchronous token stepping.
mssql-tds/src/io/sync_token.rs Implements synchronous token parsers.
mssql-tds/src/io/packet_buffer.rs Adds test-only residency tracking.
mssql-tds/src/io.rs Registers the new module.
mssql-tds/src/connection/transport/network_transport.rs Uses the new production driver.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +260 to +261
if let Err(need) = buf.ensure(total) {
return Ok(TokenStep::NeedBytes(need));
Comment on lines +105 to +108
TokenType::Order => parse_order_body(buf),
TokenType::Error => parse_error_body(buf),
TokenType::Info => parse_info_body(buf),
TokenType::EnvChange => parse_envchange_body(buf),
@saurabh500
Saurabh Singh (saurabh500) marked this pull request as draft August 10, 2026 06:49
@saurabh500
Saurabh Singh (saurabh500) marked this pull request as ready for review August 10, 2026 07:39
@saurabh500
Saurabh Singh (saurabh500) marked this pull request as draft August 10, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants