Fix hang in SYSTEM SYNC MERGES with the Manual merge selector#108770
Conversation
`ManualMergeSelector::select` removed a scheduled merge from its queue as a side effect of selection, but selecting a merge does not guarantee it runs. When the background pool queue is full, `BackgroundJobsAssignee::scheduleMergeMutateTask` (`trySchedule`) returns false and the selected merge task is dropped - but the queue entry was already gone. The dependent chain of merges then stalls and `SYSTEM SYNC MERGES` waits forever (until the test's 600s timeout), which made `04207_schedule_merge_basic` flaky under parallel TSan/debug/ARM runs. Make `select` self-healing: it no longer removes an entry on selection. A queue entry is dropped only once its merge result is observed among the available parts. Parts of an in-flight merge are excluded from `parts_ranges` (the parts collector drops parts that cannot be used in merges), so a running merge is never re-selected, while a merge that did not happen has its source parts back in `parts_ranges` and is selected again on the next call. This also removes the queue corruption caused by the replicated `getPartitionsThatMayBeMerged` path, which calls `select` only to build a hint and discards the result. Add a deterministic regression test backed by a new `ONCE` failpoint `mt_skip_scheduling_merge_once` (applied only to the `Manual` selector) that drops a manually scheduled merge once, simulating a full pool. CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=543037669696523bda6c85927bbcf5bb4c6b0fbf&name_0=MasterCI&name_1=Stateless%20tests%20%28amd_tsan%2C%20parallel%2C%202%2F2%29 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Workflow [PR], commit [89322b1] Summary: ✅
AI ReviewSummaryThis PR fixes one lost-manual-merge hang path by keeping scheduled entries in PR Metadata
Findings
Final VerdictStatus: Minimum required actions:
|
…ansform_cume_dist_peer_groups on master The PR added `04414_schedule_merge_retry_on_busy_pool`, but master has since gained `04414_window_transform_cume_dist_peer_groups` with the same numeric prefix. Renumber to `04492` (the next free number above the current maximum on master) so the two tests do not share a prefix once this change is merged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Merged the latest The regression test The only two red checks are The PR is |
|
Re-triaged CI for commit
The PR is I did not re-merge CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=108770&sha=latest&name_0=PR |
|
CI for I reran only those two failed jobs to try to clear I did not re-merge |
|
Re-triaged CI for
Both are non-deterministic fuzzer outcomes on the TSan Stress job, so I re-ran the failed jobs (attempt 6) to try for green. |
|
Re-triaged CI for
Both are non-deterministic TSan Stress outcomes, so I re-ran the two failed jobs (attempt 7) to try to clear |
|
Merged current The two red checks — That is exactly the hang fixed by The merge also picks up No unresolved review threads; |
| const auto front_info = MergeTreePartInfo::fromPartName(front.front(), MERGE_TREE_DATA_MIN_FORMAT_VERSION_WITH_CUSTOM_PARTITIONING); | ||
| const std::string containing = available_parts.getContainingPart(front_info); | ||
|
|
||
| if (!containing.empty() && containing != front_info.getPartNameV1()) |
There was a problem hiding this comment.
This still drops a scheduled merge as soon as the first source part is covered by any descendant part. ActiveDataPartSet::getContainingPart treats a mutation child as containing the original part, so after a failed trySchedule a mutation or TTL rewrite of only front.front() will hit this branch, pop_front() the manual queue entry, and leave the remaining source parts pending with no way to retry the merge. SYSTEM SYNC MERGES will then keep waiting for the uncovered siblings until max_execution_time.
Can we retire the queue entry only once all names in front resolve to the same covering active part/result instead of checking only front.front()?
|
Re-ran CI on the freshly re-merged head AI review (
|
Pull in #109254 (adds 04319_skip_unavailable_shards_mode_table_missing to ci/defs/darwin.skip), which resolves the sole remaining red on this PR: the Fast test (arm_darwin) failure of that test. The test is a darwin-only distributed-query flake unrelated to the merge-selector change; #109254 skips it on macOS. Net PR diff is unchanged (5 files, +89/-5).
|
Re-merged current Why now: the sole remaining red was This does not touch the open AI review thread on |
|
The fresh AI review on the re-merged head Confirmed. The non-replicated path passes a single merge constraint ( Design decision needed. The fix is a choice — e.g. skip an in-flight head and keep scanning later independent entries, or track "pending" and "running-but-not-yet-retired" entries separately. I did not push a queue-restructuring change here without deciding the intended behavior; this belongs to the same CI is still running on this head ( |
Resolve conflict in src/Storages/StorageMergeTree.cpp FailPoints namespace: keep both this branch's mt_skip_scheduling_merge_once and master's new mt_alter_throw_* mutation failpoint declarations (independent additions).
|
Merged current Net PR diff is unchanged — 5 files, +89/-5. The resolution does not touch |
Clean merge, no conflicts; net PR diff unchanged (5 files, +89/-5). Pulls in #108677, which fixes the 04402_map_functions_lowcardinality flake behind the sole red required check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merged current Why now: the sole real red on Merge verification: The two review threads on |
LLVM Coverage Report
Changed lines: Changed C/C++ lines covered: 39/40 (97.50%) · Uncovered code |
Fixes a hang in
SYSTEM SYNC MERGESthat made the stateless test04207_schedule_merge_basicflaky on master — it timed out at the 600s wrapper limit under parallel TSan/debug/ARM runs (the test always hit exactly 600000 ms, i.e. a permanent hang, not slowness).ManualMergeSelector::select(theManualmerge selector backingSYSTEM SCHEDULE MERGE/SYSTEM SYNC MERGES) removed a scheduled merge from its queue as a side effect of selection, but selecting a merge does not guarantee it runs. When the background merge pool queue is full,BackgroundJobsAssignee::scheduleMergeMutateTask(trySchedule) returnsfalseand the selected task is dropped — while the queue entry is already gone. The dependent chain of merges then stalls andSYSTEM SYNC MERGESwaits untilmax_execution_time(which defaults to unlimited).The selector is now self-healing: it removes a queue entry only once that merge's result is observed among the available parts. Parts of an in-flight merge are excluded from
parts_ranges(the parts collector drops parts that cannot be used in merges), so a running merge is never re-selected, while a merge that failed to be scheduled or to execute is selected again on the next call. This also removes the queue corruption from the replicatedgetPartitionsThatMayBeMergedpath, which callsselectonly to build a hint and discards the result.A deterministic regression test (
04492_schedule_merge_retry_on_busy_pool) uses a newONCEfailpointmt_skip_scheduling_merge_once(applied only to theManualselector) to drop a manually scheduled merge once, simulating a full pool, and checks that the merge still completes.Related: #104883
CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=543037669696523bda6c85927bbcf5bb4c6b0fbf&name_0=MasterCI&name_1=Stateless%20tests%20%28amd_tsan%2C%20parallel%2C%202%2F2%29
(#104883 reports the same
SYSTEM SYNC MERGEShang symptom but a different cause — scheduled parts that never exist or are dropped — which this PR does not address.)Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Fixed a hang in
SYSTEM SYNC MERGESwith theManualmerge selector when a scheduled merge could not be placed into a full background pool.🤖 Generated with Claude Code
Version info
26.7.1.808(included in26.7and later)