Skip to content

[fix](cloud) Only mark prepare rowsets before recycle - #65550

Open
wyxxxcat wants to merge 1 commit into
apache:masterfrom
wyxxxcat:mark_rowset_filter_prepared
Open

[fix](cloud) Only mark prepare rowsets before recycle#65550
wyxxxcat wants to merge 1 commit into
apache:masterfrom
wyxxxcat:mark_rowset_filter_prepared

Conversation

@wyxxxcat

@wyxxxcat wyxxxcat commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Cloud Recycler supports a mark-before-delete flow for rowset recycling. The mark
and abort preparation logic should only apply to PREPARE rowsets, because these
rowsets are deleted by rowset id prefix and may need related txn or job cleanup
before physical data deletion.

Test Coverage

Unit tests cover the following scenarios:

  • Only PREPARE rowsets are marked before recycling

    • Verifies that the mark-before-delete flow is applied only to PREPARE rowsets.
    • COMPACT and DROP rowsets are not unnecessarily marked.
  • PREPARE rowsets generated by load transactions

    • Verifies that the first recycle round only marks the rowset as recycled without deleting its data.
    • Verifies that the related transaction is aborted before physical rowset data is deleted.
    • Verifies that rowset metadata and delete bitmap metadata are cleaned up after a successful recycle.
  • PREPARE rowsets generated by compaction jobs

    • Verifies that the recycler aborts the exact compaction job associated with the rowset.
    • Covers multiple compaction jobs on the same tablet and ensures unrelated jobs are preserved.
    • Verifies that physical data deletion happens only after the target compaction job has been aborted.
  • PREPARE rowsets generated by schema change jobs

    • Verifies recycling of schema-change output rowsets on the new tablet.
    • Verifies that the corresponding schema-change job is aborted before deleting the rowset.
    • Verifies cleanup of the mirrored schema-change job records on both the base tablet and the new tablet.
  • Expired job handling

    • Verifies that the recycler can abort an expired compaction job when recycling its PREPARE rowset.
    • Verifies that expired schema-change jobs can also be aborted through rowsets belonging to the new tablet.
  • Compatibility paths

    • Covers PREPARE rowsets without an associated transaction/job.
    • Covers base-version rowsets ([0, 1]).
    • Covers rowsets whose associated transaction metadata no longer exists.
    • Ensures these compatibility cases can still be recycled without incorrectly aborting unrelated transactions.
  • Abort failure and retry

    • Injects transaction-abort failures and verifies that physical rowset data is not deleted.
    • Verifies that the marked recycle rowset is retained for retry.
    • Verifies that recycling succeeds after the underlying transaction metadata is repaired.
  • Object deletion failure and retry

    • Injects object-storage deletion failures.
    • Verifies that recycle metadata is retained when physical deletion fails.
    • Verifies that a subsequent recycle attempt can successfully finish the cleanup.
  • Commit vs. mark race

    • Covers the race where a commit removes the recycle rowset while the recycler is trying to mark it.
    • Verifies that the recycler does not proceed with stale abort/delete work when the commit wins the race.
    • Verifies that the rowset data is preserved in this case.
  • Batch boundary

    • Covers 257 PREPARE rowsets belonging to the same transaction, crossing the internal abort batch boundary.
    • Verifies that all physical deletions happen only after the related transaction has been aborted.
  • Concurrent tablet recycling

    • Covers the case where the tablet has already been recycled before the recycler tries to abort the job associated with a rowset.
    • Verifies that this case is treated as successful cleanup rather than an error.

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from be1d5e3 to ebdf1ff Compare July 14, 2026 03:06
@wyxxxcat
wyxxxcat requested a review from luwei16 as a code owner July 14, 2026 03:06
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch 3 times, most recently from 855b0a4 to 75e6ea1 Compare July 15, 2026 06:32
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 84.78% (39/46) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.42% (1896/2449)
Line Coverage 64.49% (34036/52778)
Region Coverage 64.92% (17529/26999)
Branch Coverage 54.09% (9396/17370)

@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch 2 times, most recently from 0bb7bd0 to 0611700 Compare July 21, 2026 02:31
@hello-stephen hello-stephen reopened this Jul 21, 2026
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from 0611700 to 4e99882 Compare July 21, 2026 06:20
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

run buildall

@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: restricting mark-before-delete to PREPARE rowsets is directionally correct, but the new synchronous abort-before-delete path has two job-correctness blockers and one large-backlog performance regression.

Critical checkpoint conclusions:

  • Goal and tests: PREPARE is the only production recycle type that can still be promoted by commit_rowset; one-round COMPACT/DROP cleanup matches their terminal producers. The new unit test and existing job-flow tests cover type selection and basic two-pass behavior, but they do not cover expired jobs, exact selection among parallel/mixed jobs, or scaled abort throughput. Cloud UT passed for the reviewed head.
  • Scope and compatibility: The patch is focused on three recycler files and adds no wire/storage format or new configuration. Legacy untyped rowsets and tmp-rowset behavior remain compatible.
  • Transactions, persistence, and data correctness: The persisted is_recycled mark conflicts correctly with commit_rowset, and load-transaction abort failure stops deletion. For job rowsets, however, expired jobs are rejected before ABORT handling, and multi-job records can abort the wrong owner; deletion therefore is not reliably gated on terminating the exact owning job.
  • Concurrency and lifecycle: The consolidated SimpleThreadPool drains queued work before destruction, so no dropped-task or captured-lifetime bug was found. The exact-job selection issue is a real parallel-compaction correctness problem, and running every abort synchronously on the scan thread removes the previous bounded batch concurrency.
  • Configuration and parallel paths: Existing mutable mark/abort flags were checked in both states. COMPACT, DROP, legacy, and tmp paths are sound; supported parallel compactions and mixed schema-change/compaction records expose the accepted job-selection issue.
  • Error handling and observability: Non-OK abort results now prevent physical deletion, which is the right invariant, but deterministic JOB_EXPIRED becomes a permanent retry/leak loop. Existing logs identify the rowset and job failure; no new metric or format compatibility concern was found.
  • Performance: A many-tablet PREPARE backlog can serialize per-row metadata round trips on one scan thread without an aggregate PREPARE cap. Abort work needs a bounded completion barrier before deletion rather than global scan serialization.

No local build or test was run because the review contract prohibits builds; conclusions are based on the authoritative bundled diff, current source tracing, and head CI. No additional user focus was supplied. Because the third and final convergence round caught a payload correction, this review is incomplete under the review contract even though all currently identified candidates have been verified and deduplicated.

Comment thread cloud/src/recycler/recycler.cpp Outdated
Comment thread cloud/src/recycler/recycler.cpp Outdated
Comment thread cloud/src/recycler/recycler.cpp Outdated
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from 4e99882 to e2be2f0 Compare July 21, 2026 08:28
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Jul 25th, 2026 6:03 AM.
Workflow run: https://github.com/apache/doris/actions/runs/29814423726

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: restricting mark/abort preparation to PREPARE rowsets is correct for the non-versioned path, but the current head still has two additional data-correctness blockers, the already-raised expired-job and serial-abort problems, and a failing mandatory formatter gate.

Critical checkpoint conclusions:

  • Goal and tests: The changed non-versioned branch correctly stops marking COMPACT/DROP rowsets, and the new type-selection/batch tests reflect their one-pass cleanup. The goal is incomplete for multi-version instances, which return through a parallel PREPARE path with no mark or owner abort. Tests do not cover that dispatch, the schema-change base/new-tablet identity, or successful expired-job cleanup; the new expired-job test instead codifies the existing failure.
  • Scope and compatibility: The patch remains focused on three recycler files and adds no wire/storage format, symbol, or configuration. The exact repeated-compaction selection from the earlier review is fixed on this head. Legacy rowsets, the narrowed tmp-rowset encoding, and former base-version behavior remain compatible.
  • Transactions, persistence, and data correctness: In the changed non-versioned path, the persisted is_recycled write and commit_rowset use the same recycle key transactionally, so the mark is an effective promotion barrier. Multi-version PREPARE deletion bypasses that barrier and can race a late commit into metadata that references deleted files. Schema-change output rowsets also rebuild ABORT with the new-tablet index, which process_schema_change_job rejects before removing either mirrored job record. Expired jobs remain permanently unabortable as already raised in the live thread.
  • Concurrency and lifecycle: SimpleThreadPool::stop() drains queued mark/delete work, and no dropped-task, captured-lifetime, lock-order, or deadlock issue was found. Rowset recycling and timeout abort do run concurrently, which makes the multi-version omission actionable. Synchronous per-PREPARE aborts still serialize unbounded metadata round trips on the scan thread, already covered by the live P2 thread.
  • Configuration and parallel paths: Existing mutable mark/abort flags were checked in both states. COMPACT, DROP, legacy, and non-versioned PREPARE handling are consistent; the enabled multi-version dispatch is the missing functional parallel path. No new FE/BE variable propagation or rolling-upgrade concern applies.
  • Error handling and observability: Non-OK owner aborts correctly stop deletion, and current logs carry instance/tablet/job context. The deterministic JOB_EXPIRED result becomes a retry/leak loop as already reported. Versioned statistics under-report unmarked PREPARE work, but that is a symptom of the same unsafe bypass rather than a separate root comment.
  • Performance: Apart from the already-raised loss of bounded abort concurrency, no additional hot-path, allocation, or worker-shutdown regression was substantiated.
  • Validation: The review contract prohibits builds and test execution, so none were run locally. A read-only clang-format-16 --dry-run --Werror check reproduces violations at recycler.cpp:1930-1931, matching the live failing Clang Formatter job. Current head CI shows BE UT (macOS) passing, but no current Cloud UT result was available.

Review completion: all accepted, dismissed, and duplicate candidates were rechecked against the unchanged live head and the three existing inline threads. The normal full-review and separate risk-focused convergence agents found no further valuable findings for this exact payload. No additional user focus was supplied.

Comment thread cloud/src/recycler/recycler.cpp Outdated
Comment thread cloud/src/recycler/recycler.cpp Outdated
Comment thread cloud/src/recycler/recycler.cpp
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from e2be2f0 to f39b361 Compare July 22, 2026 01:52
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for head f39b361e4ce8a8d72fe182220490c1855cf6568a. No new inline comments are being added because every remaining blocker is already covered by an existing thread.

Unresolved existing issues:

  1. P1: apply the PREPARE barrier to versioned recycling. Multi-version instances return through recycle_versioned_rowsets(), whose PREPARE branch still deletes by prefix without first marking and aborting the owner; a late commit can publish metadata for deleted files.
  2. P1: allow recycler ABORT to remove expired jobs. Both compaction and schema-change processing reject expiration before their ABORT branch, so normally expired PREPARE outputs remain permanently unrecyclable.
  3. P1: preserve the schema-change base tablet index. A new-tablet output finds the mirrored record but rebuilds the request with the new-tablet index, which cannot drive the base-tablet schema-change ABORT.
  4. P2: keep PREPARE aborts bounded-concurrent. The scan thread now serializes every PREPARE owner's metadata reads and commit with only a per-tablet cap, so a many-tablet backlog can monopolize a recycle scan.

The earlier exact repeated-compaction selection issue is fixed at this head by copying only the matched compaction, and the formatter issue is resolved by the current successful Clang Formatter check.

