Repository navigation
Core: copy ByteBuffers when copying GenericRecord (cherry-pick apache/iceberg#12855) - #16
Closed
abrarsher23 wants to merge 7 commits into
Closed
abrarsher23 wants to merge 7 commits into
abrarsher23 wants to merge 7 commits into
Conversation
(cherry picked from commit a7f3dc7)
Adds version.txt (1.8.1-PATCH.4) and an AFFIRM_VERSIONS.md changelog for the 1.8.1 line, following the convention now used on 1.11.0-affirm-patch. PATCH.1 and PATCH.3 were built from an uncommitted version.txt; their contents are recorded from branch history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
|
Superseded by #18 (same commits, renamed branch). |
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.
What
Straight
git cherry-pick -xof apache/iceberga7f3dc79a2f42a4875ac35eec2137ecff15204fc("Core: Copy ByteBuffers when Copying GenericRecord", PR apache#12855), the fix for
apache/iceberg#11239. One production file,
+16/-1; the other three files are the upstream regression tests that ship with the commit.
No conflicts, no adaptation.
The follow-on commits are release plumbing only:
version.txt(1.8.1-PATCH.4), anAFFIRM_VERSIONS.mdfor the1.8.1 line (backfilled with PATCH.1 / PATCH.3) following the convention on
1.11.0-affirm-patch, and the matchingdev/.rat-excludesentry. After merge I will tag1.8.1-PATCH.4at the merge sha (the first tag on this line).Why
BaseDeleteLoaderopens equality-delete files withreuseContainers()(
data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java:245) and relies onRecord::copyat:131to detach each record before building theStructLikeSetat:114.At 1.8.1 that copy is shallow (
Arrays.copyOfover the value array), so for a binary columnevery copied record still points at the single
ByteBufferthatParquetValueReaders$BytesReaderreuses — and which, by the end of the file, holds the last record's bytes. The set collapses to
one effective key per delete file and every other delete in that file is silently dropped.
Two consequences for tables whose equality key includes a binary column:
the same reader makes those duplicates permanent;
producing keys no delete targeted, so live rows can be hidden. This is a silent data-loss fix, not only a
dedup fix.
Verification
Unit tests (local, JDK 17, Gradle 8.12.1)
./gradlew :iceberg-data:test— 602 tests, 0 failures, 0 errors, 58 skipped.TestGenericRecord: 4/4 incl. the newtestDeepCopyValues().TestGenericReaderDeletes: 44 tests, 0 failures, 1 pre-existing skip.GenericRecord.javawhile keeping the new tests reproduces thebug — 8 failures in
TestGenericReaderDeletes(binary + struct equality-delete cases, all three fileformats) and
testDeepCopyValuesfails withExpected not same: java.nio.HeapByteBuffer[pos=0 lim=12 cap=12].Integration test (real tables, same snapshots, before vs after)
The running JVM reports
Apache Iceberg 1.8.1-PATCH.4at this branch's head commit.1.8.1-PATCH.3, so the data and delete files were identical and only the reader changed.1.8.1-PATCH.3those reads returned duplicate keys; with this patch the duplicates that the table'sequality deletes should suppress are gone. The results match an independent merge-on-read computed from the
same files, on every table checked.
compaction) are unchanged, as expected: a reader fix does not repair history.
Notes for the reviewer
:iceberg-core:spotlessJavaCheckalready fails on1.8.1-affirm-patchforExponentialHttpRequestRetryStrategy.java,TestExponentialHttpRequestRetryStrategy.javaandTestRESTCatalog.java(from Prevent Retries 5xx Errors for Non-Idempotent Requests #1). Identical at the base commit; untouched here; deliberately nospotlessApply.core-tests/kafka-connect-testsfail onpull access denied for minio/minio(Docker Hub), same as on [LAKE-6732] Spark 3.5: refuse to rewrite a table with duplicate data file registrations #6.The 1.11 line fixed this with Build: Pull MinIO images from Quay (cherry-pick apache/iceberg#18071) #11 (Quay images); a separate port to this line would green it.
ByteBufferallocation per equality-delete row loadedfor binary columns. Not benchmarked; worth knowing for a very wide binary-heavy table.
GenericRecord(GenericRecord, Map<String,Object> overwrite)overload is stillArrays.copyOf.BaseDeleteLoaderuses the no-argRecord::copy, so the delete path is fixed; callers ofcopy(overwriteValues)on a binary field are not. Same on1.11.0-affirm-patch.1.11.0-affirm-patchalready contains this fix (1.10.0+), so this commit disappears on a rebase to that base.It is deliberately a stopgap for the 1.8.1 line.
Change Management
What changes: the Spark reader/compaction path picks up
1.8.1-PATCH.4=1.8.1-PATCH.3+ this one commit.No API, file-format or table-metadata change.
Risk: Low–Medium. One upstream commit with its own regression tests, validated before/after on real tables.
The behavioural change is confined to
GenericRecord.copy()forByteBufferand nested-record values; all othervalues keep identical references. Main risk is the manual jar → Spark package release path, mitigated by a dev-build
dry run that was deployed and exercised before this PR.
Rollback: re-pin the downstream package to the previous build (
1.8.1-PATCH.3). Nothing is persisted in anew format, so a rolled-back reader simply resumes the old behaviour.
Testing: unit tests + negative control + before/after integration read (above).
Deployment order: merge → tag
1.8.1-PATCH.4→ build + publish the release package → downstream version bump(separate PR) → deploy.