Skip to content

fix: reduce CPU spikes and freeze risk after query execution#54

Merged
killertux merged 2 commits into
mainfrom
fix/query-freeze
May 25, 2026
Merged

fix: reduce CPU spikes and freeze risk after query execution#54
killertux merged 2 commits into
mainfrom
fix/query-freeze

Conversation

@killertux
Copy link
Copy Markdown
Owner

@killertux killertux commented May 25, 2026

Summary

Investigated reports of the TUI freezing with 100% CPU right after a query completes. lldb backtrace pinpointed the hang at kasuari::row::Row::insert_symbol — a known issue in the Cassowary solver ratatui 0.30 uses for Layout::split. See ratatui/kasuari#18: the simplex pivots cycle on degenerate ties when fed many identical Constraint::Min(_) constraints. Our result-table column widths were exactly that input.

Fixes

  • Bypass kasuari for result columns (src/ui/results_view.rs) — primary fix. Replace [Constraint::Min(8); n] with hand-computed Constraint::Length(w) widths that even-split the inner width. distribute_columns now does the same arithmetic directly instead of calling Layout::horizontal(...).split(...). Same output shape; existing layout tests still pass. The kasuari solver no longer runs on the per-frame result render.
  • Coalesce DDL-triggered schema reloads (src/app.rs, src/action/mod.rs) — added App::schema_reload_in_flight. Back-to-back DDLs no longer queue duplicate full-schema reintrospections; the flag clears on CacheStage::Reloaded and on Connected.
  • Per-frame cell rendering (src/datasource/cell.rs + callers) — Cell::display() now returns Cow<'_, str>. Text / Decimal / Other { repr } borrow their existing String instead of cloning per visible cell per frame. ratatui clips to column width at draw time, so we no longer allocate megabytes per redraw for wide JSON/TEXT values.
  • Autocomplete CTE parser (src/autocomplete/context.rs) — extract_projection_columns could re-enter its outer loop without i advancing if the inner scan hit an unbalanced inner ) at depth 0. Added a liveness guard so the worst case is a dropped projection, never a hang.

Bumps the patch version to 0.16.2.

Test plan

  • cargo check clean
  • cargo test --bin rowdy — 575 passed
  • Run a query that previously froze the UI and confirm it no longer hangs
  • Resize the terminal while a wide result is on screen (the kasuari issue thread flags resize as a common trigger)
  • Sanity-check mouse hit-testing on result columns — the X-position arithmetic changed
  • Sanity-check autocomplete inside a WITH cte AS (SELECT ... FROM t) body

killertux added 2 commits May 25, 2026 14:13
- autocomplete: add liveness guard in extract_projection_columns so a
  token slice with an unbalanced inner paren can't park `i` forever.
- datasource: Cell::display returns Cow<'_, str>; large Text/Decimal
  cells now borrow instead of cloning on every render frame.
- action: coalesce DDL-triggered schema reloads — back-to-back DDLs
  no longer queue redundant full reintrospections.

Bumps the patch version to 0.16.2.
The Table widget and `distribute_columns` were both feeding the
kasuari constraint solver `[Constraint::Min(8); n]` — identical
strengths and coefficients, which is the exact degenerate-pivot
input that triggers kasuari issue #18 (the solver loops forever in
the simplex pivot path). lldb on a frozen rowdy backtraced to
`kasuari::row::Row::insert_symbol`, confirming the hang.

Switch to hand-computed `Constraint::Length` widths — even split
of the inner width with the remainder spread across the leading
columns, matching the layout the solver had been producing. Same
math is reused for the hit-testing column-X table, so mouse
clicks still land on the right column.

Ref: ratatui/kasuari#18
@killertux killertux merged commit b0b9196 into main May 25, 2026
3 checks passed
@killertux killertux deleted the fix/query-freeze branch May 25, 2026 17:22
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