Skip to content

perf(cloudimg): sniff before full download and reuse the non-Range probe response #137

Description

@CMGS

Two efficiency gaps in the cloud-image pull path, both surfaced in the 2026-07-16 whole-repo audit. Deferred here rather than refactored blind because they touch the tuned parallel-download hot path and warrant a before/after benchmark per our perf-is-a-product-requirement rule.

1. Magic-byte sniff runs after the whole download

pullwithDownload downloads and hashes the entire body (up to maxDownloadBytes = 20 GiB) before sniffImageSource(f) at pull.go checks the first 8 bytes. A misconfigured URL serving a multi-GB non-image payload pays the full transfer + write + hash before rejection. The OCI import path (importQcow2Reader via utils.PeekReader) peeks first — cloudimg should too.

Constraint: the content-addressed digest requires hashing the full file anyway, so the sniff can move early but the hash cannot. The win is bounded to the reject-early case (operator misconfiguration), not the happy path.

2. Non-Range servers pay two full request cycles

probeRangeSupport issues GET Range: bytes=0-0. A server that ignores Range replies 200 with the full body; the code closes that response unread (killing connection reuse per net/http) and downloadSerial then issues a fresh GET. Every pull from a non-Range source is two full request/response cycles.

Options: probe with HEAD + Accept-Ranges, or thread the already-open 200 response into downloadSerial instead of discarding it.

Acceptance

  • A non-image URL is rejected after reading only the header bytes, not the full payload (add a test asserting bytes read).
  • A non-Range source performs one GET, not two (assert request count via a test server).
  • Range-capable parallel download path unchanged; before/after wall-clock + bytes-read on 1/8/16-way fan-out recorded on a compatible host.
  • No regression in TestDownloadToFileFallsBackWhenRangeUnsupported and the digest-verification tests.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions