Loading one deletion vector issued two or three S3 `HEAD` requests against the
same object. `loadDeletionVector` already calls `getObjectMetadata` for the
Puffin file to read its etag for the `PuffinFilesCache` key, but then passes
only the path down: `readFooterBlobs` and `loadDeletionVectorUncached` each
build a fresh `RelativePathWithMetadata` with empty metadata, and
`createReadBuffer` fills it in with another `getObjectMetadata` for every
buffer it opens.
Thread the already-fetched metadata into both helpers instead.
`createReadBuffer` issues its own request only when
`RelativePathWithMetadata::metadata` is empty, so seeding it removes the
redundant requests without changing which bytes are read. The two call sites
that run before the etag fetch keep passing `std::nullopt` and behave as
before.
On a lake scan with cold deletion vectors this is the dominant cost: a profile
of one such query recorded 5706 `S3HeadObject` requests against 2833
`PuffinFilesRead`, with about 94 seconds spent in `HEAD` alone.
Reusing a single metadata snapshot for every read of the same Puffin file is
also more coherent than re-fetching it. Iceberg data and delete files are
immutable, so the separate requests could only ever have observed the same
object.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):
Reduce number of Puffin file HEAD requests
Documentation entry for user-facing changes
...
CI/CD Options
Exclude tests:
Regression jobs to run: