This is an automated email from the ASF dual-hosted git repository.
stevenzwu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new 01cf810cd0 Core: Add modified file and row counts to ManifestInfo
(#18212)
01cf810cd0 is described below
commit 01cf810cd096fb5ff94e165a8bcb5ae161e7aea8
Author: Steven Zhen Wu <[email protected]>
AuthorDate: Mon Sep 28 16:31:37 2026 -0700
Core: Add modified file and row counts to ManifestInfo (#18212)
* Core: Add modified file and row counts to ManifestInfo
The v4 AMT entry-structure spec gives MODIFIED its own
modified_files_count (524) and modified_rows_count (525) fields.
---
.../main/java/org/apache/iceberg/ManifestInfo.java | 18 ++-
.../org/apache/iceberg/ManifestInfoStruct.java | 79 ++++++++++--
.../org/apache/iceberg/TestManifestInfoStruct.java | 137 ++++++++++++++++++++-
.../apache/iceberg/TestTrackedFileAdapters.java | 2 +
.../org/apache/iceberg/TestV4ManifestReader.java | 2 +-
.../java/org/apache/iceberg/V4TestComparators.java | 2 +
6 files changed, 225 insertions(+), 15 deletions(-)
diff --git a/core/src/main/java/org/apache/iceberg/ManifestInfo.java
b/core/src/main/java/org/apache/iceberg/ManifestInfo.java
index 04351e2afd..c41a008526 100644
--- a/core/src/main/java/org/apache/iceberg/ManifestInfo.java
+++ b/core/src/main/java/org/apache/iceberg/ManifestInfo.java
@@ -33,7 +33,10 @@ interface ManifestInfo {
506, "deleted_files_count", Types.IntegerType.get(), "Number of
deleted files");
Types.NestedField REPLACED_FILES_COUNT =
Types.NestedField.required(
- 520, "replaced_files_count", Types.IntegerType.get(), "Number of
replaced files");
+ 523, "replaced_files_count", Types.IntegerType.get(), "Number of
replaced files");
+ Types.NestedField MODIFIED_FILES_COUNT =
+ Types.NestedField.required(
+ 525, "modified_files_count", Types.IntegerType.get(), "Number of
modified files");
Types.NestedField ADDED_ROWS_COUNT =
Types.NestedField.required(
512, "added_rows_count", Types.LongType.get(), "Number of rows in
added files");
@@ -45,7 +48,10 @@ interface ManifestInfo {
514, "deleted_rows_count", Types.LongType.get(), "Number of rows in
deleted files");
Types.NestedField REPLACED_ROWS_COUNT =
Types.NestedField.required(
- 521, "replaced_rows_count", Types.LongType.get(), "Number of rows in
replaced files");
+ 524, "replaced_rows_count", Types.LongType.get(), "Number of rows in
replaced files");
+ Types.NestedField MODIFIED_ROWS_COUNT =
+ Types.NestedField.required(
+ 526, "modified_rows_count", Types.LongType.get(), "Number of rows in
modified files");
Types.NestedField MIN_SEQUENCE_NUMBER =
Types.NestedField.required(
516,
@@ -62,10 +68,12 @@ interface ManifestInfo {
EXISTING_FILES_COUNT,
DELETED_FILES_COUNT,
REPLACED_FILES_COUNT,
+ MODIFIED_FILES_COUNT,
ADDED_ROWS_COUNT,
EXISTING_ROWS_COUNT,
DELETED_ROWS_COUNT,
REPLACED_ROWS_COUNT,
+ MODIFIED_ROWS_COUNT,
MIN_SEQUENCE_NUMBER,
DV);
}
@@ -82,6 +90,9 @@ interface ManifestInfo {
/** Returns the number of replaced files in this manifest. */
int replacedFilesCount();
+ /** Returns the number of modified files in this manifest. */
+ int modifiedFilesCount();
+
/** Returns the number of rows in added files. */
long addedRowsCount();
@@ -94,6 +105,9 @@ interface ManifestInfo {
/** Returns the number of rows in replaced files. */
long replacedRowsCount();
+ /** Returns the number of rows in modified files. */
+ long modifiedRowsCount();
+
/** Returns the minimum sequence number of files in this manifest. */
long minSequenceNumber();
diff --git a/core/src/main/java/org/apache/iceberg/ManifestInfoStruct.java
b/core/src/main/java/org/apache/iceberg/ManifestInfoStruct.java
index b37c3edf7f..26a2fcef76 100644
--- a/core/src/main/java/org/apache/iceberg/ManifestInfoStruct.java
+++ b/core/src/main/java/org/apache/iceberg/ManifestInfoStruct.java
@@ -36,10 +36,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
ManifestInfo.EXISTING_FILES_COUNT,
ManifestInfo.DELETED_FILES_COUNT,
ManifestInfo.REPLACED_FILES_COUNT,
+ ManifestInfo.MODIFIED_FILES_COUNT,
ManifestInfo.ADDED_ROWS_COUNT,
ManifestInfo.EXISTING_ROWS_COUNT,
ManifestInfo.DELETED_ROWS_COUNT,
ManifestInfo.REPLACED_ROWS_COUNT,
+ ManifestInfo.MODIFIED_ROWS_COUNT,
ManifestInfo.MIN_SEQUENCE_NUMBER,
ManifestInfo.DV);
@@ -47,10 +49,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
private int existingFilesCount = -1;
private int deletedFilesCount = -1;
private int replacedFilesCount = -1;
+ private int modifiedFilesCount = -1;
private long addedRowsCount = -1L;
private long existingRowsCount = -1L;
private long deletedRowsCount = -1L;
private long replacedRowsCount = -1L;
+ private long modifiedRowsCount = -1L;
private long minSequenceNumber = -1L;
private byte[] dv = null;
@@ -66,10 +70,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
this.existingFilesCount = toCopy.existingFilesCount;
this.deletedFilesCount = toCopy.deletedFilesCount;
this.replacedFilesCount = toCopy.replacedFilesCount;
+ this.modifiedFilesCount = toCopy.modifiedFilesCount;
this.addedRowsCount = toCopy.addedRowsCount;
this.existingRowsCount = toCopy.existingRowsCount;
this.deletedRowsCount = toCopy.deletedRowsCount;
this.replacedRowsCount = toCopy.replacedRowsCount;
+ this.modifiedRowsCount = toCopy.modifiedRowsCount;
this.minSequenceNumber = toCopy.minSequenceNumber;
this.dv = toCopy.dv != null ? Arrays.copyOf(toCopy.dv, toCopy.dv.length) :
null;
}
@@ -79,10 +85,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
int existingFilesCount,
int deletedFilesCount,
int replacedFilesCount,
+ int modifiedFilesCount,
long addedRowsCount,
long existingRowsCount,
long deletedRowsCount,
long replacedRowsCount,
+ long modifiedRowsCount,
long minSequenceNumber,
byte[] dv) {
super(BASE_TYPE.fields().size());
@@ -90,10 +98,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
this.existingFilesCount = existingFilesCount;
this.deletedFilesCount = deletedFilesCount;
this.replacedFilesCount = replacedFilesCount;
+ this.modifiedFilesCount = modifiedFilesCount;
this.addedRowsCount = addedRowsCount;
this.existingRowsCount = existingRowsCount;
this.deletedRowsCount = deletedRowsCount;
this.replacedRowsCount = replacedRowsCount;
+ this.modifiedRowsCount = modifiedRowsCount;
this.minSequenceNumber = minSequenceNumber;
this.dv = dv;
}
@@ -118,6 +128,11 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
return replacedFilesCount;
}
+ @Override
+ public int modifiedFilesCount() {
+ return modifiedFilesCount;
+ }
+
@Override
public long addedRowsCount() {
return addedRowsCount;
@@ -138,6 +153,11 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
return replacedRowsCount;
}
+ @Override
+ public long modifiedRowsCount() {
+ return modifiedRowsCount;
+ }
+
@Override
public long minSequenceNumber() {
return minSequenceNumber;
@@ -173,16 +193,20 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
case 3:
return replacedFilesCount;
case 4:
- return addedRowsCount;
+ return modifiedFilesCount;
case 5:
- return existingRowsCount;
+ return addedRowsCount;
case 6:
- return deletedRowsCount;
+ return existingRowsCount;
case 7:
- return replacedRowsCount;
+ return deletedRowsCount;
case 8:
- return minSequenceNumber;
+ return replacedRowsCount;
case 9:
+ return modifiedRowsCount;
+ case 10:
+ return minSequenceNumber;
+ case 11:
return dv != null ? ByteBuffer.wrap(dv) : null;
default:
throw new UnsupportedOperationException("Unknown field ordinal: " +
pos);
@@ -205,21 +229,27 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
this.replacedFilesCount = (Integer) value;
break;
case 4:
- this.addedRowsCount = (Long) value;
+ this.modifiedFilesCount = (Integer) value;
break;
case 5:
- this.existingRowsCount = (Long) value;
+ this.addedRowsCount = (Long) value;
break;
case 6:
- this.deletedRowsCount = (Long) value;
+ this.existingRowsCount = (Long) value;
break;
case 7:
- this.replacedRowsCount = (Long) value;
+ this.deletedRowsCount = (Long) value;
break;
case 8:
- this.minSequenceNumber = (Long) value;
+ this.replacedRowsCount = (Long) value;
break;
case 9:
+ this.modifiedRowsCount = (Long) value;
+ break;
+ case 10:
+ this.minSequenceNumber = (Long) value;
+ break;
+ case 11:
this.dv = ByteBuffers.toByteArray((ByteBuffer) value);
this.mdv = null;
break;
@@ -239,10 +269,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
.add("existing_files_count", existingFilesCount)
.add("deleted_files_count", deletedFilesCount)
.add("replaced_files_count", replacedFilesCount)
+ .add("modified_files_count", modifiedFilesCount)
.add("added_rows_count", addedRowsCount)
.add("existing_rows_count", existingRowsCount)
.add("deleted_rows_count", deletedRowsCount)
.add("replaced_rows_count", replacedRowsCount)
+ .add("modified_rows_count", modifiedRowsCount)
.add("min_sequence_number", minSequenceNumber)
.add("dv", dv == null ? "null" : "(binary)")
.toString();
@@ -253,10 +285,12 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
private Integer existingFilesCount = null;
private Integer deletedFilesCount = null;
private Integer replacedFilesCount = null;
+ private Integer modifiedFilesCount = null;
private Long addedRowsCount = null;
private Long existingRowsCount = null;
private Long deletedRowsCount = null;
private Long replacedRowsCount = null;
+ private Long modifiedRowsCount = null;
private Long minSequenceNumber = null;
private byte[] dv = null;
@@ -288,6 +322,13 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
return this;
}
+ Builder modifiedFilesCount(int count) {
+ Preconditions.checkArgument(
+ count >= 0, "Invalid modified files count: %s (must be >= 0)",
count);
+ this.modifiedFilesCount = count;
+ return this;
+ }
+
Builder addedRowsCount(long count) {
Preconditions.checkArgument(count >= 0, "Invalid added rows count: %s
(must be >= 0)", count);
this.addedRowsCount = count;
@@ -315,6 +356,13 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
return this;
}
+ Builder modifiedRowsCount(long count) {
+ Preconditions.checkArgument(
+ count >= 0, "Invalid modified rows count: %s (must be >= 0)", count);
+ this.modifiedRowsCount = count;
+ return this;
+ }
+
Builder minSequenceNumber(long sequenceNumber) {
Preconditions.checkArgument(
sequenceNumber >= 0, "Invalid min sequence number: %s (must be >=
0)", sequenceNumber);
@@ -337,6 +385,8 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
deletedFilesCount != null, "Missing required value: deleted files
count");
Preconditions.checkArgument(
replacedFilesCount != null, "Missing required value: replaced files
count");
+ Preconditions.checkArgument(
+ modifiedFilesCount != null, "Missing required value: modified files
count");
Preconditions.checkArgument(
addedRowsCount != null, "Missing required value: added rows count");
Preconditions.checkArgument(
@@ -345,6 +395,8 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
deletedRowsCount != null, "Missing required value: deleted rows
count");
Preconditions.checkArgument(
replacedRowsCount != null, "Missing required value: replaced rows
count");
+ Preconditions.checkArgument(
+ modifiedRowsCount != null, "Missing required value: modified rows
count");
Preconditions.checkArgument(
minSequenceNumber != null, "Missing required value: min sequence
number");
Preconditions.checkArgument(
@@ -367,15 +419,22 @@ class ManifestInfoStruct extends SupportsIndexProjection
implements ManifestInfo
"Invalid replaced counts: %s rows in %s files",
replacedRowsCount,
replacedFilesCount);
+ Preconditions.checkArgument(
+ modifiedRowsCount == 0 || modifiedFilesCount > 0,
+ "Invalid modified counts: %s rows in %s files",
+ modifiedRowsCount,
+ modifiedFilesCount);
return new ManifestInfoStruct(
addedFilesCount,
existingFilesCount,
deletedFilesCount,
replacedFilesCount,
+ modifiedFilesCount,
addedRowsCount,
existingRowsCount,
deletedRowsCount,
replacedRowsCount,
+ modifiedRowsCount,
minSequenceNumber,
dv);
}
diff --git a/core/src/test/java/org/apache/iceberg/TestManifestInfoStruct.java
b/core/src/test/java/org/apache/iceberg/TestManifestInfoStruct.java
index cc9710db04..1892f2d890 100644
--- a/core/src/test/java/org/apache/iceberg/TestManifestInfoStruct.java
+++ b/core/src/test/java/org/apache/iceberg/TestManifestInfoStruct.java
@@ -33,16 +33,29 @@ class TestManifestInfoStruct {
void fieldAccess() {
ManifestInfoStruct info =
new ManifestInfoStruct(
- 10, 20, 3, 2, 1000L, 2000L, 300L, 200L, 5L,
MumblingTestUtil.onlyFirstBitSetBytes());
+ 10,
+ 20,
+ 3,
+ 2,
+ 1,
+ 1000L,
+ 2000L,
+ 300L,
+ 200L,
+ 100L,
+ 5L,
+ MumblingTestUtil.onlyFirstBitSetBytes());
assertThat(info.addedFilesCount()).isEqualTo(10);
assertThat(info.existingFilesCount()).isEqualTo(20);
assertThat(info.deletedFilesCount()).isEqualTo(3);
assertThat(info.replacedFilesCount()).isEqualTo(2);
+ assertThat(info.modifiedFilesCount()).isEqualTo(1);
assertThat(info.addedRowsCount()).isEqualTo(1000L);
assertThat(info.existingRowsCount()).isEqualTo(2000L);
assertThat(info.deletedRowsCount()).isEqualTo(300L);
assertThat(info.replacedRowsCount()).isEqualTo(200L);
+ assertThat(info.modifiedRowsCount()).isEqualTo(100L);
assertThat(info.minSequenceNumber()).isEqualTo(5L);
assertThat(info.manifestDeletionVector().buffer())
.isEqualTo(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()));
@@ -57,10 +70,12 @@ class TestManifestInfoStruct {
.existingFilesCount(20)
.deletedFilesCount(3)
.replacedFilesCount(2)
+ .modifiedFilesCount(1)
.addedRowsCount(1000L)
.existingRowsCount(2000L)
.deletedRowsCount(300L)
.replacedRowsCount(200L)
+ .modifiedRowsCount(100L)
.minSequenceNumber(5L)
.dv(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()))
.build();
@@ -71,10 +86,12 @@ class TestManifestInfoStruct {
assertThat(copy.existingFilesCount()).isEqualTo(20);
assertThat(copy.deletedFilesCount()).isEqualTo(3);
assertThat(copy.replacedFilesCount()).isEqualTo(2);
+ assertThat(copy.modifiedFilesCount()).isEqualTo(1);
assertThat(copy.addedRowsCount()).isEqualTo(1000L);
assertThat(copy.existingRowsCount()).isEqualTo(2000L);
assertThat(copy.deletedRowsCount()).isEqualTo(300L);
assertThat(copy.replacedRowsCount()).isEqualTo(200L);
+ assertThat(copy.modifiedRowsCount()).isEqualTo(100L);
assertThat(copy.minSequenceNumber()).isEqualTo(5L);
// verify deep copy of dv byte array
@@ -90,10 +107,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build();
@@ -110,7 +129,7 @@ class TestManifestInfoStruct {
assertThat(info.size()).isEqualTo(2);
// projected position 0 maps to internal position 0 (added_files_count)
- // projected position 1 maps to internal position 8 (min_sequence_number)
+ // projected position 1 maps to internal position 10 (min_sequence_number)
info.set(0, 10);
info.set(1, 5L);
@@ -128,10 +147,12 @@ class TestManifestInfoStruct {
.existingFilesCount(20)
.deletedFilesCount(3)
.replacedFilesCount(2)
+ .modifiedFilesCount(1)
.addedRowsCount(1000L)
.existingRowsCount(2000L)
.deletedRowsCount(300L)
.replacedRowsCount(200L)
+ .modifiedRowsCount(100L)
.minSequenceNumber(5L)
.dv(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()))
.build();
@@ -145,10 +166,12 @@ class TestManifestInfoStruct {
assertThat(info.existingFilesCount()).isEqualTo(20);
assertThat(info.deletedFilesCount()).isEqualTo(3);
assertThat(info.replacedFilesCount()).isEqualTo(2);
+ assertThat(info.modifiedFilesCount()).isEqualTo(1);
assertThat(info.addedRowsCount()).isEqualTo(1000L);
assertThat(info.existingRowsCount()).isEqualTo(2000L);
assertThat(info.deletedRowsCount()).isEqualTo(300L);
assertThat(info.replacedRowsCount()).isEqualTo(200L);
+ assertThat(info.modifiedRowsCount()).isEqualTo(100L);
assertThat(info.minSequenceNumber()).isEqualTo(5L);
assertThat(info.manifestDeletionVector()).isSameAs(mdv);
}
@@ -161,10 +184,12 @@ class TestManifestInfoStruct {
.existingFilesCount(20)
.deletedFilesCount(3)
.replacedFilesCount(2)
+ .modifiedFilesCount(1)
.addedRowsCount(1000L)
.existingRowsCount(2000L)
.deletedRowsCount(300L)
.replacedRowsCount(200L)
+ .modifiedRowsCount(100L)
.minSequenceNumber(5L)
.dv(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()))
.build();
@@ -175,10 +200,12 @@ class TestManifestInfoStruct {
assertThat(deserialized.existingFilesCount()).isEqualTo(20);
assertThat(deserialized.deletedFilesCount()).isEqualTo(3);
assertThat(deserialized.replacedFilesCount()).isEqualTo(2);
+ assertThat(deserialized.modifiedFilesCount()).isEqualTo(1);
assertThat(deserialized.addedRowsCount()).isEqualTo(1000L);
assertThat(deserialized.existingRowsCount()).isEqualTo(2000L);
assertThat(deserialized.deletedRowsCount()).isEqualTo(300L);
assertThat(deserialized.replacedRowsCount()).isEqualTo(200L);
+ assertThat(deserialized.modifiedRowsCount()).isEqualTo(100L);
assertThat(deserialized.minSequenceNumber()).isEqualTo(5L);
assertThat(deserialized.manifestDeletionVector().buffer())
.isEqualTo(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()));
@@ -192,10 +219,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -210,10 +239,12 @@ class TestManifestInfoStruct {
.addedFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -228,10 +259,12 @@ class TestManifestInfoStruct {
.addedFilesCount(0)
.existingFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -246,10 +279,12 @@ class TestManifestInfoStruct {
.addedFilesCount(0)
.existingFilesCount(0)
.deletedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -265,9 +300,11 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -283,9 +320,11 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -301,9 +340,11 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -319,15 +360,57 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Missing required value: replaced rows count");
}
+ @Test
+ void builderMissingModifiedFilesCount() {
+ assertThatThrownBy(
+ () ->
+ ManifestInfoStruct.builder()
+ .addedFilesCount(0)
+ .existingFilesCount(0)
+ .deletedFilesCount(0)
+ .replacedFilesCount(0)
+ .addedRowsCount(0L)
+ .existingRowsCount(0L)
+ .deletedRowsCount(0L)
+ .replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
+ .minSequenceNumber(0L)
+ .build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Missing required value: modified files count");
+ }
+
+ @Test
+ void builderMissingModifiedRowsCount() {
+ assertThatThrownBy(
+ () ->
+ ManifestInfoStruct.builder()
+ .addedFilesCount(0)
+ .existingFilesCount(0)
+ .deletedFilesCount(0)
+ .replacedFilesCount(0)
+ .modifiedFilesCount(0)
+ .addedRowsCount(0L)
+ .existingRowsCount(0L)
+ .deletedRowsCount(0L)
+ .replacedRowsCount(0L)
+ .minSequenceNumber(0L)
+ .build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Missing required value: modified rows count");
+ }
+
@Test
void builderMissingMinSequenceNumber() {
assertThatThrownBy(
@@ -337,10 +420,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Missing required value: min sequence number");
@@ -374,6 +459,13 @@ class TestManifestInfoStruct {
.hasMessage("Invalid replaced files count: -1 (must be >= 0)");
}
+ @Test
+ void builderRejectsNegativeModifiedFilesCount() {
+ assertThatThrownBy(() ->
ManifestInfoStruct.builder().modifiedFilesCount(-1))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid modified files count: -1 (must be >= 0)");
+ }
+
@Test
void builderRejectsNegativeAddedRowsCount() {
assertThatThrownBy(() -> ManifestInfoStruct.builder().addedRowsCount(-1L))
@@ -402,6 +494,13 @@ class TestManifestInfoStruct {
.hasMessage("Invalid replaced rows count: -1 (must be >= 0)");
}
+ @Test
+ void builderRejectsNegativeModifiedRowsCount() {
+ assertThatThrownBy(() ->
ManifestInfoStruct.builder().modifiedRowsCount(-1L))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid modified rows count: -1 (must be >= 0)");
+ }
+
@Test
void builderRejectsNegativeMinSequenceNumber() {
assertThatThrownBy(() ->
ManifestInfoStruct.builder().minSequenceNumber(-1L))
@@ -418,10 +517,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(10L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -434,10 +535,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(5L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -450,10 +553,12 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(3L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
@@ -466,14 +571,34 @@ class TestManifestInfoStruct {
.existingFilesCount(0)
.deletedFilesCount(0)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(7L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid replaced counts: 7 rows in 0 files");
+
+ assertThatThrownBy(
+ () ->
+ ManifestInfoStruct.builder()
+ .addedFilesCount(0)
+ .existingFilesCount(0)
+ .deletedFilesCount(0)
+ .replacedFilesCount(0)
+ .modifiedFilesCount(0)
+ .addedRowsCount(0L)
+ .existingRowsCount(0L)
+ .deletedRowsCount(0L)
+ .replacedRowsCount(0L)
+ .modifiedRowsCount(4L)
+ .minSequenceNumber(0L)
+ .build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid modified counts: 4 rows in 0 files");
}
@Test
@@ -484,10 +609,12 @@ class TestManifestInfoStruct {
.existingFilesCount(5)
.deletedFilesCount(5)
.replacedFilesCount(5)
+ .modifiedFilesCount(5)
.addedRowsCount(0L)
.existingRowsCount(0L)
.deletedRowsCount(0L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(0L)
.build();
@@ -495,10 +622,12 @@ class TestManifestInfoStruct {
assertThat(info.existingFilesCount()).isEqualTo(5);
assertThat(info.deletedFilesCount()).isEqualTo(5);
assertThat(info.replacedFilesCount()).isEqualTo(5);
+ assertThat(info.modifiedFilesCount()).isEqualTo(5);
assertThat(info.addedRowsCount()).isEqualTo(0L);
assertThat(info.existingRowsCount()).isEqualTo(0L);
assertThat(info.deletedRowsCount()).isEqualTo(0L);
assertThat(info.replacedRowsCount()).isEqualTo(0L);
+ assertThat(info.modifiedRowsCount()).isEqualTo(0L);
}
@Test
@@ -509,10 +638,12 @@ class TestManifestInfoStruct {
.existingFilesCount(20)
.deletedFilesCount(3)
.replacedFilesCount(2)
+ .modifiedFilesCount(1)
.addedRowsCount(1000L)
.existingRowsCount(2000L)
.deletedRowsCount(300L)
.replacedRowsCount(200L)
+ .modifiedRowsCount(100L)
.minSequenceNumber(5L)
.dv(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()))
.build();
@@ -523,10 +654,12 @@ class TestManifestInfoStruct {
assertThat(deserialized.existingFilesCount()).isEqualTo(20);
assertThat(deserialized.deletedFilesCount()).isEqualTo(3);
assertThat(deserialized.replacedFilesCount()).isEqualTo(2);
+ assertThat(deserialized.modifiedFilesCount()).isEqualTo(1);
assertThat(deserialized.addedRowsCount()).isEqualTo(1000L);
assertThat(deserialized.existingRowsCount()).isEqualTo(2000L);
assertThat(deserialized.deletedRowsCount()).isEqualTo(300L);
assertThat(deserialized.replacedRowsCount()).isEqualTo(200L);
+ assertThat(deserialized.modifiedRowsCount()).isEqualTo(100L);
assertThat(deserialized.minSequenceNumber()).isEqualTo(5L);
assertThat(deserialized.manifestDeletionVector().buffer())
.isEqualTo(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()));
diff --git a/core/src/test/java/org/apache/iceberg/TestTrackedFileAdapters.java
b/core/src/test/java/org/apache/iceberg/TestTrackedFileAdapters.java
index a515f0fef0..a7bfe777c1 100644
--- a/core/src/test/java/org/apache/iceberg/TestTrackedFileAdapters.java
+++ b/core/src/test/java/org/apache/iceberg/TestTrackedFileAdapters.java
@@ -115,10 +115,12 @@ class TestTrackedFileAdapters {
.existingFilesCount(5)
.deletedFilesCount(2)
.replacedFilesCount(0)
+ .modifiedFilesCount(0)
.addedRowsCount(300L)
.existingRowsCount(500L)
.deletedRowsCount(200L)
.replacedRowsCount(0L)
+ .modifiedRowsCount(0L)
.minSequenceNumber(7L)
.dv(ByteBuffer.wrap(MumblingTestUtil.onlyFirstBitSetBytes()))
.build();
diff --git a/core/src/test/java/org/apache/iceberg/TestV4ManifestReader.java
b/core/src/test/java/org/apache/iceberg/TestV4ManifestReader.java
index 94e448e8b8..92104ac90c 100644
--- a/core/src/test/java/org/apache/iceberg/TestV4ManifestReader.java
+++ b/core/src/test/java/org/apache/iceberg/TestV4ManifestReader.java
@@ -75,7 +75,7 @@ class TestV4ManifestReader {
private static final Tracking ADDED_TRACKING =
TrackingBuilder.added(SNAPSHOT_ID).build();
private static final ManifestInfo MANIFEST_INFO =
- new ManifestInfoStruct(49, 51, 0, 0, 4_900L, 5_100L, 0L, 0L, 1L, null);
+ new ManifestInfoStruct(49, 51, 0, 0, 1, 4_900L, 5_100L, 0L, 0L, 100L,
1L, null);
private static final Schema TABLE_SCHEMA =
new Schema(
diff --git a/core/src/test/java/org/apache/iceberg/V4TestComparators.java
b/core/src/test/java/org/apache/iceberg/V4TestComparators.java
index 4905d6032f..9c3227afd7 100644
--- a/core/src/test/java/org/apache/iceberg/V4TestComparators.java
+++ b/core/src/test/java/org/apache/iceberg/V4TestComparators.java
@@ -114,10 +114,12 @@ class V4TestComparators {
.thenComparingInt(ManifestInfo::existingFilesCount)
.thenComparingInt(ManifestInfo::deletedFilesCount)
.thenComparingInt(ManifestInfo::replacedFilesCount)
+ .thenComparingInt(ManifestInfo::modifiedFilesCount)
.thenComparingLong(ManifestInfo::addedRowsCount)
.thenComparingLong(ManifestInfo::existingRowsCount)
.thenComparingLong(ManifestInfo::deletedRowsCount)
.thenComparingLong(ManifestInfo::replacedRowsCount)
+ .thenComparingLong(ManifestInfo::modifiedRowsCount)
.thenComparingLong(ManifestInfo::minSequenceNumber)
.thenComparing(ManifestInfo::manifestDeletionVector, BITMAPS));