Add packages_rubygems_spec_files table, model, and uploader

Summary

This is the first of three MRs to implement RubyGems spec index file generation for the package registry ([related issue link here]).

  • MR 1 (this one): Database table, model, uploader, and specs
  • MR 2 (pending this merge): CreateSpecFilesService, CreateSpecFilesWorker, and hooks into ProcessGemService / MarkPackageForDestructionService
  • MR 3 (pending MR 2): API endpoint to serve spec index files, request specs, and docs

What does this MR do?

Introduces the packages_rubygems_spec_files table and associated Packages::Rubygems::SpecFile model to store generated RubyGems spec index files (specs.4.8.gz, latest_specs.4.8.gz, prerelease_specs.4.8.gz) per project. This follows the same pattern as Packages::Npm::MetadataCache and Packages::Helm::MetadataCache.

Changes:

  • New migration creating packages_rubygems_spec_files with a unique index on (project_id, file_name) and a unique index on object_storage_key
  • Packages::Rubygems::SpecFile model with FileStoreMounter, ObjectStorable, and Packages::Destructible concerns
  • Packages::Rubygems::SpecFileUploader (extends Packages::BaseMetadataCacheUploader)
  • has_many :rubygems_spec_files association on Project
  • Factory, fixture, and model specs

Database

New table: packages_rubygems_spec_files

Column Type Constraints
id bigint PK
created_at timestamptz NOT NULL
updated_at timestamptz NOT NULL
project_id bigint NOT NULL
size integer NOT NULL
status smallint NOT NULL, DEFAULT 0
file_store integer DEFAULT 1
file_name text NOT NULL, limit 255
file text NOT NULL, limit 255
object_storage_key text NOT NULL, limit 255

Indexes

  • index_packages_rubygems_spec_files_on_project_id_and_file_name — UNIQUE on (project_id, file_name)
  • index_packages_rubygems_spec_files_on_object_storage_key — UNIQUE on (object_storage_key)

Query Plans

All queries use the unique index on `(project_id, file_name)`.

**1. Lookup by project and file name** (used by `find_or_build` and `with_project_and_file_name` scope):

```sql

SELECT * FROM packages_rubygems_spec_files

WHERE project_id = 1 AND file_name = 'specs.4.8.gz'

LIMIT 1;

  • Time: 0.509 ms (planning: 0.449 ms, execution: 0.060 ms)
  • Plan: Index Scan using index_packages_rubygems_spec_files_on_project_id_and_file_name
  • Full plan

2. Insert new spec file:

INSERT INTO packages_rubygems_spec_files

(project_id, file_name, file, size, status, object_storage_key, created_at, updated_at)

VALUES (1, 'specs.4.8.gz', 'spec_file.gz', 1024, 0, 'packages/rubygems/spec_files/abc123', now(), now());

  • Time: 2.868 ms (planning: 0.081 ms, execution: 2.787 ms)
  • Full plan

3. Update existing spec file:

UPDATE packages_rubygems_spec_files

SET file = 'spec_file.gz', size = 2048, updated_at = now()

WHERE project_id = 1 AND file_name = 'specs.4.8.gz';

  • Time: 0.514 ms (planning: 0.395 ms, execution: 0.119 ms)
  • Plan: Index Scan using index_packages_rubygems_spec_files_on_project_id_and_file_name
  • Full plan

MR acceptance checklist

  • db/structure.sqlupdated (pending — requiresbundle exec rake db:migrate db:schema:dump)
    • Database dictionary file included (db/docs/packages_rubygems_spec_files.yml)
    • Model specs passing
    • Followsdatabase review guidelines
Edited by Tim Rizzi

Merge request reports

Loading
Loading