Skip to content

Read response headers in blocks instead of one byte at a time - #2241

Open
xroche wants to merge 8 commits into
masterfrom
read-headers-in-blocks
Open

xroche wants to merge 8 commits into
masterfrom
read-headers-in-blocks

Conversation

@xroche

@xroche xroche commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

The engine read response headers with one recv() per byte and a select() after each byte. It now peeks at the buffered bytes, finds where the old byte loop would stop, and reads exactly that much. On a synthetic crawl of 100,000 pages, CPU time falls from 78.7 s to 58.7 s (median of three runs), and system time halves.

Linux 5.6 to 5.12 ignore MSG_PEEK on MPTCP sockets and consume the data. So once the engine opens an MPTCP socket on such a kernel, or on macOS, it reads bytewise again. A self-test checks that both paths leave the same lines and the same unread bytes on random streams.

xroche and others added 7 commits November 14, 2026 18:07
The line modes of http_xfread1() read one byte per recv() and called
select() after each byte, so a 150-byte header block cost about 300
syscalls. They now peek at what is buffered, find where the byte loop
would stop, and consume exactly that, so the bytes taken from the
socket and the per-call stops are unchanged. Transports that cannot
peek (files, old MPTCP kernels) keep the byte loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
…t flag

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
…ffer entry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche
xroche enabled auto-merge (squash) November 14, 2026 18:00
macOS loopback hands sent bytes to a separate input thread, so the
zero-timeout poll right after send() could see nothing. The case then
read nothing and left its bytes for the next one, and xfread-lines
failed on the macOS arm64 leg. A mutant that delivers the stream 5 ms
late reproduces this on Linux, and passes with the wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
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.

1 participant