Skip to content

Core: Preserve concurrent snapshots in replace transactions - #16943

Open
wombatu-kun wants to merge 4 commits into
apache:mainfrom
wombatu-kun:issue/16942-replace-concurrent-snapshots
Open

wombatu-kun wants to merge 4 commits into
apache:mainfrom
wombatu-kun:issue/16942-replace-concurrent-snapshots

Conversation

@wombatu-kun

@wombatu-kun wombatu-kun commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

Closes #16942. Part of #16232.

A replace transaction commits metadata built when it started, so on BaseMetastoreCatalog catalogs (Hive, Glue, JDBC, Nessie, Hadoop) changes committed in between are lost: another writer's snapshot drops out of history, and a snapshot that expire_snapshots removed comes back. When the table changed, the replacement is now rebuilt on the refreshed metadata and the transaction's updates are replayed, which also keeps concurrent property changes, as REST does. If the rebuilt schema, spec, sort order or format version would differ from the transaction's (IDs included), or an update cannot be replayed (for example a merge-schema CREATE OR REPLACE), the commit falls back to today's behavior. REST keeps merging server-side; path-based HadoopTables is a follow-up. Builds on #16975, #15092 and #15904.

Test plan: each CatalogTests suite checks that a replace keeps a concurrent snapshot, does not bring back an expired snapshot, and, when a no-op schema update blocks the replay, keeps its own data and every manifest list; TestReplaceTransaction checks the history and that the replace's files keep their sort order, on format versions 1 to 4. The history tests fail on main for metastore catalogs, the replay test fails without the fallback or the cleanup filter, and the sort-order test fails without the sort-order check.


AI Disclosure

@wombatu-kun

Copy link
Copy Markdown
Contributor Author

@nastra @amogh-jahagirdar this one has been sitting since June 24 with no review at all. CI is green (56/56) and it still merges cleanly on current main, so it is only waiting on a reviewer.

It fixes silent snapshot loss: when two replace / createOrReplace transactions race, the loser re-commits replacement metadata built from its stale base, so the concurrent writer's snapshot disappears from history (#16942). This hits the catalogs that rewrite full metadata (Hadoop, Hive, Glue, JDBC, Nessie); REST merges server-side and is unaffected.

Tagging you two because you handled the closest prior work in this path (#11671). A look whenever you have time would be much appreciated.

@wombatu-kun
wombatu-kun force-pushed the issue/16942-replace-concurrent-snapshots branch from 49f6d44 to c995464 Compare August 11, 2026 05:46
@wombatu-kun
wombatu-kun force-pushed the issue/16942-replace-concurrent-snapshots branch from c995464 to e339dd4 Compare September 10, 2026 04:02
@wombatu-kun wombatu-kun reopened this Sep 10, 2026
@wombatu-kun wombatu-kun changed the title Core: Preserve concurrent snapshots on replace transaction retry Core: Preserve concurrent snapshots in replace transactions Sep 30, 2026
@wombatu-kun

Copy link
Copy Markdown
Contributor Author

@pvary you merged #15389 in BaseTransaction, so this looks like your area - would you have a moment for this one? It fixes #16942 and part of #16232: on metastore catalogs a replace transaction commits metadata built before a concurrent commit, so the other writer's snapshot drops out of history and an expired snapshot can come back. The red CVE Scan jobs are the repo-wide jackson-databind finding that #18318 fixes.

@pvary

pvary commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@wombatu-kun: I likely will not have time to dig into the details in the near future 😢

@wombatu-kun
wombatu-kun force-pushed the issue/16942-replace-concurrent-snapshots branch from 16dd446 to 8037fda Compare October 12, 2026 02:29
cdouglas added a commit to cdouglas/iceberg that referenced this pull request Oct 21, 2026
A replace transaction committed the replacement it built from the table
as it began, so it dropped whatever other writers committed in between:
a commit to main or to another branch, a tag, a property such as
gc.enabled=false, a format upgrade (the replace downgraded the table),
and it brought back snapshots expired since, without their manifest
lists. A replace replaces the table's data, schema and partitioning,
but is meant to keep its history.

As in apache#16943, the catalog's table builder passes the
transaction a function that builds the replacement from a table, and
when the table changed, the transaction rebuilds the replacement on the
refreshed table and applies its updates to it again, so the replace
keeps what the other writers committed, as it would had it begun after
them. Unlike apache#16943, which then commits the replacement as it began, a
replace whose rebuilt replacement would have another schema, partition
spec, sort order or format version, which the files it wrote depend on,
or whose updates don't apply again (a schema update commits once),
fails with CommitFailedException: committing it would drop the other
writers' changes.

Two racing replaces with the same definition still end as the second
built it, now keeping the first's snapshot in history. Two whose
schemas or sort orders differ make the second fail, so two CatalogTests
cases expect that except over REST, whose server applies a replace's
changes to the table as it is. A transaction built without the function
commits as before, still without snapshots the table no longer has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wombatu-kun and others added 4 commits October 31, 2026 17:40
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generated-by: Claude Code (claude-opus-5-5)
Generated-by: Claude Code (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wombatu-kun
wombatu-kun force-pushed the issue/16942-replace-concurrent-snapshots branch from 8037fda to 8c89ec2 Compare October 31, 2026 11:20
@wombatu-kun

Copy link
Copy Markdown
Contributor Author

@findepi you merged #18095 in this same cleanup code - could you take a look at this one? On metastore catalogs a replace transaction commits metadata built before a concurrent commit, so the other writer's snapshot drops out of history and an expired snapshot can come back (#16942, part of #16232, which RussellSpitzer called "a pretty serious issue"). The replacement is now rebuilt on the refreshed metadata, with a fallback to today's behavior when that isn't safe. It's rebased onto #18095.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

createOrReplace drops concurrent writers' snapshots on commit retry

2 participants