Skip to content

Stream iodata in bounded chunks#12

Draft
harmon25 wants to merge 2 commits into
mainfrom
optimizations
Draft

Stream iodata in bounded chunks#12
harmon25 wants to merge 2 commits into
mainfrom
optimizations

Conversation

@harmon25

Copy link
Copy Markdown
Owner

This pull request significantly improves how large responses are sent over TCP by incrementally walking nested iodata structures instead of flattening them into large binaries. This change reduces memory usage and fragmentation, especially on memory-constrained devices like the ESP32, and introduces strict bounds on both chunk size and the number of iodata entries per chunk. The implementation is thoroughly tested to ensure correctness and robustness.

Incremental iodata chunking and bounded memory usage:

  • src/tcp_server.erl: Replaces the previous approach of flattening complete responses with incremental traversal of nested iodata, bounding both the byte size and entry count per chunk using the new next_chunk/2 function and MAX_CHUNK_ENTRIES constant. This ensures that temporary allocations remain small regardless of total response size. Partial sends now retry only the unsent portion of the current chunk, never concatenating with the rest of the response. [1] [2]
  • AGENTS.md, README.md: Updated documentation to explain the new chunking behavior, emphasizing that responses are never fully flattened and that partial sends are retried in a memory-efficient manner. [1] [2] [3]

Testing and developer support:

  • src/tcp_server.erl: Exports next_chunk/2 for testing when compiled with TEST defined, facilitating direct verification of chunking logic.
  • test/tcp_server_test.exs: Adds comprehensive tests for the new chunking logic, including preservation of nested iodata, enforcement of entry limits, and error handling for invalid input.

Constants and configuration:

  • src/tcp_server.erl: Introduces and documents the MAX_CHUNK_ENTRIES constant to prevent excessive cons cell allocations from highly fragmented iodata.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves TCP response sending in tcp_server by streaming nested iodata incrementally in bounded chunks (byte-size + entry-count limits), avoiding response-sized flattening and reducing peak memory usage/fragmentation on constrained targets (e.g., ESP32).

Changes:

  • Replace full-response flattening with incremental iodata traversal (next_chunk/2) and bounded chunk extraction in src/tcp_server.erl.
  • Add ExUnit coverage for correctness of chunk boundaries, deep nesting, entry-count bounds, and invalid input handling.
  • Update README and agent guidance to describe the new bounded chunking and partial-send retry behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/tcp_server.erl Implements bounded incremental iodata chunking and adjusts partial-send retry to only resend the unsent part of the current chunk.
test/tcp_server_test.exs Adds tests validating chunking behavior, bounds, and error handling for invalid inputs.
README.md Documents the incremental iodata chunking behavior and partial-send retry semantics.
AGENTS.md Updates contributor guidance to reinforce “never flatten full responses” and describe bounded chunk traversal.

Comment thread src/tcp_server.erl Outdated
Comment on lines +416 to +420
case Rest of
[] -> ok;
_ -> receive after 0 -> ok end
end,
do_send_iodata(Socket, Rest, ChunkSize);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fixed in the latest commit — the recursive do_send_iodata/3 call is now inside the _ -> branch so it's only reached when Rest is non-empty.

Comment thread README.md Outdated
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