Skip to content

CI: lldb stack budget by build flavor, and keep the server alive after a timed-out lldb attach - #2385

Open
filimonov wants to merge 2 commits into
antalya-26.6from
fix/antalya-26.6/lldb-budget-and-sigcont
Open

filimonov wants to merge 2 commits into
antalya-26.6from
fix/antalya-26.6/lldb-budget-and-sigcont

Conversation

@filimonov

@filimonov filimonov commented Sep 16, 2026

Copy link
Copy Markdown
Member

Two changes to tests/clickhouse-test's lldb stack collection, each its own commit:

  1. lldb budget by build flavor (port of upstream 1fd4b6eea445, 7918dfd548d4, 5e152c370237, reduced to the timeout selection): 30 s per pid for release, 120 s for debug/sanitizer/coverage, read from args.build_flags or from the binary via clickhouse local when the server never started; print_c_stacktraces gets an aggregate deadline and names the pids it skips; the per-test timeout handler keeps the tight 30 s / 60 s pair. Not ported: the stacktrace log files and truncation marker, and the removal of the on-demand lldb install (the fork's images still need it).
  2. Interrupt a timed-out lldb instead of killing it, and keep its JIT breakpoint out of the server. Killing lldb on the budget is what froze an MSan CAS-S3 shard, but not through group-stop: on Linux the tracer is lldb-server, which exits on its own once the client is gone, the kernel restarts the threads, and nobody removes the breakpoints lldb planted. Its JIT loader puts one on __jit_debug_register_code, which the linker folds with other trivial functions in the clickhouse binary, so ordinary threads hit the stale int3, get SIGTRAP, and land in the fatal-signal handler; SignalListener and AsyncLogger are among them, so the 300 s wait for the stack dump never ends and the server stays in state S while ignoring SIGTERM and every client. Reproduced with a release binary and lldb 14 in the stateless-test image (nine threads in signalHandler(SIGTRAP) at that address); with the JIT loader disabled, or with lldb interrupted by SIGINT so it runs the queued detach, the server answers right afterwards. Now _lldb_command turns plugin.jit-loader.gdb.enable off and attaches with an explicit process attach; on the budget the collector sends SIGINT, gives lldb 15 s to abandon the backtrace, detach and quit (keeping the partial output), and only then kills it. An earlier revision of this PR ran lldb in its own process group and sent SIGCONT to the server; that never reached lldb-server and would not have helped, so it is gone. Intended to be proposed upstream as well.

Tests in ci/tests/test_print_stacktraces.py: six ported budget tests, plus the command order, SIGINT with the partial output kept, and SIGKILL after the grace period. The nine server-independent tests pass locally; the real command was exercised end to end against a live server in the stateless-test image with lldb 14 on the SIGINT, SIGINT-during-attach, SIGKILL-after-grace and SIGKILL-mid-backtrace paths, with the server healthy after each.

Related: #2298

Changelog category (leave one):

  • CI Fix or improvement

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

CI: the test runner gives lldb 120 s instead of 30 s to collect stacks from debug and sanitizer servers, and a timed-out lldb no longer leaves the server wedged: it is interrupted so it detaches, and its JIT breakpoint is kept out of the server.

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

CI/CD Options

Exclude tests:

  • Fast test
  • Integration Tests
  • Stateless tests
  • Stateful tests
  • Unit tests
  • Performance tests
  • Aarch64 tests
  • All with ASAN
  • All with TSAN
  • All with MSAN
  • All with UBSAN
  • All with Coverage
  • All Regression
  • Disable CI Cache

Regression jobs to run:

  • Fast suites (mostly <1h)
  • Aggregate Functions (2h)
  • Alter (1.5h)
  • Benchmark (30m)
  • CAS (content-addressed storage; Antalya only)
  • ClickHouse Keeper (1h)
  • Iceberg (2h)
  • LDAP (1h)
  • OAuth (5m)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

🤖 Generated with Claude Code

https://claude.ai/code/session_01GhVd7eMAWdFubNk4g1B2Tx

@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown

Workflow [PR], commit [3885c5c]

@k-morozov
k-morozov self-requested a review September 16, 2026 12:49
@filimonov filimonov added the CAS label Sep 17, 2026
filimonov and others added 2 commits September 17, 2026 17:47
Port of the budget selection from upstream (1fd4b6e, 7918dfd,
5e152c3), reduced to the part that chooses the per-PID timeout:

- `LLDB_TIMEOUT` (30 s) for release, `LLDB_SLOW_BUILD_TIMEOUT` (120 s) for
  debug, sanitizer and coverage servers, read from `args.build_flags`, or from
  the binary via `clickhouse local` (`is_slow_build_binary`) when the server
  never started and the flags were not collected.
- `print_c_stacktraces` takes `per_pid_timeout` and `total_timeout`, clamps
  each attach to what is left of the aggregate ceiling and names the pids it
  skipped. The per-test timeout handler, which runs inside a fired one-shot
  alarm, keeps the tight pair (30 s per pid, 60 s total); the abort paths take
  the flavor budget.

Not ported: the stacktrace log files, the truncation marker and
`keep_output_on_error` (a separate upstream change), and the removal of the
on-demand lldb install, which the fork's images still need.

Tests mirror upstream's, run without a server.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GhVd7eMAWdFubNk4g1B2Tx
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
… JIT breakpoint out of the server

`get_stacktraces_from_lldb` killed lldb on the budget and assumed the server
was untouched. It is not, though not for the reason first suspected. On Linux
the ptrace tracer is `lldb-server`, launched in its own session; it exits once
its client is gone, the kernel restarts the stopped threads by itself, and
neither lldb nor `lldb-server` removes the breakpoints lldb planted in the
inferior on the way out. The JIT loader plants one on
`__jit_debug_register_code` at attach; in the clickhouse binary the linker
folds that empty function with other trivial ones, so ordinary server threads
run through it. Each of them is delivered SIGTRAP, which the server treats as
fatal: the handler waits 300 s for a stack dump that is never written because
`SignalListener` and `AsyncLogger` are trapped as well, the rest of the server
piles up behind them, and the process shows state S while ignoring SIGTERM and
every client.

Reproduced with a release binary in the stateless-test image (lldb 14): lldb
killed 5 s into `thread backtrace all` leaves nine threads in
`signalHandler(SIGTRAP)` at that address and the server unresponsive; killed
with the JIT loader disabled, or interrupted with SIGINT so it runs the queued
`detach`, the server answers right afterwards. This is the MSan CAS-S3 shard
freeze (six attaches on the budget, then `system flush logs` and `clickhouse
stop` timing out); the watchdog's `stopped by signal 19` line is the attach
itself, not a lasting group-stop, and SIGCONT would not have helped.

- `_lldb_command` turns `plugin.jit-loader.gdb.enable` off and attaches with
  an explicit `process attach`, so a killed lldb leaves no breakpoint in
  server code. The dynamic-loader breakpoint in `ld.so` remains; it is only
  reached through `dlopen`.
- On the budget the collector sends SIGINT and gives lldb
  `LLDB_INTERRUPT_GRACE` (15 s) to abandon the backtrace, detach and quit,
  keeping the partial output. Only then is it killed.
- No process-group or SIGCONT handling.

Tests: the command order, SIGINT with the partial output kept, SIGKILL after
the grace period. The two live-server tests still exercise the real command.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
@filimonov
filimonov force-pushed the fix/antalya-26.6/lldb-budget-and-sigcont branch from d29211a to 3885c5c Compare September 17, 2026 16:10
@filimonov filimonov changed the title CI: lldb stack budget by build flavor, and resume the server after a timed-out attach CI: lldb stack budget by build flavor, and keep the server alive after a timed-out lldb attach Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant