Skip to content

Compactor: delete orphaned global block deletion marks - #7890

Open
cvas22 wants to merge 3 commits into
cortexproject:masterfrom
cvas22:fix/7885-orphaned-deletion-marks
Open

cvas22 wants to merge 3 commits into
cortexproject:masterfrom
cvas22:fix/7885-orphaned-deletion-marks

Conversation

@cvas22

@cvas22 cvas22 commented Oct 21, 2026 •

Copy link
Copy Markdown

What this PR does:

When a block is gone from the bucket but its deletion mark is still in the tenant's markers/ location, the bucket index updater logs skipped missing block deletion mark on every run and never removes the mark. The tenant location then stays in the bucket forever, even with no blocks and no bucket index.

This change deletes such a mark from the updater. To avoid racing with a block that is being marked for deletion (the global mark is uploaded before the per-block one), the mark is only removed when nothing exists under the block's location. If listing or deleting fails, it is logged and the update continues.

Only block deletion marks are handled. Orphaned no-compact marks are not touched.

Tests: new TestUpdater_UpdateIndex_ShouldDeleteOrphanedGlobalDeletionMarks (fails without the change). Ran the bucketindex and compactor blocks cleaner tests on Linux.

Which issue(s) this PR fixes:
Fixes #7885

Checklist

  • Tests updated
  • Documentation added (no user-facing config or documented behavior changes)
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]
  • docs/configuration/v1-guarantees.md updated if this PR introduces experimental flags (no new flags)

@cvas22
cvas22 marked this pull request as ready for review October 21, 2026 20:15
@cvas22
cvas22 requested a review from a team as a code owner October 21, 2026 20:15
@cvas22
cvas22 requested a review from alanprot October 21, 2026 20:15
Comment thread CHANGELOG.md Outdated
@cvas22
cvas22 force-pushed the fix/7885-orphaned-deletion-marks branch from e000cf4 to 0355207 Compare October 22, 2026 02:21
@cvas22
cvas22 force-pushed the fix/7885-orphaned-deletion-marks branch from 0355207 to 8f727a8 Compare October 22, 2026 19:47
@cvas22

cvas22 commented Oct 22, 2026

Copy link
Copy Markdown
Author

Rebased onto master to resolve the CHANGELOG.md conflict with #7888 (both entries kept; the code is unchanged). I also fixed the issue link in the description: this fixes #7885.

The earlier test (amd64) failure was TestCPUCheckedBeforeHeap in pkg/util/queryeviction, which this PR doesn't touch; it looks like the flake #7817 addresses. bucketindex and the compactor TestBlocksCleaner tests pass on Linux after the rebase.

@cvas22
cvas22 force-pushed the fix/7885-orphaned-deletion-marks branch from 8f727a8 to 77650d5 Compare October 25, 2026 19:37
@cvas22

cvas22 commented Oct 25, 2026

Copy link
Copy Markdown
Author

Rebased onto master again to resolve the CHANGELOG.md conflict with #7892; both entries are kept and the code is unchanged. Thanks for the review.

@sandy2008 sandy2008 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.

The empty-location guard looks safe given the ordering of the writers (the global mark is written before the per-block one, and block.Delete removes deletion-mark.json last), and the new test fails without the fix. One problem with how the iteration is stopped early, inline.

Comment thread pkg/storage/tsdb/bucketindex/updater.go Outdated
hasObjects := false
err := w.bkt.Iter(ctx, id.String()+objstore.DirDelim, func(string) error {
hasObjects = true
return errStopIteration

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.

Returning an error to stop early doesn't play well with S3. The objstore S3 Iter returns straight away and leaves minio's ListObjects channel undrained, and its producer blocks on the send (even after ctx cancel), so with three or more objects under the prefix a goroutine leaks per call. Cortex's BucketWithRetries also treats the sentinel as a failure and retries it 5 times with 5s→1m backoff, and the metrics wrapper counts it in thanos_objstore_bucket_operation_failures_total{operation="iter"}. This path recurs every cleanup cycle for a block whose per-block mark never got uploaded. A block directory only has a handful of objects, so setting hasObjects and returning nil (letting the listing finish) avoids all three.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch, thanks. In 4fe9f99 the callback now sets hasObjects and returns nil, so the listing always finishes, and I removed errStopIteration. The bucketindex tests pass.

When a block no longer exists but its deletion mark is still in the
tenant's markers/ location, the bucket index updater skipped the mark
at every run and never removed it, so the tenant location stayed in the
bucket forever. Delete such a mark when the block location is empty.

Fixes cortexproject#7885

Signed-off-by: Srinivas Chippagiri <cvas22@gmail.com>
Signed-off-by: Srinivas Chippagiri <cvas22@gmail.com>
Returning an error from the Iter callback leaves the S3 listing
undrained, and BucketWithRetries and the metrics wrapper treat it as a
failed operation. A block location holds only a few objects, so list
them all.

Signed-off-by: Srinivas Chippagiri <cvas22@gmail.com>
@cvas22
cvas22 force-pushed the fix/7885-orphaned-deletion-marks branch from 4fe9f99 to e67337a Compare October 28, 2026 09:13
@cvas22

cvas22 commented Oct 28, 2026

Copy link
Copy Markdown
Author

I rebased this on master to resolve a CHANGELOG conflict (both entries are kept). There are no code changes since the approvals. Could a maintainer start the CI workflows and merge if it's green? Thanks!

This branch has not been deployed

No deployments
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.

Compactor leaves orphaned global block deletion markers, keeping empty tenant folders forever

4 participants