Skip to content

Conversation

@lexnv
Copy link
Collaborator

@lexnv lexnv commented Jan 14, 2026

The substream implementation utilises a pending_out_bytes counter to enforce backpressure via flushing once the buffer fills up to 64KiB.

  • The pending out bytes counter is properly incremented when data is received
  • However, the variable was never decremented when writing data into the underlying socket
  • Once enough data is received, this led to the poll_ready to make a syscall to flush the socket at every call

This implementation decrements the counter when data is moved to the socket. This should optimize the poll_ready fn for long lived substreams.

While at it, the poll_ready implementation calls into the Sink::poll_flush which also drains the pending frames.

@lexnv lexnv self-assigned this Jan 14, 2026
Comment on lines +680 to +688
// This attempts to empty 'pending_out_frames' into the socket.
match futures::Sink::poll_flush(self.as_mut(), cx) {
Poll::Ready(Ok(())) => {}
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Pending => {
// Still flushing. We cannot accept new data yet.
return Poll::Pending;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is this different from poll_flush!?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The poll_flush! should call into the socket / TCP under the hood via AsyncWrite::poll_flush.

By calling the futures::Sink::poll_flush we ensure our impl is always called and try to write any pending frames before calling poll_flush

@lexnv lexnv merged commit 4ce2fbe into master Jan 20, 2026
2 checks passed
@lexnv lexnv deleted the lexnv/opt-len-enc branch January 20, 2026 15:37
dmitry-markin added a commit that referenced this pull request Jan 21, 2026
## [0.13.0] - 2026-01-21

This release brings multiple fixes to both the transport and
application-level protocols.

Specifically, it enhances WebSocket stability by resolving AsyncWrite
errors and ensuring that partial writes during the negotiation phase no
longer trigger connection failures.

At the same time, Bitswap client functionality is introduced, which
makes this release semver breaking.

### Added

- Add Bitswap client
([#501](#501))

### Fixed

- notif/fix: Avoid CPU busy loops on litep2p full shutdown
([#521](#521))
- protocol: Ensure transport manager knows about closed connections
([#515](#515))
- substream: Decrement the bytes counter to avoid excessive flushing
([#511](#511))
- crypto/noise: Improve stability of websockets by fixing AsyncWrite
implementation ([#518](#518))
- bitswap: Split block responses into batches under 2 MiB
([#516](#516))
- crypto/noise: Fix connection negotiation logic on partial writes
([#519](#519))
- substream/fix: Fix partial reads for ProtocolCodec::Identity
([#512](#512))
- webrtc: Avoid panics returning error instead
([#509](#509))
- bitswap: e2e test & max payload fix
([#508](#508))
- tcp: Exit connections when events fail to propagate to protocols
([#506](#506))
- webrtc: Avoid future being dropped when channel is full
([#483](#483))

---------

Co-authored-by: Alexandru Vasile <[email protected]>
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.

3 participants