Support rewrite_manifests table maintenance - #3631
Conversation
|
Marking this ready for review. I had kept it as a draft to land consistently with #3124, which adds State: CI green (17/17), mergeable, five tests using an in-memory catalog with real appends. V3 tables are rejected with a clear error for now, since rewriting must preserve @Fokko @sungwy would either of you have time to take a look? Closes #3629. |
fdafa3e to
b061e1d
Compare
Add table.maintenance.rewrite_manifests(), which merges the current snapshot's data manifests into fewer manifests sized by commit.manifest.target-size-bytes. Entries are rewritten as EXISTING and keep their sequence numbers; delete manifests and manifests that need no merging are kept as-is. The result is committed as a replace snapshot whose totals carry over unchanged. V3 tables are rejected for now: rewriting must preserve the first-row-id of rewritten manifests, which needs the read side of row lineage (apache#3621). Closes apache#3629
Committing a replace snapshot that merely re-lists the same manifests has no value; return no updates instead, and assert in the no-op test that the current snapshot is unchanged. Document that rewrites carry live entries only, matching the reference implementation, and add the Spark interop integration test (data, snapshot history, file and manifest counts, and pre-rewrite time travel verified from Spark).
tests/table/test_rewrite_manifests.py and the integration test shared a module name, which fails mypy collection.
The target was exactly twice the first manifest's length, so a second manifest one byte larger started its own group and the test was flaky.
b061e1d to
dd05200
Compare
|
Hi @moomindani, Thanks for taking the initiative on this feature and setting up a great foundation! While working on the follow-up for #3840 (suggested by @kevinjqliu to allow rewriting legacy manifests), I came across your PR. Based on the Java Iceberg reference (
I already have a tested implementation with these enhancements ready locally. If you're open to it, I'd be more than happy to collaborate by opening a PR directly to your branch or co-authoring to help land this together! Thanks again for your great work! |
|
@hedger9487 thanks for the careful read. One piece of context that shapes my answer: in @kevinjqliu's plan on #3840 (31 August), step 3 is exactly this API — a maintenance operation that rewrites the manifests of the current snapshot so the legacy Of your four, the one I want here is (1) — and I think your (2) is the right way to express it, rather than a second feature. Today (3) bin-packing and concurrency via A PR against my branch is very welcome — @kevinjqliu one thing worth flagging from your #3840 plan: step 3 is this PR. CI is green and it has been open since 8 July with no review, and with the |
|
Hi @moomindani, Thank you for the helpful context regarding #3840! Following our discussion, I have opened a PR against your branch with the Summary of changes:
Please take a look when you have a moment and let me know if there is anything you would like adjusted! |
- Support selective manifest rewriting via rewrite_if(predicate) - Allow single manifest rewriting when matching predicate (needed for apache#3840) - Update rewrites_needed() to evaluate predicate - Add unit tests for selective rewriting and single manifest predicates
…and V1 edge cases - Guard ManifestWriter by peeking first live entry with itertools.chain to avoid empty manifest files - Retain plain rewrite_manifests behavior merging live and fully-deleted manifests into one - Clarify rewrite_if docstring regarding single-manifest optimization - Add regression tests for kept paths, fully deleted manifests, and merging dead manifests
Closes #3629
Rationale for this change
Adds
table.maintenance.rewrite_manifests(), the explicit maintenance counterpart of Java'sTable.rewriteManifests()(Spark:rewrite_manifests). When a table accumulates many small manifests from repeated appends, scan planning slows down; this merges the current snapshot's data manifests into fewer manifests sized bycommit.manifest.target-size-bytes(default 8 MB).rewrite_if(predicate)selects which data manifests to rewrite; manifests that do not match are kept as-is. Passing a predicate also disables the single-manifest shortcut, so a matching manifest is rewritten even when there is nothing to merge it with — which is what lets a caller target a specific set of manifests, such as ones written by an older library version. Contributed by @hedger9487.replacesnapshot; snapshot totals carry over unchanged (update_snapshot_summariesnow handlesOperation.REPLACE), and the summary reportsmanifests-created/manifests-kept/manifests-replaced/entries-processed, matching Java.first-row-idof rewritten manifests, which needs the read side of row lineage (Support row lineage assignment on commit #3621). The writer-side plumbing already exists in Support writing V3 manifests and manifest lists #3624.Related: #270 tracks automatic manifest merging on write; this PR covers only the explicit maintenance API.
Related: #3124 is adding
table.maintenance.compact()on the sameMaintenanceTable. The two touch different methods and do not conflict; whichever lands first sets the convention for the other.Are these changes tested?
Yes, eleven tests using an in-memory catalog with real appends: merging three manifests into one (entry counts, EXISTING status, data unchanged, replace summary with carried-over totals), sequence-number preservation including the merged manifest's
min_sequence_number, single-manifest no-op, target-size grouping, andrewrites_needed(); then forrewrite_if: selective rewrite with the untouched manifests asserted to keep their exact paths and underlying data files, a single manifest rewritten because it matches,rewrites_needed()under matching and non-matching predicates, a predicate matching nothing committing nothing, a manifest holding only deleted entries left alone rather than producing an empty manifest, and plainrewrite_manifests()merging a live and a fully-deleted manifest into one. Removing the empty-manifest guard fails the fully-deleted test; removing the implementation fails all of them.Are there any user-facing changes?
Yes: a new
table.maintenance.rewrite_manifests()API with an optionalrewrite_if(predicate), documented in a new "Manifest Rewriting" subsection ofmkdocs/docs/api.md.This pull request and its description were written by Claude Fable 5.