[Store] Add reliable per-object deletion and Bucket GC for LOCAL_DISK - #3221
Open
zchuango wants to merge 8 commits into
Open
[Store] Add reliable per-object deletion and Bucket GC for LOCAL_DISK#3221zchuango wants to merge 8 commits into
zchuango wants to merge 8 commits into
Conversation
zchuango
requested review from
00fish0,
Icedcoco,
Libotry,
ShangmingCai,
UNIDY2002,
XucSh,
YiXR,
alogfans,
staryxchen,
stmatengss and
ykwd
as code owners
July 31, 2026 09:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Refs #3220 .
This PR implements reliable per-object deletion and physical space reclamation for
LOCAL_DISKreplicas in the Bucket backend.The implementation is submitted as one end-to-end change because object incarnation, stable storage identity, durable delete intents, holder-side tombstones, ACK durability, Bucket GC, and crash recovery jointly form the correctness boundary of the deletion lifecycle.
The changes are organized by subsystem in the implementation, description, and tests to keep the review tractable.
Currently,
RemoveandBatchRemoveprimarily remove logical metadata from the Master, but they do not reliably propagate per-object deletion to the remote Bucket backend holding the correspondingLOCAL_DISKreplica.This can result in:
This PR adds the following end-to-end deletion path:
Remove/BatchRemovedoes not wait for physical GC. A successful return means the logical deletion and the delete intent supported by the current deployment mode have been accepted; it does not mean SSD space has already been synchronously reclaimed.What changed
1. Object incarnation and stable storage identity
Generate an immutable
ObjectIncarnationfor every newly created logical object.Propagate the incarnation through:
Persist a stable LOCAL_DISK identity in:
Add stable
local_disk_segment_idand per-ownermount_epoch.Validate
client_id, storage identity, mount epoch, and delete capability during Fetch/Ack.Fence the old epoch when a new owner mounts the same storage identity.
Use a local advisory lock to prevent two processes on the same node from opening the same directory concurrently.
Fail closed by default for non-empty legacy directories without an identity marker.
Allow explicit administrator adoption through:
2. Master-side deletion protocol
LOCAL_DISKreplicas that advertiseOBJECT_TOMBSTONE_V1.LocalDeleteRegistrywith a capacity of 50,000 tasks.BatchRemoveresult semantics instead of introducing a batch-wide transaction.3. Fetch/Ack RPC and HA recovery
FetchLocalDeleteTasks.AckLocalDeleteTasks.REMOVEdelete-intent payload.LOCAL_DELETE_ACKOpLog operation.4. Holder-side durable tombstone
BatchMarkDeletedperforms at most one metadata persistence operation per affected bucket.tombstoned=true;.meta;fsyncthe temporary file;.meta;fsyncthe parent directory;RemovedAlreadyRemovedStaleVersionRetryableFailureon file-write, fsync, rename, or other persistence failures.ScanMeta,BucketScan, and read paths.5. Watermarked Bucket GC
The GC mechanism is implemented in this PR, while its final default rollout policy is intentionally left open for review. In particular, normal ratio-based GC and high-watermark-triggered reclaim can be configured differently if maintainers prefer a more conservative rollout.
6. GC crash recovery
Persist local source/target transition state in:
PREPARED:COMMITTED:Fail closed if a committed target is missing or corrupted.
Clean up stale bucket metadata during initialization when
.metaexists but the corresponding data file is missing.7. Snapshot and compatibility
Upgrade the snapshot format from
1.0.0to1.1.0.Keep support for reading
1.0.0.Read legacy bucket metadata as:
Do not deliver delete tasks to backends that do not advertise the tombstone capability.
Return
SEGMENT_ALREADY_EXISTSfor an identical repeated local-disk mount.Update mount state when the same client changes storage identity, epoch, or capability.
Require participating components to understand the corresponding RPC, OpLog, and snapshot semantics before relying on the reliable-deletion guarantee.
The current implementation persists
.mooncake_local_disk_segment_idfor stable LOCAL_DISK identity.For an existing non-empty directory without this marker, the current implementation fails closed unless explicit adoption is enabled through:
This behavior reflects the current implementation, but the final rollout policy for legacy unmarked directories is open to maintainer feedback. A compatibility mode for existing unmarked directories can be added if preferred.
Deployment semantics
Scope
This PR changes:
RemoveBatchRemoveThis PR does not change:
RemoveAllRemoveByRegexReview scope
This PR intentionally implements the complete LOCAL_DISK per-object deletion lifecycle in one change.
Although the implementation spans Master metadata, OpLog/snapshot recovery, holder-side storage handling, and Bucket GC, these components are coupled by the deletion correctness contract:
The PR is organized by subsystem so each component can be reviewed independently while preserving an end-to-end implementation that can be tested as a whole.
Known limitations
1. Permanently lost storage
A permanently lost storage identity does not automatically expire its pending tasks.
This is intentional fail-closed behavior because silently expiring tasks would weaken the deletion guarantee.
If the registry reaches capacity, new Remove operations may be rejected.
Explicit storage retirement, administrator force-drop, audit logging, and related metrics are left as follow-up work.
2. Runtime GC cleanup retry
If
.bucket_gc_intenthas already reachedCOMMITTEDbut source unlink, directory fsync, or reader drain fails or times out:This is a space-reclamation liveness limitation rather than an object-consistency failure.
Runtime retry of committed GC cleanup can be added as follow-up work.
3. Delete/GC relocation correctness
If GC relocates an object from a source bucket to a replacement bucket while deletion is in progress, the delete path must re-resolve the current bucket mapping and retry the tombstone against the replacement when the same incarnation is still present.
StaleVersionis only terminal when the object is truly absent or the current object belongs to a different incarnation.This race is part of the correctness contract and should remain protected by deterministic regression coverage.
4. Performance validation
Bucket GC introduces additional live-byte copy I/O when reclaiming partially dead buckets.
The current implementation bounds this work through:
Remove/BatchRemoveRPC path.Representative SSD benchmarks for Get p99, GC throughput, write amplification, RSS, and foreground I/O interference are useful additional validation and are planned during review.
The final default GC policy can be adjusted based on maintainer feedback and benchmark results without changing the core reliable-deletion protocol.
Related work
RemoveAll; this PR handles per-object deletion.Module
mooncake-transfer-engine)mooncake-store)mooncake-ep)mooncake-pg)mooncake-integration)mooncake-p2p-store)mooncake-wheel)mooncake-common)mooncake-rl)Type of Change
This is currently marked as a breaking/deployment compatibility change because the implementation introduces a persistent LOCAL_DISK identity marker and currently fails closed when mounting an existing non-empty directory without that marker.
Legacy snapshots and bucket metadata remain readable, and explicit adoption is supported.
The final behavior for legacy unmarked directories is still open to review. If a backward-compatible legacy mount mode is preferred and implemented, this PR may no longer need to be classified as a breaking change.
How Has This Been Tested?
Feature and regression tests
ctest --test-dir build-ssd-delete --output-on-failure -R '^(master_service_test_for_snapshot|snapshot_child_process_test|master_snapshot_codec_test|storage_backend_test|batch_remove_test|master_service_ssd_test|file_storage_test|client_integration_test|non_ha_reconnect_test|master_service_ha_test|hot_standby_service_test|catalog_backed_snapshot_provider_test)$'ctest --test-dir build-ssd-delete --output-on-failure -R '^(storage_backend_bucket_delete_test|local_delete_test|oplog_applier_test|local_delete_process_kill_test)$'ctest --test-dir build-ssd-delete --output-on-failure -R '^(serializer_test|segment_test|oplog_types_test|master_service_test|master_service_ssd_test_for_snapshot)$'The listed tests pass in the current development environment.
Current coverage includes:
Additional validation planned during review includes:
Test results:
Checklist
./scripts/code_format.shmainAI Assistance Disclosure
Codex was used to assist with design analysis, implementation, test construction, failure-path review, and documentation.
The submitter remains responsible for reviewing, understanding, testing, and defending the final implementation.