Skip to content

feat(catalog): support write.metadata.delete-after-commit.enabled - #3582

Merged
szehon-ho merged 2 commits into
apache:mainfrom
viirya:feat-metadata-delete-after-commit
Nov 9, 2026
Merged

szehon-ho merged 2 commits into
apache:mainfrom
viirya:feat-metadata-delete-after-commit

Conversation

@viirya

@viirya viirya commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Which issue does this PR close?

What changes are included in this PR?

Adds the write.metadata.delete-after-commit.enabled table property (default false) and a shared iceberg::delete_removed_metadata_files helper that matches Java's CatalogUtil.deleteRemovedMetadataFiles. Catalogs call it only after the metadata pointer swap succeeds, so a failed commit, or one whose outcome is unknown, never deletes anything.

The helper reads the property from the new metadata (as Java does) and deletes the files in the base metadata_log that are not in the new one. It diffs the two logs rather than using TableMetadataBuildResult::expired_metadata_logs, because TableCommit::apply builds the metadata and drops that result before catalogs see it, and the diff is what Java does. Deletion is best-effort: each failure is logged with tracing::warn! and the commit still succeeds.

Wired into the memory, SQL and Glue catalogs. Not wired into REST, where the server owns metadata files (Java doesn't delete client-side either), or S3 Tables, where the service manages file cleanup. HMS doesn't support update_table yet.

Are these changes tested?

Yes.

  • Memory catalog unit tests: enabled deletes exactly the files that fell out of the log and keeps the ones still in it; unset or false keeps everything; a delete that fails (a non-empty directory in place of the old file on the local FS) doesn't fail the commit, and later commits keep deleting.
  • table_suite in crates/catalog/loader: the same enabled scenario for the Glue, SQL and memory catalogs. I ran the Glue case locally against the moto and MinIO containers.

AI Disclosure

Written with an AI assistant (Claude). Please check:

  • The catalog split: wired into memory, SQL and Glue; skipped for S3 Tables even though its client writes the metadata file itself, on the assumption that the service owns cleanup of table bucket files. If S3 Tables should delete them client-side, it's a two-line addition.
  • The removed-file semantics: diffing base and new metadata_log by file path, and reading the property from the new metadata.
  • The memory catalog releases its state lock before deleting, so deletes don't block other commits.

Add the `write.metadata.delete-after-commit.enabled` table property
(default false). When it is set, catalogs that write metadata files
themselves delete the previous metadata files that fall out of the
metadata log (bounded by `write.metadata.previous-versions-max`) after
a successful commit, matching Java's
`CatalogUtil.deleteRemovedMetadataFiles`.

The shared `delete_removed_metadata_files` helper diffs the base and
committed metadata logs and deletes best-effort, logging failures
without failing the commit. It is wired into the memory, SQL and Glue
catalogs. REST and S3 Tables are left out because the server or
service owns metadata file cleanup, and HMS does not support commits
yet.

Co-authored-by: Isaac <no-reply@databricks.com>
Copilot AI balanced review requested due to automatic review settings October 30, 2026 01:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are blocking the opt-in metadata cleanup change.

No open issues 🎉

What changed in this PR

Addresses #3581 by adding opt-in cleanup of old metadata files after successful commits in the memory, SQL, and Glue catalogs.

Changes:

  • Adds write.metadata.delete-after-commit.enabled, defaulting to false.
  • Introduces shared, best-effort cleanup of files removed from the metadata log, called only after a successful metadata pointer update.
  • Adds tests for enabled and disabled cleanup, deletion failures, and cross-catalog behavior.
File Description
crates/​iceberg/​src/​spec/​table_properties.rs Defines the cleanup property, getter, and default.
crates/​iceberg/​src/​lib.rs Exports the shared cleanup helper.
crates/​iceberg/​src/​catalog/​utils.rs Implements bounded concurrent deletion with warning-only failures.
crates/​iceberg/​src/​catalog/​memory/​catalog.rs Runs cleanup after committing and releasing the lock; adds unit tests.
crates/​iceberg/​public-api.txt Records the new property API and helper.
crates/​catalog/​sql/​src/​catalog.rs Runs cleanup after a successful SQL catalog update.
crates/​catalog/​loader/​tests/​table_suite.rs Tests cleanup across memory, SQL, and Glue catalogs.
crates/​catalog/​glue/​src/​catalog.rs Runs cleanup after a successful Glue catalog update.

Review effort: Balanced

@viirya

viirya commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

cc @szehon-ho Can you take a look? Thanks!

Comment thread crates/iceberg/src/catalog/utils.rs Outdated
}

/// Deletes the previous metadata files tracked by `base` that `new` no longer tracks, if
/// `write.metadata.delete-after-commit.enabled` is set on `new`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we say “is true” here? The property can be explicitly set to false, which skips cleanup.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point, changed it to "is true on new".

}

#[tokio::test]
async fn test_update_table_deletes_metadata_files_removed_from_log_when_enabled() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As optional coverage, could we add a test that enables cleanup during an update and verifies deletion on that same commit? This would check that cleanup reads the new metadata’s setting.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added test_update_table_deletes_removed_metadata_files_on_commit_that_enables_cleanup. It creates the table with only previous-versions-max=1, commits twice with cleanup off so v0 falls out of the log, then sets delete-after-commit.enabled=true on the third commit. That commit deletes v1 and leaves v0 in place, since v0 fell out of the log while cleanup was off. This matches Java. The test fails if the helper reads the property from base instead of new. None of the existing tests caught that, because they all set the property at table creation.

Address review: test that cleanup reads the property from the new
metadata, and say the property must be true in the helper's doc.

Co-authored-by: Isaac <no-reply@databricks.com>
@viirya
viirya requested a review from szehon-ho November 7, 2026 06:25
@szehon-ho
szehon-ho added this pull request to the merge queue Nov 9, 2026
@szehon-ho

Copy link
Copy Markdown
Member

lgtm, thanks!

Merged via the queue into apache:main with commit ffdf043 Nov 9, 2026
24 checks passed
@viirya
viirya deleted the feat-metadata-delete-after-commit branch November 9, 2026 22:20
@viirya

viirya commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

Thanks @szehon-ho !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support write.metadata.delete-after-commit.enabled to delete old metadata files after commit

3 participants