Skip to content

Core: Report metadata file size in commit metrics - #17164

Open
amirmor1 wants to merge 1 commit into
apache:mainfrom
amirmor1:core-metadata-file-size-metric
Open

amirmor1 wants to merge 1 commit into
apache:mainfrom
amirmor1:core-metadata-file-size-metric

Conversation

@amirmor1

Copy link
Copy Markdown

Summary

  • Add an optional metadata-file-size-bytes metric to CommitMetricsResult and JSON serde.
  • Capture metadata file size at write time via new additive APIs in TableMetadataParser and expose it through TableOperations#metadataFileSizeInBytes().
  • Populate CommitReport with this metric in SnapshotProducer when the table operations implementation provides the value.
  • Add coverage in core metrics parser/report parser tests and Hadoop commit reporting tests.
  • Update metrics reporting docs for the new commit metric.

Why

  • Exposes useful commit metadata size telemetry to MetricsReporter consumers.
  • Captures size during write to avoid an extra metadata-file read after commit.

Compatibility

  • Existing TableMetadataParser.write/overwrite/internalWrite behavior remains intact.
  • New APIs are additive (writeAndReturnLength, overwriteAndReturnLength).
  • Metric is optional and may be null for table operations that cannot provide write-time size.

Test plan

  • ./gradlew :iceberg-core:test --tests org.apache.iceberg.metrics.TestCommitMetricsResultParser
  • ./gradlew :iceberg-core:test --tests org.apache.iceberg.metrics.TestCommitReportParser
  • ./gradlew :iceberg-core:test --tests org.apache.iceberg.hadoop.TestHadoopCommits
  • ./gradlew :iceberg-core:spotlessCheck

@github-actions

Copy link
Copy Markdown

This pull request has been marked as stale due to 30 days of inactivity. It will be closed in 1 week if no further activity occurs. If you think that’s incorrect or this pull request requires a review, please simply write any comment. If closed, you can revive the PR at any time and @mention a reviewer or discuss it on the dev@iceberg.apache.org list. Thank you for your contributions.

@github-actions github-actions Bot added the stale label Aug 12, 2026
@amirmor1

Copy link
Copy Markdown
Author

not stale

@github-actions github-actions Bot removed the stale label Aug 13, 2026

private static long metadataLength(PositionOutputStream stream, String location) {
try {
return stream.storedLength();

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.

This might be called on a closed stream since writeMetadata closes the PositionOutputStream via
try-with-resources and then returns it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I've reworked writeMetadata to return the length
directly, with the close scoped in a nested try so the ordering is explicit and commented,
and dropped the metadataLength helper.

}

@Test
public void testCommitReportContainsMetadataFileSizeInBytes() {

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.

avoid using test prefix in test names.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Renamed to commitReportContainsMetadataFileSizeInBytes. Thanks.

Comment thread docs/docs/metrics-reporting.md Outdated
* number of added/removed data/delete files
* number of added/removed equality/positional delete files
* number of added/removed equality/positional deletes
* metadata file size in bytes for the committed table metadata file (optional, may be null depending on catalog implementation)

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.

"null" is a Java detail; "may be absent" reads better in docs

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed — reworded to "size in bytes of the table metadata file written by the commit,
when available (some catalogs do not write metadata files directly)".

private String currentMetadataLocation = null;
private boolean shouldRefresh = true;
private int version = -1;
private volatile Long metadataFileSizeInBytes;

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.

the size is mutable per-ops-instance state, read later in notifyListeners(). If the same ops instance sees interleaved commits, the reported size can belong to a different metadata file than the reported snapshot

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, this was the weakest part of the change. Reading shared ops state at report time
meant the value wasn't bound to the snapshot being reported, and it also left a stale size
in place on any commit path that doesn't write a metadata file.

I've moved the capture into the producer, following the newSnapshotId pattern already in
SnapshotProducer#commit:

AtomicReference<Long> metadataFileSizeInBytes = new AtomicReference<>();
...
taskOps.commit(base, updated.withUUID());
metadataFileSizeInBytes.set(taskOps.metadataFileSizeInBytes());
...
notifyListeners(metadataFileSizeInBytes.get());

The size is now read in the same thread immediately after the commit attempt that produced
it, and it's scoped to a single producer. A concurrent commit through a shared ops instance
can no longer be attributed to this snapshot at report time, and stale values from earlier
commits are gone. Added eachCommitReportsTheMetadataFileSizeItWrote to cover the
per-commit scoping.

This still routes the value through a field on the ops instance, which I kept because
TableOperations#commit returns void and the write happens inside subclass doCommit
implementations.

@amirmor1
amirmor1 requested a review from manuzhang August 14, 2026 13:29
Add an optional metadata-file-size-bytes metric to CommitMetricsResult so
MetricsReporter implementations can observe the size of the metadata.json
written by a commit. Metadata bloat is otherwise invisible through the
metrics reporting API, and some catalogs enforce a hard limit on metadata
file size.

The size is captured at write time from the PositionOutputStream rather
than by re-reading the file after the commit, avoiding an extra metadata
read on the commit path. SnapshotProducer captures the value per commit
attempt so it stays bound to the snapshot being reported, and the metric
is omitted when a TableOperations implementation cannot report a
write-time size.

Co-authored-by: Cursor <cursoragent@cursor.com>
@amirmor1
amirmor1 force-pushed the core-metadata-file-size-metric branch from 8ea3149 to 1a165e9 Compare September 6, 2026 13:05
@amirmor1

amirmor1 commented Sep 8, 2026

Copy link
Copy Markdown
Author

@manuzhang

All four of your comments are addressed:

  • writeMetadata now returns the length directly, with the close scoped in a nested try
    so the post-close read is explicit (same reason PuffinWriter#finish reads storedLength
    after close). Dropped the metadataLength helper.
  • Test renamed to drop the test prefix.
  • Docs reworded to avoid the Java "null" detail.
  • The size is now captured per commit attempt in SnapshotProducer, following the existing
    newSnapshotId pattern, so it's no longer read off shared ops state at report time.
    Added eachCommitReportsTheMetadataFileSizeItWrote to cover the scoping.

Still happy to thread the value through the commit path explicitly instead if you'd prefer
that shape — just let me know. No rush, and thanks for the review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants