Repository navigation
Description
vortex view <https url> freezes while it fetches data: the screen stops redrawing, keys (even q) do nothing, and the queued keys replay at once when the fetch ends. Locally it is barely visible; over HTTP (e.g. the Hugging Face samples, ~200 ms per range request) a chunk takes seconds.
Cause
The render loop waits on the I/O thread. IoWorker exists so the render loop never does I/O, but every frame reads its window synchronously:
VortexGridTui.Loop.render() → fetchWindow → LazyGridSource.readRows → worker.runAndAwait(...) (cli/src/main/java/io/github/dfa1/vortex/cli/tui/VortexGridTui.java:192, LazyGridSource.java:145)
So the main thread blocks until the worker has loaded and formatted the chunk. IoWorker.pending(), meant for a status-line "loading" counter, is never seen non-zero by a frame.
Over HTTP LazyGridSource.loadChunk (LazyGridSource.java:216) makes each wait long:
- it decodes every column of the chunk (
chunk.column(...)for all of them), one range request each, sequentially, though only the on-screen columns are drawn; - moving forward several chunks walks each one in between with
iter.next(); - moving back even one chunk closes the scan and walks again from chunk 0.
Proposal
- Never block the render loop.
render()requests the window without waiting and draws what is cached, with…cells and a "loading" status for the rest; the loop keeps reading keys (qquits at once) and redraws when the worker completes. A request the user has already scrolled past is dropped, not queued. - Fetch only the visible columns, concurrently. Scan with a projection of the on-screen columns (plus a small margin), with a bounded number of range requests in flight.
- Jump straight to a chunk. A row-range scan for the target chunk, instead of walking from the current position or restarting from chunk 0.
(1) fixes the freeze on its own; (2) and (3) make it fast. (2) shares the concurrent-range work with #743.
To check before (3): whether skipping a chunk with iter.next() fetches anything over HTTP or only advances the iterator (a JFR recording, io.github.dfa1.vortex.HttpRange events, while pressing End).
Reproduce
U=$(curl -s -o /dev/null -w '%{redirect_url}' https://huggingface.co/datasets/dfa11/vortex-java-samples/resolve/main/0.19.1/openpowerlifting/openpowerlifting.compact.vortex)
java -XX:StartFlightRecording:filename=view.jfr -jar cli/target/vortex-cli-*-all.jar view "$U"
Scroll with PageDown, press End, then q while it loads.
Activity
view: decode only the visible columns
Fetch the visible columns of a chunk concurrently over HTTP
Merge neighboring segments into one range request when prefetching
Keep every segment an HTTP handle has read, so scrolling back is free
view: stay responsive and fast over HTTP
view: stay responsive and fast over HTTP
Pin that skipping a chunk over HTTP fetches nothing
view: stay responsive and fast over HTTP
Pin that skipping a chunk over HTTP fetches nothing
dfa1 commentedon Nov 13, 2026
Done in #747: the render loop no longer blocks on I/O, only the visible columns are fetched (concurrently, merged requests). Item 3 (jump straight to a chunk) is not needed: skipping a chunk costs no requests, and a manual test over HTTP is fine.