fix(remote): deliver a line the inflater still holds - #537
Merged
Merged
Conversation
A highly compressible line (a ProvidersReplaced that repeats the model catalogs, for example) could fill LineStream's output buffer while every input byte was already consumed, leaving the rest of the line, newline included, inside the inflater. read_line then waited on the network, so the line only surfaced when the peer sent another one: a phone showed the Usage refresh spinning long after the host had finished the check. Keep inflating until the output buffer has spare room, the same rule the writer already uses for the deflater.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Behaviour
Over iroh (a phone attached to a Mac), a highly compressible protocol line could be held back until the peer sent its next line. Observed: the phone's Settings → Usage refresh kept spinning although the host finished the usage check in ~3 s and emitted
ProvidersReplacedwith the check cleared.Cause:
LineStream::read_line(added in #514's raw-deflate stream) calleddecompress_veconce perfill_buf. When the line expands far beyondcompressed.len() * 4 + 1024, the output buffer fills while every input byte is already consumed; the rest of the line, newline included, stays inside the inflater, andread_linegoes back to waiting on the network.Fix: keep inflating the chunk until the output buffer has spare room — the same termination rule the writer's
deflatehelper already uses. The loop is bounded by the chunkfill_bufreturned, so no separate size cap is needed inside it; the existingmaxcheck still runs before the next read.Both directions share
LineStream(host.rsbridge andclient.rsrelay), so both are fixed. No other streaming decompression exists in the workspace (the ACP registry gunzips a complete download).Structure
LineStream<R = LineReader>is generic overAsyncBufReadso the test can feed it from an in-memory duplex; callers are unchanged.compress_lineis the writer's per-line encoding, extracted so the test produces exactly whatLineWritersends.Test
a_highly_compressible_line_arrives_without_waiting_for_the_next: one complete compressed line arrives and the peer keeps the stream open. Contract: the line is returned without further input. Without the fix it times out after 5 s (verified); with it, it passes.Checks run
cargo test -p tcode-traverse— passcargo fmt --all --check— passcargo clippy -p tcode-traverse --all-targets --all-features --locked -- -D warnings— pass