Uh oh!
There was an error while loading. Please reload this page.
[opt](cloud) Enable compaction on new tablets during schema change queuing - #61089
Conversation
c160456 to
3f1b5b1CompareYukang-Lian
commented
Mar 10, 2026
run buildall |
doris-robot
commented
Mar 10, 2026
TPC-H: Total hot run time: 27666 ms |
doris-robot
commented
Mar 10, 2026
TPC-DS: Total hot run time: 153061 ms |
Yukang-Lian
commented
Mar 11, 2026
run p0 |
Yukang-Lian
commented
Mar 11, 2026
run beut |
doris-robot
commented
Mar 11, 2026
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
hello-stephen
commented
Mar 11, 2026
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
hello-stephen
commented
Mar 11, 2026
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
Yukang-Lian
commented
Mar 19, 2026
run buildall |
doris-robot
commented
Mar 19, 2026
TPC-H: Total hot run time: 26962 ms |
doris-robot
commented
Mar 19, 2026
TPC-DS: Total hot run time: 168330 ms |
hello-stephen
commented
Mar 19, 2026
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
hello-stephen
commented
Mar 19, 2026
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
PR approved by at least one committer and no changes requested. |
PR approved by anyone and no changes requested. |
Yukang-Lian
commented
Mar 23, 2026
run external |
hello-stephen
commented
Mar 23, 2026
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
Uh oh!
There was an error while loading. Please reload this page.
…euing (#61089) ## Summary In cloud mode, schema change (SC) tasks for multi-tablet tables are submitted to a thread pool with limited workers. Tablets waiting in the queue cannot do compaction because their `alter_version` is unset (-1), which causes rowset accumulation during long queue waits. This PR: 1. **Sets `alter_version = V0` before enqueue** via `pre_submit_callback` on `TaskWorkerPool`, allowing compaction on new tablets for versions > V0 during the queue wait period. 2. **Fixes a cross-V1 compaction race condition**: During the queue wait, compaction may commit a rowset that crosses the eventual V1 boundary (determined later by `prepare_tablet_job`). After SC commit, this creates version overlap and causes BE crash (`Check failed: versions are not continuity`). The fix adds a cross-V1 check in `process_alter_tablet` after `prepare_tablet_job` returns V1: sync new tablet and reject if any rowset crosses V1, letting FE retry with a higher V1. ## Changes **BE only — no FE or meta-service changes.** ### Core logic - `task_worker_pool.h/cpp`: Add optional `pre_submit_callback` to `TaskWorkerPool`, called synchronously before task enqueue. - `agent_server.cpp`: Pass `set_alter_version_before_enqueue` as `pre_submit_callback` for ALTER workers. - `task_worker_pool.cpp`: Implement `set_alter_version_before_enqueue` (sets alter_version=V0 on both tablets) and cleanup logic in `alter_cloud_tablet_callback` (resets alter_version=-1 before `remove_task_info` to avoid race with re-submission). - `cloud_schema_change_job.cpp`: Add cross-V1 compaction check after `prepare_tablet_job` — sync new tablet and verify no rowset crosses V1 boundary. If detected, return error for FE retry (next retry V1 will be higher, cross-boundary rowset falls within [2, V1']). ### Key Design Points - **V0** (partition visible version from FE) is set at pre-submit time to enable compaction during queue wait. - **V1** (base_max_version) is still determined at SC execution time for rowset conversion alignment — unchanged behavior. - SC commit atomically replaces rowsets [2, V1] on the new tablet, so any compaction results in (V0, V1] during queue time are harmlessly discarded. - Cleanup order: `alter_version` is reset to -1 before `remove_task_info` to prevent race with same-signature re-submission. ### Cross-V1 race condition analysis The dangerous timing window is: compaction commits to meta-service BEFORE `prepare_tablet_job` registers the SC job. At that point, no `JOB_CHECK_ALTER_VERSION` protection exists, so compaction succeeds. When SC later commits with a lower V1, meta-service cannot delete the cross-V1 rowset, creating version overlap. After `prepare_tablet_job`, two existing mechanisms protect: - `clear_compaction`: `prepare_tablet_job` clears all compaction jobs on new tablet, so in-flight compaction commits are rejected. - `JOB_CHECK_ALTER_VERSION`: new compaction starts are rejected if input versions cross V1. The fix covers the only unprotected window by checking for cross-V1 rowsets right after `prepare_tablet_job` returns. ### Tests - `task_worker_pool_test.cpp`: UT for `pre_submit_callback` mechanism and task dedup behavior. - `test_sc_compaction_optimization.groovy`: Verify compaction runs on new tablets during SC queue wait (merged rowset version range proves compaction happened). - `test_sc_compaction_optimization_with_load.groovy`: End-to-end with concurrent writes, data consistency after SC + compaction. - `test_sc_compaction_cross_v1_race.groovy`: Reproduce cross-V1 race using `override_base_max_version` debug point. Without fix: BE crash. With fix: SC detects cross-V1 and returns retryable error, BE stays alive.
…euing (#61089) ## Summary In cloud mode, schema change (SC) tasks for multi-tablet tables are submitted to a thread pool with limited workers. Tablets waiting in the queue cannot do compaction because their `alter_version` is unset (-1), which causes rowset accumulation during long queue waits. This PR: 1. **Sets `alter_version = V0` before enqueue** via `pre_submit_callback` on `TaskWorkerPool`, allowing compaction on new tablets for versions > V0 during the queue wait period. 2. **Fixes a cross-V1 compaction race condition**: During the queue wait, compaction may commit a rowset that crosses the eventual V1 boundary (determined later by `prepare_tablet_job`). After SC commit, this creates version overlap and causes BE crash (`Check failed: versions are not continuity`). The fix adds a cross-V1 check in `process_alter_tablet` after `prepare_tablet_job` returns V1: sync new tablet and reject if any rowset crosses V1, letting FE retry with a higher V1. ## Changes **BE only — no FE or meta-service changes.** ### Core logic - `task_worker_pool.h/cpp`: Add optional `pre_submit_callback` to `TaskWorkerPool`, called synchronously before task enqueue. - `agent_server.cpp`: Pass `set_alter_version_before_enqueue` as `pre_submit_callback` for ALTER workers. - `task_worker_pool.cpp`: Implement `set_alter_version_before_enqueue` (sets alter_version=V0 on both tablets) and cleanup logic in `alter_cloud_tablet_callback` (resets alter_version=-1 before `remove_task_info` to avoid race with re-submission). - `cloud_schema_change_job.cpp`: Add cross-V1 compaction check after `prepare_tablet_job` — sync new tablet and verify no rowset crosses V1 boundary. If detected, return error for FE retry (next retry V1 will be higher, cross-boundary rowset falls within [2, V1']). ### Key Design Points - **V0** (partition visible version from FE) is set at pre-submit time to enable compaction during queue wait. - **V1** (base_max_version) is still determined at SC execution time for rowset conversion alignment — unchanged behavior. - SC commit atomically replaces rowsets [2, V1] on the new tablet, so any compaction results in (V0, V1] during queue time are harmlessly discarded. - Cleanup order: `alter_version` is reset to -1 before `remove_task_info` to prevent race with same-signature re-submission. ### Cross-V1 race condition analysis The dangerous timing window is: compaction commits to meta-service BEFORE `prepare_tablet_job` registers the SC job. At that point, no `JOB_CHECK_ALTER_VERSION` protection exists, so compaction succeeds. When SC later commits with a lower V1, meta-service cannot delete the cross-V1 rowset, creating version overlap. After `prepare_tablet_job`, two existing mechanisms protect: - `clear_compaction`: `prepare_tablet_job` clears all compaction jobs on new tablet, so in-flight compaction commits are rejected. - `JOB_CHECK_ALTER_VERSION`: new compaction starts are rejected if input versions cross V1. The fix covers the only unprotected window by checking for cross-V1 rowsets right after `prepare_tablet_job` returns. ### Tests - `task_worker_pool_test.cpp`: UT for `pre_submit_callback` mechanism and task dedup behavior. - `test_sc_compaction_optimization.groovy`: Verify compaction runs on new tablets during SC queue wait (merged rowset version range proves compaction happened). - `test_sc_compaction_optimization_with_load.groovy`: End-to-end with concurrent writes, data consistency after SC + compaction. - `test_sc_compaction_cross_v1_race.groovy`: Reproduce cross-V1 race using `override_base_max_version` debug point. Without fix: BE crash. With fix: SC detects cross-V1 and returns retryable error, BE stays alive.
…euing (apache#61089) ## Summary In cloud mode, schema change (SC) tasks for multi-tablet tables are submitted to a thread pool with limited workers. Tablets waiting in the queue cannot do compaction because their `alter_version` is unset (-1), which causes rowset accumulation during long queue waits. This PR: 1. **Sets `alter_version = V0` before enqueue** via `pre_submit_callback` on `TaskWorkerPool`, allowing compaction on new tablets for versions > V0 during the queue wait period. 2. **Fixes a cross-V1 compaction race condition**: During the queue wait, compaction may commit a rowset that crosses the eventual V1 boundary (determined later by `prepare_tablet_job`). After SC commit, this creates version overlap and causes BE crash (`Check failed: versions are not continuity`). The fix adds a cross-V1 check in `process_alter_tablet` after `prepare_tablet_job` returns V1: sync new tablet and reject if any rowset crosses V1, letting FE retry with a higher V1. ## Changes **BE only — no FE or meta-service changes.** ### Core logic - `task_worker_pool.h/cpp`: Add optional `pre_submit_callback` to `TaskWorkerPool`, called synchronously before task enqueue. - `agent_server.cpp`: Pass `set_alter_version_before_enqueue` as `pre_submit_callback` for ALTER workers. - `task_worker_pool.cpp`: Implement `set_alter_version_before_enqueue` (sets alter_version=V0 on both tablets) and cleanup logic in `alter_cloud_tablet_callback` (resets alter_version=-1 before `remove_task_info` to avoid race with re-submission). - `cloud_schema_change_job.cpp`: Add cross-V1 compaction check after `prepare_tablet_job` — sync new tablet and verify no rowset crosses V1 boundary. If detected, return error for FE retry (next retry V1 will be higher, cross-boundary rowset falls within [2, V1']). ### Key Design Points - **V0** (partition visible version from FE) is set at pre-submit time to enable compaction during queue wait. - **V1** (base_max_version) is still determined at SC execution time for rowset conversion alignment — unchanged behavior. - SC commit atomically replaces rowsets [2, V1] on the new tablet, so any compaction results in (V0, V1] during queue time are harmlessly discarded. - Cleanup order: `alter_version` is reset to -1 before `remove_task_info` to prevent race with same-signature re-submission. ### Cross-V1 race condition analysis The dangerous timing window is: compaction commits to meta-service BEFORE `prepare_tablet_job` registers the SC job. At that point, no `JOB_CHECK_ALTER_VERSION` protection exists, so compaction succeeds. When SC later commits with a lower V1, meta-service cannot delete the cross-V1 rowset, creating version overlap. After `prepare_tablet_job`, two existing mechanisms protect: - `clear_compaction`: `prepare_tablet_job` clears all compaction jobs on new tablet, so in-flight compaction commits are rejected. - `JOB_CHECK_ALTER_VERSION`: new compaction starts are rejected if input versions cross V1. The fix covers the only unprotected window by checking for cross-V1 rowsets right after `prepare_tablet_job` returns. ### Tests - `task_worker_pool_test.cpp`: UT for `pre_submit_callback` mechanism and task dedup behavior. - `test_sc_compaction_optimization.groovy`: Verify compaction runs on new tablets during SC queue wait (merged rowset version range proves compaction happened). - `test_sc_compaction_optimization_with_load.groovy`: End-to-end with concurrent writes, data consistency after SC + compaction. - `test_sc_compaction_cross_v1_race.groovy`: Reproduce cross-V1 race using `override_base_max_version` debug point. Without fix: BE crash. With fix: SC detects cross-V1 and returns retryable error, BE stays alive.
…change (#62256) ### What problem does this PR solve? Problem Summary: During cloud schema change, the MS (Meta Service) side correctly recycles rowsets in `[2, alter_version]` on the new tablet when committing the SC job. However, the BE side did not mirror this behavior — it directly called `add_rowsets` for the SC output without first removing existing local rowsets. This could leave stale rowsets (e.g., compaction outputs on the new tablet) visible in `_rs_version_map`, and since their delete bitmap does not cover the SC output rows, duplicate keys may appear in MOW tables. PR #61089 increased the likelihood of triggering this issue by enabling compaction on new tablets during SC, which makes it more common for the new tablet to have compaction rowsets with wider version ranges (e.g., `[818-822]`) that overlap with individual SC output rowsets (e.g., `[818],[819],...,[822]`). The `add_rowsets` overlap check (`to_add_v.contains(v)`) is one-directional: `[818].contains([818-822])` evaluates to false, so the stale compaction rowset was not removed. Fix: Before calling `add_rowsets` for SC output, delete all local rowsets in `[2, alter_version]` from the new tablet, mirroring the MS-side recycle behavior. A new `CloudTablet::delete_rowsets_for_schema_change` method is added that also removes edges from the version graph, preventing the greedy capture algorithm from preferring the wider stale compaction path over the individual SC output rowsets.
…change (#62256) ### What problem does this PR solve? Problem Summary: During cloud schema change, the MS (Meta Service) side correctly recycles rowsets in `[2, alter_version]` on the new tablet when committing the SC job. However, the BE side did not mirror this behavior — it directly called `add_rowsets` for the SC output without first removing existing local rowsets. This could leave stale rowsets (e.g., compaction outputs on the new tablet) visible in `_rs_version_map`, and since their delete bitmap does not cover the SC output rows, duplicate keys may appear in MOW tables. PR #61089 increased the likelihood of triggering this issue by enabling compaction on new tablets during SC, which makes it more common for the new tablet to have compaction rowsets with wider version ranges (e.g., `[818-822]`) that overlap with individual SC output rowsets (e.g., `[818],[819],...,[822]`). The `add_rowsets` overlap check (`to_add_v.contains(v)`) is one-directional: `[818].contains([818-822])` evaluates to false, so the stale compaction rowset was not removed. Fix: Before calling `add_rowsets` for SC output, delete all local rowsets in `[2, alter_version]` from the new tablet, mirroring the MS-side recycle behavior. A new `CloudTablet::delete_rowsets_for_schema_change` method is added that also removes edges from the version graph, preventing the greedy capture algorithm from preferring the wider stale compaction path over the individual SC output rowsets.
…change (#62256) ### What problem does this PR solve? Problem Summary: During cloud schema change, the MS (Meta Service) side correctly recycles rowsets in `[2, alter_version]` on the new tablet when committing the SC job. However, the BE side did not mirror this behavior — it directly called `add_rowsets` for the SC output without first removing existing local rowsets. This could leave stale rowsets (e.g., compaction outputs on the new tablet) visible in `_rs_version_map`, and since their delete bitmap does not cover the SC output rows, duplicate keys may appear in MOW tables. PR #61089 increased the likelihood of triggering this issue by enabling compaction on new tablets during SC, which makes it more common for the new tablet to have compaction rowsets with wider version ranges (e.g., `[818-822]`) that overlap with individual SC output rowsets (e.g., `[818],[819],...,[822]`). The `add_rowsets` overlap check (`to_add_v.contains(v)`) is one-directional: `[818].contains([818-822])` evaluates to false, so the stale compaction rowset was not removed. Fix: Before calling `add_rowsets` for SC output, delete all local rowsets in `[2, alter_version]` from the new tablet, mirroring the MS-side recycle behavior. A new `CloudTablet::delete_rowsets_for_schema_change` method is added that also removes edges from the version graph, preventing the greedy capture algorithm from preferring the wider stale compaction path over the individual SC output rowsets.
…change (#62256) ### What problem does this PR solve? Problem Summary: During cloud schema change, the MS (Meta Service) side correctly recycles rowsets in `[2, alter_version]` on the new tablet when committing the SC job. However, the BE side did not mirror this behavior — it directly called `add_rowsets` for the SC output without first removing existing local rowsets. This could leave stale rowsets (e.g., compaction outputs on the new tablet) visible in `_rs_version_map`, and since their delete bitmap does not cover the SC output rows, duplicate keys may appear in MOW tables. PR #61089 increased the likelihood of triggering this issue by enabling compaction on new tablets during SC, which makes it more common for the new tablet to have compaction rowsets with wider version ranges (e.g., `[818-822]`) that overlap with individual SC output rowsets (e.g., `[818],[819],...,[822]`). The `add_rowsets` overlap check (`to_add_v.contains(v)`) is one-directional: `[818].contains([818-822])` evaluates to false, so the stale compaction rowset was not removed. Fix: Before calling `add_rowsets` for SC output, delete all local rowsets in `[2, alter_version]` from the new tablet, mirroring the MS-side recycle behavior. A new `CloudTablet::delete_rowsets_for_schema_change` method is added that also removes edges from the version graph, preventing the greedy capture algorithm from preferring the wider stale compaction path over the individual SC output rowsets.
What problem does this PR solve?
Issue Number: close #xxx
Related PR: #xxx
Problem Summary:
Summary
In cloud mode, schema change (SC) tasks for multi-tablet tables are submitted to a thread pool with limited workers. Tablets waiting in the queue cannot do compaction because their
alter_versionis unset (-1), which causes rowset accumulation during long queue waits.This PR:
Sets
alter_version = V0before enqueue viapre_submit_callbackonTaskWorkerPool, allowing compaction on new tablets for versions > V0 during the queue wait period.Fixes a cross-V1 compaction race condition: During the queue wait, compaction may commit a rowset that crosses the eventual V1 boundary (determined later by
prepare_tablet_job). After SC commit, this creates version overlap and causes BE crash (Check failed: versions are not continuity). The fix adds a cross-V1 check inprocess_alter_tabletafterprepare_tablet_jobreturns V1: sync new tablet and reject if any rowset crosses V1, letting FE retry with a higher V1.Changes
BE only — no FE or meta-service changes.
Core logic
task_worker_pool.h/cpp: Add optionalpre_submit_callbacktoTaskWorkerPool, called synchronously before task enqueue.agent_server.cpp: Passset_alter_version_before_enqueueaspre_submit_callbackfor ALTER workers.task_worker_pool.cpp: Implementset_alter_version_before_enqueue(sets alter_version=V0 on both tablets) and cleanup logic inalter_cloud_tablet_callback(resets alter_version=-1 beforeremove_task_infoto avoid race with re-submission).cloud_schema_change_job.cpp: Add cross-V1 compaction check afterprepare_tablet_job— sync new tablet and verify no rowset crosses V1 boundary. If detected, return error for FE retry (next retry V1 will be higher, cross-boundary rowset falls within [2, V1']).Key Design Points
alter_versionis reset to -1 beforeremove_task_infoto prevent race with same-signature re-submission.Cross-V1 race condition analysis
The dangerous timing window is: compaction commits to meta-service BEFORE
prepare_tablet_jobregisters the SC job. At that point, noJOB_CHECK_ALTER_VERSIONprotection exists, so compaction succeeds. When SC later commits with a lower V1, meta-service cannot delete the cross-V1 rowset, creating version overlap.After
prepare_tablet_job, two existing mechanisms protect:clear_compaction:prepare_tablet_jobclears all compaction jobs on new tablet, so in-flight compaction commits are rejected.JOB_CHECK_ALTER_VERSION: new compaction starts are rejected if input versions cross V1.The fix covers the only unprotected window by checking for cross-V1 rowsets right after
prepare_tablet_jobreturns.Tests
task_worker_pool_test.cpp: UT forpre_submit_callbackmechanism and task dedup behavior.test_sc_compaction_optimization.groovy: Verify compaction runs on new tablets during SC queue wait (merged rowset version range proves compaction happened).test_sc_compaction_optimization_with_load.groovy: End-to-end with concurrent writes, data consistency after SC + compaction.test_sc_compaction_cross_v1_race.groovy: Reproduce cross-V1 race usingoverride_base_max_versiondebug point. Without fix: BE crash. With fix: SC detects cross-V1 and returns retryable error, BE stays alive.Release note
None
Check List (For Author)
Test
Behavior changed:
Does this need documentation?
Check List (For Reviewer who merge this PR)