Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions api/src/main/java/org/apache/iceberg/ManifestFile.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,9 @@
public interface ManifestFile {
int PARTITION_SUMMARIES_ELEMENT_ID = 508;

/** Format version for pre-v4 manifest files. */
int LEGACY_FORMAT_VERSION = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be public? Another location would probably be better to avoid polluting the public API.


Types.NestedField PATH =
required(500, "manifest_path", Types.StringType.get(), "Location URI with FS scheme");
Types.NestedField LENGTH =
Expand DownExpand Up@@ -186,6 +189,22 @@ default boolean hasDeletedFiles() {
/** Returns the total number of rows in all files with status DELETED in the manifest file. */
Long deletedRowsCount();

/**
Comment thread
stevenzwu marked this conversation as resolved.
* Returns the number of files with status REPLACED in the manifest file, or null for pre-v4
* manifests.
*/
default Integer replacedFilesCount() {
return null;

@rdbluerdblueSep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the pre-v4 value 0 because that status did not exist? That seems like the best thing to return to me. Should this also be required since it is always known for v4 manifests?

}

/**
* Returns the total number of rows in all files with status REPLACED in the manifest file, or
* null for pre-v4 manifests.
*/
default Long replacedRowsCount() {
return null;
}

/**
* Returns a list of {@link PartitionFieldSummary partition field summaries}.
*
Expand All@@ -210,6 +229,16 @@ default Long firstRowId() {
return null;
}

/** Returns the number of entries in the manifest file, or null for pre-v4 manifests. */
default Long recordCount() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? We should have all of the more specific counts.

return null;
}

/** Returns the format version of the manifest file, or 0 for pre-v4 manifests. */
default int formatVersion() {
return LEGACY_FORMAT_VERSION;
}

/**
* Copies this {@link ManifestFile manifest file}. Readers can reuse manifest file instances; use
* this method to make defensive copies.
Expand Down
64 changes: 62 additions & 2 deletions core/src/main/java/org/apache/iceberg/GenericManifestFile.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -60,6 +60,8 @@ public class GenericManifestFile extends SupportsIndexProjection
private PartitionFieldSummary[] partitions = null;
private byte[] keyMetadata = null;
private Long firstRowId = null;
private Long recordCount = null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the CopyBuilder inner class may need to be updated to include these new fields?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

private int formatVersion = LEGACY_FORMAT_VERSION;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why update this class when these values are correctly provided by the interface?


/** Used by Avro reflection to instantiate this class when reading manifest files. */
public GenericManifestFile(Schema avroSchema) {
Expand DownExpand Up@@ -94,7 +96,7 @@ public GenericManifestFile(Schema avroSchema) {
this.firstRowId = null;
}

/** Adjust the arg order to avoid conflict with the public constructor below */
/** Pre-v4 constructor. */
GenericManifestFile(
String path,
long length,
Expand DownExpand Up@@ -130,6 +132,50 @@ public GenericManifestFile(Schema avroSchema) {
this.partitions = partitions == null ? null : partitions.toArray(new PartitionFieldSummary[0]);
this.keyMetadata = ByteBuffers.toByteArray(keyMetadata);
this.firstRowId = firstRowId;
this.recordCount = null;
this.formatVersion = LEGACY_FORMAT_VERSION;
}

/** v4+ constructor variant that accepts recordCount and formatVersion. */
GenericManifestFile(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this should be used for v4. Manifests are now stored as TrackedFile. Why would we update the v3 class used to read from manifest lists?

String path,
long length,
int specId,
ManifestContent content,
long sequenceNumber,
long minSequenceNumber,
Long snapshotId,
List<PartitionFieldSummary> partitions,
ByteBuffer keyMetadata,
Integer addedFilesCount,
Long addedRowsCount,
Integer existingFilesCount,
Long existingRowsCount,
Integer deletedFilesCount,
Long deletedRowsCount,
Long firstRowId,
Long recordCount,
int formatVersion) {
super(ManifestFile.schema().columns().size());
this.avroSchema = AVRO_SCHEMA;
this.manifestPath = path;
this.length = length;
this.specId = specId;
this.content = content;
this.sequenceNumber = sequenceNumber;
this.minSequenceNumber = minSequenceNumber;
this.snapshotId = snapshotId;
this.addedFilesCount = addedFilesCount;
this.addedRowsCount = addedRowsCount;
this.existingFilesCount = existingFilesCount;
this.existingRowsCount = existingRowsCount;
this.deletedFilesCount = deletedFilesCount;
this.deletedRowsCount = deletedRowsCount;
this.partitions = partitions == null ? null : partitions.toArray(new PartitionFieldSummary[0]);
this.keyMetadata = ByteBuffers.toByteArray(keyMetadata);
this.firstRowId = firstRowId;
this.recordCount = recordCount;
this.formatVersion = formatVersion;
}

/**
Expand DownExpand Up@@ -172,6 +218,8 @@ private GenericManifestFile(GenericManifestFile toCopy) {
? null
: Arrays.copyOf(toCopy.keyMetadata, toCopy.keyMetadata.length);
this.firstRowId = toCopy.firstRowId;
this.recordCount = toCopy.recordCount;
this.formatVersion = toCopy.formatVersion;
}

/** Constructor for Java serialization. */
Expand DownExpand Up@@ -272,6 +320,16 @@ public Long firstRowId() {
return firstRowId;
}

@Override
public Long recordCount() {
return recordCount;
}

@Override
public int formatVersion() {
return formatVersion;
}

@Override
public int size() {
return ManifestFile.schema().columns().size();
Expand DownExpand Up@@ -468,7 +526,9 @@ private CopyBuilder(ManifestFile toCopy) {
toCopy.existingRowsCount(),
toCopy.deletedFilesCount(),
toCopy.deletedRowsCount(),
toCopy.firstRowId());
toCopy.firstRowId(),
toCopy.recordCount(),
toCopy.formatVersion());
}
}

Expand Down
Loading
Loading