Package Registry: skip find-or-create for Maven checksum (.sha1/.md5) uploads

Summary

During mvn deploy, Maven uploads a .sha1 and .md5 checksum file after every artifact (.jar, .pom, maven-metadata.xml). On the finalize endpoint (PUT /projects/:id/packages/maven/*path/:file_name), these checksum uploads currently run the full Packages::Maven::FindOrCreatePackageService path — the same work as a real artifact upload — even though checksums are stored as columns on the package file and never need find-or-create.

For a release deploy this is roughly two-thirds of the PUTs per module (~6 of ~9), each doing avoidable work on a hot, latency-sensitive endpoint.

What the checksum PUTs do today

For .sha1 / .md5, the finalize endpoint runs FindOrCreatePackageService, which performs:

  • a Packages::Maven::PackageFinder lookup (JOIN on packages_maven_metadata.path);
  • duplicate detection (Namespace::PackageSetting.duplicates_allowed?, a cascading namespace-ancestry lookup, plus loading all package_files for snapshots);
  • create_build_infos! (find-or-create);
  • on create, a package-protection-rule check plus INSERTs.

Then:

  • md5 → the result is discarded and an empty body is returned (all preceding work wasted);
  • sha1 → only the stored file's sha1 is needed, to compare against the uploaded checksum.

The whole block is also pinned to the primary database.

Proposed change

Fast-path checksum uploads on the finalize endpoint:

  • md5 → return an empty body immediately (no DB work, no primary pinning);
  • sha1 → look up the package and package file and verify the stored hash, skipping find-or-create entirely.

The real-artifact path is unchanged, and the happy path (artifact uploaded before its checksums, as Maven and Gradle always do) is behaviorally identical.

Gated behind the maven_checksum_upload_fast_path feature flag (gitlab_com_derisk, default off) to de-risk the change on this hot endpoint.

Scope

This is one of several independent server-side improvements identified for Maven deploy PUT latency. Adopting use_final_store_path for the authorize step (to remove the synchronous object-storage HEAD + COPY + DELETE on real-file finalize) is a separate, larger change tracked on its own.