Fix flaky 04408_array_fold_cancellation under sanitizers#110942
Fix flaky 04408_array_fold_cancellation under sanitizers#110942groeneai wants to merge 2 commits into
Conversation
The const-throw case of the test flaked (~0.16% on Stateless amd_tsan parallel, 0 on master). arrayFold folds a block in one executeImpl(); the in-function time check fires at each fold slice, but the setup before it (selector build + scatter) is uninterruptible for this input, and the const array replicated across the four rows makes that setup (~0.88s) rival max_execution_time=1s. When the outer `timeout` wrapper kills the client before the in-function check is reached, the grep finds no TIMEOUT_EXCEEDED and the line prints "const throw: no timeout". Shorten the folded array from range(120000) to range(60000): setup drops to ~0.51s so the query reaches the interruptible fold quickly, while the O(N^2) arrayPushFront fold still runs ~7.6s (far above the 1s limit). Peak memory drops to <20 MiB. The four-row shape, the const-vs-runtime distinction, and the reference output are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Internal second-model review (click to expand)An independent second model reviewed this diff before the PR was opened. Findings and dispositions: Nits / other
No blockers or majors affecting the change itself. |
Pre-PR validation gate (click to expand)
Session id: cron:clickhouse-author-slot-2:20260718-134700 |
|
cc @Ergus - could you review this? It de-flakes 04408_array_fold_cancellation by shortening the folded array (range(120000) -> range(60000)) so arrayFold reaches its interruptible fold loop before the uninterruptible setup can rival max_execution_time; test-only, reference output unchanged. |
|
Workflow [PR], commit [f5f128a] Summary: ❌
AI ReviewSummaryThis PR de-flakes Final VerdictStatus: ✅ Approve |
The break-mode cases only asserted the client exit code under an outer timeout 30. The uncancelled fold at range(60000) finishes in ~7.6s, well under 30s, so a build that regressed to ignoring checkTimeLimit in break mode would still exit 0 and print the same "stopped without error" line (reported by the automated review). Assert the number of result rows instead: a cancelled break-mode fold emits no rows, a completed one emits all four. This restores break-mode coverage without lengthening the workload, so the sanitizer-timing fix (range(60000)) is preserved and the reference output is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI finish ledger — f5f128aCI fully finished (Finish Workflow + Config Workflow pass). Every failure has an owner.
This PR's diff is test-only (04408_array_fold_cancellation.sh de-flake); it cannot cause an RWLock exclusive-lock error in the stress test. nikitamikhaylov approved. |
Related: #110887
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
...
Description
Fix flakiness of
04408_array_fold_cancellation(surfaced on theStateless tests (amd_tsan, parallel)check).CIDB, last 30 days: 60 FAIL vs 36,777 OK (~0.16%), across 15 unrelated PRs, 0 on master. The CI job's own same-settings rerun passes (6/6), so it is a timing flake, not a settings flake. The failing diff is always the same single line, the
const throwcase:Root cause.
arrayFoldfolds a whole block inside oneexecuteImpl(); the in-functioncheckQueryTimeLimit()runs at the top of each fold slice and fires on the first slice where elapsed wall-clock exceedsmax_execution_time. But the setup phase before that first check (selector build over all elements plusscatterinto per-element vertical slices) is uninterruptible for this input: the selector loop only checks the time every0xFFFFFelements, andrange(120000)overnumbers(4)is 480000 elements, so the check never fires during setup. Measured setup-only time on a debug build:range(120000)const path ~0.88s versus the runtime path ~0.36s. The const array is replicated across the four rows, so its setup is ~2.4x heavier and sits right against the 1smax_execution_time. The test asserts by latency wrapped intimeout 30and greps stdout forTIMEOUT_EXCEEDED; if the outertimeoutkills the client before the in-function check is reached, the grep is empty and the line printsconst throw: no timeout. Under the sanitizer's slowdown plus parallel contention, the const path's already-heavier setup is the one that crosses that boundary, which is why only that line flakes.Fix. Shorten the folded array from
range(120000)torange(60000)(still overnumbers(4)). This cuts the uninterruptible setup roughly in half (~0.88s -> ~0.51s) so the query reaches the interruptible fold quickly, while the O(N^2)arrayPushFrontfold still runs ~7.6s, far longer than the 1s limit, so the in-function check keeps firing with a large margin. Peak memory drops (~40 MiB -> <20 MiB), keeping the test comfortably parallel-safe. The four-row shape and the runtime-vs-const distinction are preserved, and the reference output is unchanged.Validation (debug build): 50/50 runs of the full test match the reference; all four assertion lines behave as before.