Critical checkpoint conclusions:

  • Goal and proof: Restricting mark-before-delete to PREPARE is correct for the current-key path. COMPACT and DROP records retire already-formal inputs transactionally and have no live PREPARE owner. The new test proves type selection, but the overall safety goal is not complete while the versioned dispatch and job-abort blockers remain.
  • Scope: The patch is confined to the recycler implementation/header and unit tests. The changes are related to the same safety flow, although the unresolved owner-abort corrections are still required for a complete solution.
  • Concurrency: Current-key marking conflicts transactionally with commit_rowset, txn/job abort failures stop deletion, and failed keys retain their data for retry. No lock-order, deadlock, captured-lifetime, or worker-drain issue was found. The remaining concurrency defect is the already-raised unbounded cross-tablet serial abort work.
  • Lifecycle: The current PREPARE flow is mark on one pass, exact owner abort on a later pass, then physical and KV cleanup. SimpleThreadPool::stop() drains queued work. The versioned path bypasses that lifecycle barrier, and expired/schema-change owners cannot complete it.
  • Configuration: No configuration item is added. Existing mutable mark/abort/commit-side checks and force-immediate behavior were traced; the default current-key fence is sound. No PR-introduced configuration regression was found.
  • Compatibility: No wire protocol, function symbol, persisted format, or rolling-upgrade contract is changed. Legacy untyped rowsets, base-version handling, and tmp-rowset encoding remain compatible.
  • Parallel paths and conditions: Current PREPARE, tmp rowsets, COMPACT, DROP, legacy rowsets, loads, repeated compactions, schema changes, and versioned recycling were checked. The enabled multi-version path is the missing functional parallel path; the end_version != 1 condition is preserved and introduced no distinct issue.
  • Tests and results: The changed tests cover PREPARE-only marking, one-pass COMPACT batching, and exact later-compaction selection. They do not prove multi-version late-commit exclusion, successful expired-job removal, new-tablet schema-change cleanup, or bounded backlog behavior. The live head shows BE UT (macOS) and Clang Formatter passing, but no current Cloud UT result is present in the check rollup.
  • Observability: Existing logs include instance, tablet, version, txn/job, and failure context. The versioned statistics mismatch is a symptom of the same missing barrier rather than a separate finding; no additional metric blocker was substantiated.
  • Transactions, persistence, and data writes: Current-key mark/commit conflict handling is atomic, and active exact-compaction removal commits before deletion. Data correctness is still blocked because versioned PREPARE data can be deleted before owner termination, while expired and new-tablet schema-change owners cannot be terminated by this helper.
  • FE/BE propagation: No new cross-process variable or protocol field is introduced, so no additional propagation path applies.
  • Performance: Apart from the existing bounded-concurrency thread, no new hot-path copy, allocation, or complexity regression was found.
  • Other issues: One flag-combination race considered during review was rejected as pre-existing and non-regressive after comparing the aggregate base; this head improves its abort/delete ordering. No other substantiated non-duplicate issue remains.

Validation was static only because the review contract prohibits builds and test execution. The authoritative bundled diff, current source, live head/check state, and existing GitHub review context were inspected. No additional user-provided focus was supplied. The review completed within the three-round limit, and every candidate has been accepted, deduplicated, or dismissed with code evidence.

@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from f39b361 to b24762b Compare July 22, 2026 03:10
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch 3 times, most recently from 3843baf to 69bc479 Compare August 6, 2026 13:26
@wyxxxcat

wyxxxcat commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

run buildall

@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for head 69bc479ebca8c54ff92e85700611d5ba65455d40. No new inline comment is being added because the remaining blocker is already covered by an unresolved live thread.

Unresolved blocker:

  • P1: apply the PREPARE barrier to versioned recycling. Multi-version instances return from recycle_rowsets() through recycle_versioned_rowsets(), whose PREPARE branch still deletes by prefix without marking the current recycle key, aborting the exact owner, or re-reading the key before deletion. A late commit_rowset() can therefore promote the same rowset while object deletion is in flight and leave published metadata referencing missing files. The requested multi-version late-commit test is also still absent.

