Skip to content

[pull] main from facebook:main#551

Merged
pull[bot] merged 1 commit into
code:mainfrom
facebook:main
May 28, 2026
Merged

[pull] main from facebook:main#551
pull[bot] merged 1 commit into
code:mainfrom
facebook:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 28, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

)

The Flight Server emits Text and TypedArray rows as two chunks: a header
that gives the row's id, type, and content length, followed by the
content itself. These two chunks were pushed into
`completedRegularChunks` (and `completedDebugChunks` in DEV) as separate
items, so when the destination signaled backpressure between them, the
flush would write the header and then break out before reaching the
content. The content chunk was left stranded at the head of the queue.
Async work running while the destination was paused appended new rows to
`completedImportChunks` / `completedHintChunks`, and the next drain
flushed those queues first — splicing the newly-arrived bytes into the
position the Flight Client expects to read as the original row's
content. From there the Flight Client read rows from the wrong byte
offsets and the model failed to deserialize.

This only surfaced on the Node stream path.
`createFakeWritableFromReadableStreamController`, used by
`renderToReadableStream`, always returns `true` from `write()`, so the
flush loop never saw backpressure.

The fix pushes a `NEXT_TWO_CHUNKS_ARE_ATOMIC` sentinel ahead of each
`headerChunk` / `contentChunk` pair in `completedRegularChunks` and
`completedDebugChunks`. The flush loops detect the sentinel and write
the two chunks that follow it together before re-checking backpressure,
so backpressure can still break between rows but never within one.

### Alternatives considered

- **Pushing the pair as a `[headerChunk, contentChunk]` tuple.** Simpler
but allocates an array per row. The required `isArray` branch in the
flush hot path is likely comparable with the symbol check. This also
violates the opaque `Chunk` type boundary.
- **Concatenating header and content into one chunk.** Bad for memory —
typed-array content can be large.
- **Storing atomic groups in a separate queue.** Conceptually wrong and
risks breaking reference-ordering assumptions between rows.
- **Ignoring backpressure until the regulars queue is empty.** Defeats
the point of backpressure.
- **Wrapping the tuple behind a host-config API** (`writeAdjacentChunks`
/ `isAdjacentChunks` / `chunksToAdjacentChunks` /
`getAdjacentChunksLength`). Keeps the implementation opaque but adds
four exports per host config. Also has the tuple overhead.
- **Begin/end sentinels for variable-length atomic groups.** Not needed
— only Text and TypedArray rows use this pattern, and both are pairs.
@pull pull Bot locked and limited conversation to collaborators May 28, 2026
@pull pull Bot added the ⤵️ pull label May 28, 2026
@pull pull Bot merged commit c014813 into code:main May 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant