-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Core: Fix row lineage last updated sequence inheritance #17039
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
78e103a
6a6f812
a489551
8fe315a
da082da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,12 +26,14 @@ | |
| import java.io.UncheckedIOException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import org.apache.iceberg.data.Record; | ||
| import org.apache.iceberg.io.CloseableIterable; | ||
| import org.apache.iceberg.io.InputFile; | ||
| import org.apache.iceberg.relocated.com.google.common.collect.Iterables; | ||
| import org.apache.iceberg.types.Types; | ||
| import org.apache.iceberg.types.Types.NestedField; | ||
| import org.apache.iceberg.util.PartitionUtil; | ||
| import org.junit.jupiter.api.AfterEach; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
@@ -722,6 +724,45 @@ public void testRowDeltaAssignmentAfterUpgrade(@TempDir File altLocation) { | |
| assertThat(manifests.get(1).path()).isEqualTo(existingManifests.get(1).path()); | ||
| } | ||
|
|
||
| @Test | ||
| public void lastUpdatedAfterUpgrade(@TempDir File altLocation) throws IOException { | ||
| BaseTable upgradeTable = | ||
| TestTables.create(altLocation, "test_upgrade", SCHEMA, PartitionSpec.unpartitioned(), 2); | ||
|
|
||
| upgradeTable.newAppend().appendFile(FILE_A).commit(); | ||
| Snapshot originalSnapshot = upgradeTable.currentSnapshot(); | ||
| long originalSequenceNumber = originalSnapshot.sequenceNumber(); | ||
|
|
||
| upgradeTable | ||
| .newRewrite() | ||
| .validateFromSnapshot(originalSnapshot.snapshotId()) | ||
| .rewriteFiles(Set.of(FILE_A), Set.of(FILE_B), originalSequenceNumber) | ||
| .commit(); | ||
|
|
||
| TestTables.upgrade(altLocation, "test_upgrade", 3); | ||
| upgradeTable.refresh(); | ||
|
|
||
| // Assign row IDs to the upgraded metadata tree without rewriting the data file. | ||
| upgradeTable.newFastAppend().commit(); | ||
|
|
||
| try (CloseableIterable<FileScanTask> tasks = upgradeTable.newScan().planFiles()) { | ||
| FileScanTask task = Iterables.getOnlyElement(tasks); | ||
|
|
||
| assertThat(task.file().location()).isEqualTo(FILE_B.location()); | ||
| assertThat(task.file().dataSequenceNumber()).isEqualTo(originalSequenceNumber); | ||
| assertThat(task.file().fileSequenceNumber()).isGreaterThan(originalSequenceNumber); | ||
| assertThat(task.file().firstRowId()).isNotNull(); | ||
|
|
||
| // Scan planning projects row lineage metadata columns through constantsMap. | ||
| // The upgraded data file is not rewritten, so validate the value readers see. | ||
| assertThat( | ||
| PartitionUtil.constantsMap(task) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is a bit strange in these tests to have inspect the constantsMap but I get it because the sequence number is inherited metadata and not present on any of the in memory representations available. Maybe just an inline comment? |
||
| .get(MetadataColumns.LAST_UPDATED_SEQUENCE_NUMBER.fieldId())) | ||
| .as("Last updated should preserve the original data sequence after upgrade") | ||
| .isEqualTo(originalSequenceNumber); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testUpgradeAssignmentWithManifestCompaction(@TempDir File altLocation) { | ||
| // create a non-empty upgrade table with FILE_A | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2069,6 +2069,49 @@ public void testUnpartitionedRewriteDataFilesPreservesLineage() throws NoSuchTab | |
| assertEquals("Rows must match", expectedRecordsWithLineage, actualRecordsWithLineage); | ||
| } | ||
|
|
||
| @TestTemplate | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this looks right but I'd cleanup the empty append and do a more realistic write, I'd also just use an explicit assertion on the records (just a bit more readable/less opaque)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to keep your test name as is, just what i had locally
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually my test is arguably a bit brittle to how we organize the manifests in the manifest list, today it works but if there's a reordering the test would fail needlessly since the first row ID assignment would be different but still valid. Maybe we should key off a logical row to make it more resilient (but it becomes a bit more complex)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok here's a more minimal test I came up with so we don't even have to append any records. We can just do a compact + upgrade + rewrite manifests to move the new file into a single v3 manifest. since there's a single data file/single manifest we can then reliably assert the row IDs regardless of any change in the implementation.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed according to your last comment. |
||
| public void testUpgradePreservesDataSequence() throws NoSuchTableException { | ||
| assumeThat(formatVersion).isEqualTo(2); | ||
|
|
||
| Table table = createTable(); | ||
| writeRecords(2, 4); | ||
| table.refresh(); | ||
| shouldHaveFiles(table, 2); | ||
| long committedDataSequence = table.currentSnapshot().sequenceNumber(); | ||
|
|
||
| Result result = basicRewrite(table).execute(); | ||
| assertThat(result.rewrittenDataFilesCount()).isEqualTo(2); | ||
| assertThat(result.addedDataFilesCount()).isOne(); | ||
| table.refresh(); | ||
| shouldHaveFiles(table, 1); | ||
|
|
||
| DataFile compactedFile = Iterables.getOnlyElement(currentDataFiles(table)); | ||
| long dataSequenceNumber = compactedFile.dataSequenceNumber(); | ||
| assertThat(dataSequenceNumber) | ||
| .as("Compaction must preserve the original data sequence number") | ||
| .isEqualTo(committedDataSequence); | ||
| assertThat(compactedFile.fileSequenceNumber()) | ||
| .as("Compaction must bump the file sequence above the preserved data sequence") | ||
| .isGreaterThan(dataSequenceNumber); | ||
|
|
||
| table.updateProperties().set(TableProperties.FORMAT_VERSION, "3").commit(); | ||
| table.rewriteManifests().rewriteIf(manifest -> true).commit(); | ||
| table.refresh(); | ||
|
|
||
| List<Object[]> expectedLineage = | ||
| Lists.newArrayList( | ||
| row(0L, committedDataSequence, ANY, ANY, ANY), | ||
| row(1L, committedDataSequence, ANY, ANY, ANY), | ||
| row(2L, committedDataSequence, ANY, ANY, ANY), | ||
| row(3L, committedDataSequence, ANY, ANY, ANY)); | ||
|
|
||
| assertEquals( | ||
| "First snapshot after upgrade to v3 assigns row IDs and inherits the committed data" | ||
| + " sequence as _last_updated_sequence_number", | ||
| expectedLineage, | ||
| currentDataWithLineage()); | ||
| } | ||
|
|
||
| @TestTemplate | ||
| public void testRewriteDataFilesPreservesLineage() throws NoSuchTableException { | ||
| assumeThat(formatVersion).isGreaterThan(2); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
testLastUpdatedDataSequencePreservedAfterUpgrade? I think we should still prefix with test in this class to be consistent.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we agreed we would no longer be restrained by the sins of our past :)
More seriously I did think we decided we were doing updates for new code. Just trying not to blanket modify everything when it doesn't matter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it, in that case i'm good with how it is!