Critical checkpoint conclusions:

  • Goal and proof: Restricting mark/abort preparation to PREPARE rowsets is correct on the current-key path. COMPACT and DROP entries are already-terminal formal rowsets. The current head proves PREPARE-only selection, exact txn/job abort, retry behavior, and current-path mark/commit conflict handling, but the overall safety goal is incomplete while the versioned dispatch bypasses that lifecycle.
  • Scope: The changes are focused on four Cloud recycler/meta-service files and their unit tests. The additional exact-job, expired-job, schema-mirror, batching, and retry work is part of the same abort-before-delete safety flow.
  • Concurrency: On the current-key path, the persisted mark conflicts with commit_rowset; txn/job abort conflicts with concurrent publish/finish; a fresh recycle-key read suppresses deletion after a winning commit; and failures retain a key for idempotent retry. The shared SimpleThreadPool has bounded workers and queueing and drains on stop(). The remaining actionable concurrency failure is the versioned-path bypass already reported above.
  • Lifecycle: Current PREPARE cleanup is mark, exact owner abort, fresh-key collection, physical/delete-bitmap cleanup, then recycle-key removal. Exact parallel compactions are selected correctly, expired owners can be aborted only through the internal recycler call, and schema change preserves the base tablet index while clearing both base/new-tablet mirrors atomically. No captured-lifetime, lock-order, deadlock, or partial-retry defect was found.
  • Configuration: No new configuration is added. Existing mutable mark/abort flags, base-version compatibility, force-immediate behavior, and multi-version routing were checked. The enabled multi-version route is the missing functional path.
  • Compatibility: No RPC field, persisted format, storage format, or cross-version wire contract changes. The internal helper signature defaults expiration checking on, public RPC behavior is unchanged, and legacy untyped/base-version rowsets remain supported.
  • Parallel paths and conditions: Current PREPARE, load txn, repeated compaction, schema change, COMPACT, DROP, tmp, legacy, config-disabled, and versioned paths were reviewed. The end_version != 1 condition is preserved. Only recycle_versioned_rowsets() lacks the required PREPARE barrier.
  • Tests and results: Added tests cover PREPARE-only marking, txn/job abort-before-delete, exact/expired compactions, schema mirrors, compatibility, retry, commit/mark conflict, and 256-key batch boundaries. They do not cover the unresolved multi-version late-commit case. No build or test was run locally because the review contract prohibits it. Live checks for this head show Clang Formatter and BE UT (macOS) passing; no current Cloud UT result is present.
  • Observability: Existing logs carry instance, tablet, version, txn/job, key, and failure context. Existing counters remain adequate; no new observability blocker was substantiated.
  • Transactions, persistence, and data writes: Current-path mark, owner abort, and job-mirror changes use transactional conflict/commit boundaries and safely retain work after failures. Data correctness is still blocked because versioned PREPARE data can be deleted before its owner is fenced.
  • FE/BE propagation: No new FE/BE variable or protocol propagation applies.
  • Performance: The earlier serial-abort regression is fixed by bounded worker-pool execution. No additional hot-path, allocation, starvation, or shutdown regression survived review.
  • Other issues: A v1 delete-bitmap cleanup concern was verified against the aggregate base and dismissed as unchanged pre-existing behavior; this head improves v2 cleanup retry retention. No distinct new inline issue survived validation and duplicate suppression.

User focus: no additional review focus was supplied, so the complete PR was reviewed without further narrowing.

Review completion: two convergence rounds completed within the three-round cap. All normal and risk-focused reviewers returned NO_NEW_VALUABLE_FINDINGS in round 2, every candidate was accepted, deduplicated, or dismissed with code evidence, and the final changed-file/unresolved-candidate sweep found no issue beyond the existing P1 thread.

@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

Requesting changes for head 69bc479ebca8c54ff92e85700611d5ba65455d40. No new inline comment is being added because the remaining blocker is already covered by an unresolved live thread.

Unresolved blocker:

  • P1: apply the PREPARE barrier to versioned recycling. Multi-version instances return from recycle_rowsets() through recycle_versioned_rowsets(), whose PREPARE branch still deletes by prefix without marking the current recycle key, aborting the exact owner, or re-reading the key before deletion. A late commit_rowset() can therefore promote the same rowset while object deletion is in flight and leave published metadata referencing missing files. The requested multi-version late-commit test is also still absent.

