Skip to content

Count compound responses the server split across frames #19

Open

Description

@vdavid

Context

A compound request (CREATE + READ + CLOSE in one frame, for example) normally gets one compound response. MS-SMB2
§ 3.3.4.1.3 lets a server answer it in several frames instead, and Samba (plus the QNAP firmware built on it) and
Windows Server both do in some cases. The client handles that transparently: the receiver task routes each sub-response
by its MessageId, and Connection::execute_compound reassembles the results in submission order.

SmbClient::diagnostics() / Connection::diagnostics() expose per-connection counters (MetricsSnapshot), including
the four-way routing partition, status_pending_loops, and the frame-error counters. A response_splits_observed
counter was designed alongside them and deferred.

Problem

Nothing counts or logs a split today, so there's no way to see from a snapshot or a log whether a server splits
compounds, how often, or whether a performance difference between two servers lines up with it. It's a diagnostic gap,
not a correctness one: splits are handled either way.

The reason it was deferred is the shape of the actor. Each sub-op's oneshot::Receiver resolves on its own as its
MessageId arrives, so the receiver task doesn't know "N sub-responses are expected for this caller", and
execute_compound doesn't see which transport frame each sub-response came from.

Solution

Tag each routed sub-response with the transport frame it arrived in, and have execute_compound count a split when its
sub-responses carry more than one tag.

For the implementer

  • crates/smb2/src/client/connection.rs: in receiver_loop, give each received transport frame a sequence number (a
    per-connection counter is enough) and carry it on the routed Frame or next to it through the waiter's
    oneshot::Sender. Keep it crate-private; Frame is public, so don't add a public field for this.
  • execute_compound: after collecting its results, tick metrics.response_splits_observed once if the sub-responses
    came from more than one frame. Count per compound call, not per extra frame, to match compound_requests_sent.
  • crates/smb2/src/client/diagnostics.rs: add the field to MetricsSnapshot (it's #[non_exhaustive], so this is a
    minor change), document it, and add it to the Display output.
  • A debug! line naming the command chain and frame count when a split is seen would help live diagnosis too; keep it
    at debug, since a split is protocol-normal.
  • Tests: a mock-transport test that answers a three-op compound in two frames and asserts the counter reads 1, and one
    that answers it in one frame and asserts 0 (the existing execute_compound_partial_failure_routes_correctly shows how
    to script compound answers on the mock). AGENTS.md pitfall 13 and client/CLAUDE.md § Gotchas both say "nothing
    counts or logs a split"; update them.

Impact: Makes server-side compound splitting visible in diagnostics · Size: S (one tag through the demux, one
counter, two tests)

Origin: Diagnostics plan § response_splits_observed is deferred

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions