Skip to content

Core: Avoid HEAD on metadata file in synthetic metadata-table tasks - #16833

Closed
eholmer-pltr wants to merge 1 commit into
apache:mainfrom
eholmer-pltr:avoid-head-on-metadata-file-in-synthetic-tasks
Closed

Core: Avoid HEAD on metadata file in synthetic metadata-table tasks#16833
eholmer-pltr wants to merge 1 commit into
apache:mainfrom
eholmer-pltr:avoid-head-on-metadata-file-in-synthetic-tasks

Conversation

@eholmer-pltr

Copy link
Copy Markdown

What

HistoryTable, SnapshotsTable, MetadataLogEntriesTable, RefsTable, ManifestsTable, AllManifestsTable, and PartitionsTable build a StaticDataTask whose rows are materialized from in-memory TableMetadata (or from pre-walked manifest data). The DataFile these tasks wrap exists only so FileScanTask.file() can return a path for identification — the file bytes are never read.

The previous StaticDataTask.of(InputFile, ...) entry point built that DataFile via DataFiles.Builder.withInputFile, which calls InputFile.getLength() to populate fileSizeInBytes. On object-store FileIO implementations that is a HEAD/GetObject round-trip against the table's metadata.json — one extra request on every metadata-table scan, for a value that is never consulted on the DataTask read path.

Change

Replace StaticDataTask.of(InputFile, ...) with StaticDataTask.of(String location, ...), which builds the synthetic DataFile via withPath(location) + withFileSizeInBytes(0L). The seven metadata tables and TestDataTaskParser are migrated to it, and the old overload and its private constructor — the only remaining getLength() call site — are removed, so no construction path performs I/O against the synthetic location. FileScanTask.length() for these tasks now returns 0 instead of the metadata.json size.

Why this is safe

fileSizeInBytes is never read for a DataTask. Engines branch on ScanTask.isDataTask() and obtain rows via DataTask.rows(); any file-size-aware logic (buffer sizing, split planning) lives on the !isDataTask() path — e.g. RowDataReader.open in iceberg-spark and DataTaskReader.open in iceberg-flink.

There is existing precedent in the same area: AllManifestsTable.ManifestListReadTask.length() already returns a hard-coded 8192 with the comment "return a generic length to avoid looking up the actual length".

StaticDataTask is package-private, so this is not a public API change (no revapi impact).

Related discussion

This is a small, concrete step in a direction the community has been discussing — reducing engines' dependence on the root metadata.json and the code paths that read it directly:

See also Yufei Gu's doc tracking clients/engines with hard dependencies on the metadata file in storage, shared in that thread: https://docs.google.com/document/d/17PBhJ0IBxHxMKvCW6CstGOp7cZnboMDdpO6BCPO2kmA/edit

The metadata tables never need any bytes from metadata.json — only a path for identification — yet today they issue a HEAD against it solely to populate an unused size field. This removes that one unnecessary read; it doesn't attempt the broader changes proposed in those threads.

Testing

  • New TestStaticDataTask pins the contract: a bogus, never-created location is tolerated with no I/O, length() and DataFile.fileSizeInBytes() are 0, format is METADATA, and the supplied path is preserved for identification.
  • TestDataTaskParser is migrated to the string overload; the serialized round-trip is byte-identical (the previous Files.localInput(...) already reported size 0 and stripped the URI scheme).

HistoryTable, SnapshotsTable, MetadataLogEntriesTable, RefsTable,
ManifestsTable, AllManifestsTable, and PartitionsTable build a
StaticDataTask whose rows come from in-memory TableMetadata (or from
pre-walked manifest data). They wrap a DataFile around metadataFileLocation
purely so FileScanTask.file() has a path to return; the bytes are never
read.

The old StaticDataTask.of(InputFile, ...) entry point built that DataFile
via DataFiles.Builder.withInputFile, which calls InputFile.getLength() to
populate fileSizeInBytes -- triggering a HEAD/GetObject against the
metadata.json on object-store FileIO. That size is never consulted by the
DataTask read path in any engine (Spark's RowDataReader.open and Flink's
DataTaskReader.open both gate file-size-aware logic on !task.isDataTask()).

This replaces StaticDataTask.of(InputFile, ...) with
StaticDataTask.of(String location, ...), which builds the DataFile via
withPath + withFileSizeInBytes(0L), and migrates the seven metadata tables
plus TestDataTaskParser to it. The old InputFile overload and its private
constructor (the only remaining getLength call site) are removed, so no
construction path performs I/O against the synthetic location.
task.length() for these tasks now returns 0 instead of the metadata.json
file size.

Precedent: AllManifestsTable.ManifestListReadTask.length() already returns
a hard-coded 8192 with the comment "return a generic length to avoid
looking up the actual length".
@eholmer-pltr

Copy link
Copy Markdown
Author

@stevenzwu @flyrain, this came out of the metadata.json-dependence discussion; would appreciate your eyes when you have a moment. It removes the HEAD/getLength on metadata.json that the synthetic metadata-table tasks were doing.

@eholmer-pltr

Copy link
Copy Markdown
Author

Thanks for taking a look, @flyrain! Would you be up for a formal review when you have a moment? It's a small, self-contained change. Happy to address anything.

If someone else is better placed to review, a pointer would be much appreciated too.

@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 Jul 25, 2026
@eholmer-pltr

Copy link
Copy Markdown
Author

Still relevant and still looking for a reviewer

@github-actions github-actions Bot removed the stale label Jul 29, 2026
@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 28, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

This pull request has been closed due to lack of activity. This is not a judgement on the merit of the PR in any way. It is just a way of keeping the PR queue manageable. If you think that is incorrect, or the pull request requires review, you can revive the PR at any time.

@github-actions github-actions Bot closed this Sep 5, 2026
@eholmer-pltr

Copy link
Copy Markdown
Author

@szehon-ho @RussellSpitzer, would either of you mind reopening and reviewing this? GitHub won’t let me reopen it after the stale workflow closed it.

I rechecked it against current main: the change is still needed and merges cleanly. It removes an unnecessary object-store HEAD request from metadata-table scans without changing public API. You’ve both reviewed closely related code in #17522 and #10735, so I thought you might be the right people to ask.

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.

1 participant