Critical checkpoint conclusions:

  • Goal and proof: Restricting mark/abort preparation to PREPARE rowsets is correct on the current-key path. COMPACT and DROP entries are already-terminal formal rowsets. The current head proves PREPARE-only selection, exact txn/job abort, retry behavior, and current-path mark/commit conflict handling, but the overall safety goal is incomplete while the versioned dispatch bypasses that lifecycle.
  • Scope: The changes are focused on four Cloud recycler/meta-service files and their unit tests. The additional exact-job, expired-job, schema-mirror, batching, and retry work is part of the same abort-before-delete safety flow.
  • Concurrency: On the current-key path, the persisted mark conflicts with commit_rowset; txn/job abort conflicts with concurrent publish/finish; a fresh recycle-key read suppresses deletion after a winning commit; and failures retain a key for idempotent retry. The shared SimpleThreadPool has bounded workers and queueing and drains on stop(). The remaining actionable concurrency failure is the versioned-path bypass already reported above.
  • Lifecycle: Current PREPARE cleanup is mark, exact owner abort, fresh-key collection, physical/delete-bitmap cleanup, then recycle-key removal. Exact parallel compactions are selected correctly, expired owners can be aborted only through the internal recycler call, and schema change preserves the base tablet index while clearing both base/new-tablet mirrors atomically. No captured-lifetime, lock-order, deadlock, or partial-retry defect was found.
  • Configuration: No new configuration is added. Existing mutable mark/abort flags, base-version compatibility, force-immediate behavior, and multi-version routing were checked. The enabled multi-version route is the missing functional path.
  • Compatibility: No RPC field, persisted format, storage format, or cross-version wire contract changes. The internal helper signature defaults expiration checking on, public RPC behavior is unchanged, and legacy untyped/base-version rowsets remain supported.
  • Parallel paths and conditions: Current PREPARE, load txn, repeated compaction, schema change, COMPACT, DROP, tmp, legacy, config-disabled, and versioned paths were reviewed. The end_version != 1 condition is preserved. Only recycle_versioned_rowsets() lacks the required PREPARE barrier.
  • Tests and results: Added tests cover PREPARE-only marking, txn/job abort-before-delete, exact/expired compactions, schema mirrors, compatibility, retry, commit/mark conflict, and 256-key batch boundaries. They do not cover the unresolved multi-version late-commit case. No build or test was run locally because the review contract prohibits it. Live checks for this head show Clang Formatter and BE UT (macOS) passing; no current Cloud UT result is present.
  • Observability: Existing logs carry instance, tablet, version, txn/job, key, and failure context. Existing counters remain adequate; no new observability blocker was substantiated.
  • Transactions, persistence, and data writes: Current-path mark, owner abort, and job-mirror changes use transactional conflict/commit boundaries and safely retain work after failures. Data correctness is still blocked because versioned PREPARE data can be deleted before its owner is fenced.
  • FE/BE propagation: No new FE/BE variable or protocol propagation applies.
  • Performance: The earlier serial-abort regression is fixed by bounded worker-pool execution. No additional hot-path, allocation, starvation, or shutdown regression survived review.
  • Other issues: A v1 delete-bitmap cleanup concern was verified against the aggregate base and dismissed as unchanged pre-existing behavior; this head improves v2 cleanup retry retention. No distinct new inline issue survived validation and duplicate suppression.

User focus: no additional review focus was supplied, so the complete PR was reviewed without further narrowing.

Review completion: two convergence rounds completed within the three-round cap. All normal and risk-focused reviewers returned NO_NEW_VALUABLE_FINDINGS in round 2, every candidate was accepted, deduplicated, or dismissed with code evidence, and the final changed-file/unresolved-candidate sweep found no issue beyond the existing P1 thread.

versioned recycleing will be resolved at another pr

@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from 69bc479 to 261fa33 Compare August 10, 2026 15:06
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 96.04% (97/101) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 78.41% (1997/2547)
Line Coverage 65.66% (36536/55647)
Region Coverage 65.69% (18545/28229)
Branch Coverage 55.35% (10102/18252)

@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed after two full convergence rounds. One new P1 finding is attached inline.

Critical checkpoint conclusions:

  • Goal and scope: The PR is focused on typed PREPARE recycling and exact owner cleanup. The ordinary mark/abort/delete sequence is substantially improved, but mark-only mode still lacks a durable publication fence.
  • Architecture and parallel paths: The non-versioned production path and its load, compaction, and schema-change owners were traced end to end. The multi-version bypass is real but already covered by discussion r3622806962, so it is not duplicated here. No static-lifecycle or unrelated FE/BE-variable concern was found.
  • Concurrency and lifecycle: The shared worker pool is bounded, and each batch preserves mark -> abort -> reread -> object/delete-bitmap deletion -> recycle-key removal. Same-owner transactional conflicts and failure retries are safe after a successful owner abort. The inline mark-only retry race remains.
  • Transactions and data correctness: Exact job selection, expired ABORT handling, schema mirror/base indices, lock cleanup, and final key removal were verified. In the inline interleaving, metadata can still be published after its object files are removed.
  • Configuration and compatibility: The mark and abort flags are independently mutable, making mark=true, abort=false a supported unsafe combination. No new serialization, storage-format, or rolling-compatibility defect was found. The manufactured [0-1] test case is fileless in real production and was not reported.
  • Tests and failure paths: I did not run local builds or tests, per the review bundle instructions. The added tests cover ordinary load/job ownership, batching, and retry failures, but do not execute a real late prepare_rowset() overwrite followed by publication in mark-only mode.
  • Performance, observability, and documentation: The shared pool restores bounded concurrency; existing logging includes relevant IDs and batch timing. No distinct new performance, observability, or documentation issue was substantiated.
  • User focus: No additional review focus was supplied.

Review status: complete and converged, with one new P1 plus the already-existing review threads.

Comment thread cloud/src/recycler/recycler.cpp Outdated
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch 3 times, most recently from 3316c71 to 8cc487f Compare August 13, 2026 06:12
@wyxxxcat
wyxxxcat marked this pull request as draft August 13, 2026 06:14
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch 5 times, most recently from 207b82e to 94c43c2 Compare August 14, 2026 01:55
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

run buildall

@wyxxxcat
wyxxxcat marked this pull request as ready for review August 14, 2026 01:56
@wyxxxcat

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: the head still introduces one owner-abort concurrency regression, one large-backlog FDB read regression, and two completion-accounting defects. Four new P2 findings are attached inline.

Critical checkpoint conclusions:

  • Goal and proof: Restricting deletion to PREPARE rowsets and terminating their exact txn/job owners is directionally correct, and the added tests cover load, compaction, schema change, expiration, and several failure paths. The goal is not fully proved: the same-owner test is unintentionally serialized, and no tests cover the two completion counters or large tmp-rowset reread batches. Existing current-publication and versioned-path blockers remain represented by their live threads.
  • Scope and clarity: The implementation is focused on four Cloud meta-service/recycler files and tests, with no unrelated feature expansion. No new config, protocol, storage format, function-symbol contract, or FE/BE variable propagation is introduced.
  • Concurrency and lifecycle: Current and tmp cleanup use bounded SimpleThreadPool workers, and stop drains and joins them before captured counters/metrics contexts leave scope. No lock-order, deadlock, static-initialization, or capture-lifetime defect survived review. However, per-key current-PREPARE tasks can concurrently abort the same owner and self-conflict, leaving expired keys for the next normal 3600-second round.
  • Configuration, conditions, and parallel paths: Dynamic mark/abort combinations, base-version/no-owner compatibility, current/tmp/versioned collectors, and load/compaction/schema-change owners were traced. The versioned PREPARE bypass is already covered by discussion r3622806962, and the current-key publication fence is already covered by r3755122307; neither is duplicated here.
  • Transactions, persistence, and data writes: Exact compaction selection, expired internal ABORT, and schema-change base/mirror cleanup are transactionally conflict-protected. Object and bitmap failures retain a driver key for retry, and worker shutdown is orderly. The tmp-key/ref-count split and two tmp publication races considered during review are real but unchanged from the authoritative baseline, so they are not attributed to this patch. No FE EditLog path applies.
  • Error handling and observability: Owner-abort and physical-delete failures retain keys and include instance/tablet/txn/job context. Successful current PREPARE cleanup omits num_recycled, while deferred tmp aborts skip num_expired and metadata-byte accounting, producing internally inconsistent completion reports.
  • Tests and results: The added 257-rowset test inherits worker_pool_size=1 from an earlier test and therefore misses production same-owner conflicts; it also never crosses the helper batch because production passes one key per call. No test observes the accepted accounting or FDB-read-amplification paths. I did not run local builds or tests because the review bundle prohibits them; the refreshed live head shows Cloud UT, cloud_p0, compile, formatter, BE/macOS UT, and the other reported checks passing, with only this automated review pending.
  • Performance and other issues: The new tmp freshness loop can create and synchronously await up to 10,000 point-read transactions per scan page instead of using the existing bounded-concurrent snapshot batch API. No additional CPU, memory, log-volume, compatibility, documentation, or data-correctness issue survived attribution and duplicate suppression.

User focus: no additional review focus was supplied, so the complete PR was reviewed without further narrowing.

Review completion: capped/incomplete. A new valuable performance finding survived in the third and final allowed round. All currently known candidates are nevertheless verified, deduplicated, accepted, or dismissed, and all four accepted findings are included in this review.

Comment thread cloud/src/recycler/recycler.cpp Outdated
err = txn->get(key, &val);
if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) {
// has already been removed
int ret = txn_get(txn_kv_.get(), key, val);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Batch the tmp-rowset freshness reads

This loop calls txn_get() once per key; that helper creates a new transaction and synchronously waits for one snapshot point read. A scan page can contain 10,000 expired tmp keys, so one worker can perform 10,000 serial FDB round trips before any object cleanup begins. Keep the post-abort freshness check, but use snapshot batch_get in bounded chunks (the existing API issues up to 1,000 FDB gets concurrently) and retain the per-key missing/parse handling. Please add a large-batch read-count or instrumentation test.

Comment thread cloud/src/recycler/recycler.cpp Outdated
if (delete_versioned_delete_bitmap_kvs(tablet_id, rowset_id) != 0) {
return;
}
if (txn_remove(txn_kv_.get(), aborted_keys) != 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Count successful abort-protected deletions

After this removal succeeds, the new PREPARE path exits without incrementing num_recycled as the other prefix/formal deletion workers do. An all-PREPARE abort-enabled run can therefore delete every object and KV while its completion log reports num_recycled=0. Update the counter after successful KV removal and cover it in the new PREPARE tests.

Comment thread cloud/src/recycler/recycler.cpp Outdated
<< instance_id_ << " tablet_id=" << rowset_meta->tablet_id()
<< " version=[" << rowset_meta->start_version() << '-'
<< rowset_meta->end_version() << "]";
submit_recycle_prepare_rowsets_job(std::string(k), rowset_meta->resource_id(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Coalesce PREPARE aborts by owner

This submits one abort transaction per rowset, so the default 32 workers race when many PREPARE rowsets share one load txn or tablet job. They all read/write the same owner record; one commit wins and the losers return TXN_CONFLICT, retaining already-expired keys until the next recycler interval (normally 3600s). Group by txn_id or exact (tablet_id, job_id), abort once, and fan the result out to all owned keys. The added 257-key test does not cover this: an earlier test leaks worker_pool_size=1, and each invocation here passes only {key}, so it neither exercises production concurrency nor the 256-item collector batch.

Comment thread cloud/src/recycler/recycler.cpp
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from 94c43c2 to bafa160 Compare August 14, 2026 07:14
@wyxxxcat
wyxxxcat force-pushed the mark_rowset_filter_prepared branch from bafa160 to fd77f09 Compare August 14, 2026 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants