Skip to content

refactor(model): fold rwnd_remaining into set_rcv_buf - #28

Merged
BobAnkh merged 2 commits into
mainfrom
rwnd-trace-semantics
Aug 29, 2026
Merged

refactor(model): fold rwnd_remaining into set_rcv_buf#28
BobAnkh merged 2 commits into
mainfrom
rwnd-trace-semantics

Conversation

@zhang-hc22

Copy link
Copy Markdown
Contributor

This PR solves issue #27.

Description

A rwnd step had two mutually exclusive action fields, and which one it used
decided how the receiver behaved -- but neither name said so. rwnd_remaining
only reproduced the window it named if the application drained continuously, so
the right edge slid with rcv_nxt; app_read_bytes meant the opposite, a fixed
budget after which the window decayed from what was left unread. The reading
behaviour was the whole difference, and it was carried by convention in the
replayer rather than by the format.

set_rcv_buf now carries that meaning: it sizes the buffer and states that the
application keeps up with it, so the window is held there. That is what
rwnd_remaining said, minus the second way of saying it.

The two fields become orthogonal rather than alternatives, so every combination
is meaningful -- a buffer, a read, both (resize then read), or neither (carry the
previous step forward). With no invariant left to enforce, the hand-written
Deserialize and its both-set error go away and Serialize/Deserialize
derive.

set_rcv_buf app_read_bytes meaning
N buffer N, window pinned at N, application drains continuously
M application reads M bytes against the standing buffer; window = buffer − unread
N M resize the buffer to N, then read M bytes from it
carry the previous configuration forward for this step's duration

Unknown keys are now rejected (deny_unknown_fields on StaticRwndConfig).
Serde's default of skipping what it does not recognise would turn every window
step of an existing trace into a step that says nothing -- a replay that
completes and looks healthy while reproducing no receiver at all.
Deserialization now fails and names the offending field instead.

  • RwndAction removed; RwndDecision becomes two independent Option<u64> fields
  • hand-written Deserialize and the both-set error replaced by a derive
  • StaticRwndConfig::remaining() dropped; set_rcv_buf() and app_read() may now be combined
  • old-schema traces rejected rather than silently degraded
  • doc comments on RwndDecision and the rwnd module restated in the new vocabulary

Two files change, src/lib.rs and src/model/rwnd.rs, for a net reduction of 84
lines. The rwnd-model feature and the model/mod.rs re-exports added in #26 are
unchanged.

Note this is a breaking change to a schema already published in v0.4.6: traces
using rwnd_remaining will not deserialize.

Fixes #

How Has This Been Tested

Local, rustc 1.98.0, Linux x86_64.

  • cargo test --all-features — 32 lib tests and 53 doc tests pass, 9 of them
    covering rwnd specifically: buffer-only, app-read-only, both fields on one
    step, neither field, the repeated pattern, serde round-trips in both human
    and non-human forms, omission of absent keys, rejection of a trace still
    using rwnd_remaining, and the zero-duration infinite-pattern termination
    case.
  • cargo clippy --all-features --all-targets — no warnings or errors.
  • cargo fmt --check — clean.
  • Downstream end-to-end, which is the check a fixture cannot make: a real trace
    was generated from a packet capture by the downstream generator under the new
    schema (4867 steps: 4808 set_rcv_buf, 59 app_read_bytes, no other keys) and
    then loaded by the downstream replayer, which parsed exactly those counts. That
    exercises the two ends of the schema against each other rather than against a
    hand-written example.

Not tested here: behaviour on the wire. This PR changes what a trace says, and
the two behaviours it names were already implemented downstream, so no replay
behaviour is expected to change for an equivalent trace. The fidelity of the
resulting emulation is measured downstream, not in this repository.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • Code follows the code style of this project.
  • Changes follow the CONTRIBUTING guidelines.
  • Update necessary documentation accordingly.
  • Lint and tests pass locally with the changes.
  • Check issues and pull requests first. You don't want to duplicate effort.

Other information

Branched from main at b4cb89c rather than cherry-picked from the earlier
working branch: main already carries the rwnd implementation from #26, so a
cherry-pick would have collided add/add on src/model/rwnd.rs and produced a
diff that read as re-adding an existing file instead of changing its semantics.

CHANGELOG.md is untouched — it is generated per release from PR titles, so a
hand-written entry would be overwritten.

A rwnd step had two mutually exclusive action fields, and which one it
used decided how the receiver behaved -- but neither name said so.
rwnd_remaining only reproduced the window it named if the application
drained continuously, so the right edge slid with rcv_nxt; app_read_bytes
meant the opposite, a fixed budget after which the window decayed from
what was left unread. The reading behaviour was the whole difference, and
it was carried by convention in the replayer rather than by the format.

set_rcv_buf now carries that meaning: it sizes the buffer and states that
the application keeps up with it, so the window is held there. That is
what rwnd_remaining said, minus the second way of saying it.

The two fields become orthogonal rather than alternatives, so every
combination is meaningful -- a buffer, a read, both (resize then read),
or neither (carry the previous step forward). With no invariant left to
enforce, the hand-written Deserialize and its both-set error go away and
Serialize/Deserialize derive.

@Centaurus99 Centaurus99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be helpful to describe more precisely in the docstring the behavior when both set_rcv_buf and app_read_bytes are specified, and to add this case to the docstring examples.

@zhang-hc22
zhang-hc22 requested a review from Centaurus99 August 29, 2026 05:42

@Centaurus99 Centaurus99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@Centaurus99
Centaurus99 requested a review from BobAnkh August 29, 2026 06:04
@BobAnkh
BobAnkh merged commit 8347527 into main Aug 29, 2026
9 checks passed
@BobAnkh
BobAnkh deleted the rwnd-trace-semantics branch August 29, 2026 06:08
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.

[enhancement] Simplify rwnd trace semantics: fold rwnd_remaining into set_rcv_buf

3 participants