[LAKE-6732] Spark 3.5: refuse to rewrite a table with duplicate data file registrations - #6
Open
abrarsher23 wants to merge 1 commit into
Open
Conversation
…file registrations A data file registered at two data sequence numbers cannot be compacted safely. File identity in the rewrite path is keyed on location alone, so the two registrations are indistinguishable: the data side removes one of them while the delete side removes both corresponding delete-file registrations. The surviving data registration is then left with no delete file covering it and previously suppressed rows become visible. Adds validate-duplicate-file-registrations (default true), checked before planFileGroups so the action fails before making any commit.
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.
Problem
A data file registered at two data sequence numbers cannot be compacted safely. This is not
something a healthy writer produces — it arises when a commit is retried after its outcome became
unknown (
CommitStateUnknownException) and the retry re-registers aWriteResultthat had in factalready been applied server-side.
File identity in the rewrite path is keyed on location alone, and a file's data sequence number
lives on the manifest entry rather than on the
ContentFile, so the two registrations cannot betold apart:
RewriteFileGroup.rewrittenFiles()collects into aDataFileSetkeyed onlocation(). Two scan tasks for one path collapse to a singleDataFilecarrying a single
manifestLocation(),canTrustManifestReferencesstays true, and the othermanifest is never opened.
entriesmetadata table viaSparkDeleteFile;SparkContentFilenever overridesmanifestLocation(), so it returnsnull,allDeletesReferenceManifestsbecomes false, and every manifest is filtered.Net effect: the surviving data registration is left with no delete file covering it, and rows
that were correctly suppressed become visible as duplicates.
Observed in production. One physical file, 30 records, registered at seq 93949 and seq 93950.
rewrite_data_filesremoved only the 93949 registration;remove_dangling_deletesthen removedboth registrations of both its delete files — including a position delete its own test correctly
judged not dangling. 23 rows across 6 keys surfaced.
Change
Adds
validate-duplicate-file-registrations, defaulttrue, checked immediately aftervalidateAndInitOptions()and beforeplanFileGroups()so the action fails before making anycommit:
On a hit it throws
ValidationExceptionnaming up to 10 affected paths and pointing at the opt-out.Cost is one scan of the entries table projecting two columns — cheaper than the two
RemoveDanglingDeletesSparkActionalready performs.Design notes
correct behaviour. Scheduled compaction will fail loudly for an affected table; that is intended.
validate-duplicate-file-registrations=false, for compacting such atable deliberately.
Relationship to #4
Complementary, not overlapping. #4 makes
remove_dangling_deleteserr safe by retaining any deletefile attached to a live
FileScanTask, which holds the damage at 2 copies per key instead of 7. Itdoes not prevent the initial doubling, which happens in
rewrite_data_filesbefore the danglingaction runs. This PR stops the rewrite from starting at all.
Testing
TestRewriteDataFilesAction:testRejectsDuplicateDataFileRegistrations— re-appends an already-liveDataFileto produce agenuine second registration, asserts
ValidationExceptionnaming the path.testDuplicateDataFileRegistrationCheckCanBeDisabled— opt-out still runs.testAcceptsTableWithoutDuplicateRegistrations— no regression on a clean table.Upstream
Not fixed upstream.
apache/iceberg#15727is open and unmerged, and the same location-keyedidentity is present at 1.9.0, 1.10.0 and
main. A version bump does not address this. Worth filingupstream separately — the durable fix is keying file identity on
(location, data_sequence_number), which requires plumbing the manifest entry's sequence numberinto the identity.