|
| 1 | +-- Staging schema — used by gcsParquetToStaging activity for temporary unlogged tables. |
| 2 | +CREATE SCHEMA IF NOT EXISTS staging; |
| 3 | + |
1 | 4 | -- ============================================================ |
2 | 5 | -- DOMAIN 1: UNIVERSE (Tier 3 → Tier 2 ranking input) |
3 | 6 | -- ============================================================ |
@@ -130,7 +133,12 @@ CREATE TABLE versions ( |
130 | 133 | -- Nullable for same reason: yanked status comes from registry-specific workers, not deps.dev. |
131 | 134 | is_yanked bool, |
132 | 135 | is_prerelease bool NOT NULL DEFAULT FALSE, |
133 | | - license text, -- SPDX where available; can differ per version |
| 136 | + -- Denormalized from packages for fast deps merge resolution. |
| 137 | + -- Allows resolving (ecosystem, namespace, name, number) → version_id in one index lookup. |
| 138 | + namespace text, |
| 139 | + name text NOT NULL, |
| 140 | + licenses text[], -- SPDX array, deterministically sorted; can differ per version |
| 141 | + download_count bigint, -- per-version where available (npm, crates) |
134 | 142 | last_synced_at timestamptz NOT NULL DEFAULT NOW(), |
135 | 143 | PRIMARY KEY (id, package_id), |
136 | 144 | UNIQUE (package_id, number) |
@@ -239,6 +247,8 @@ CREATE INDEX ON versions (package_id) |
239 | 247 | WHERE |
240 | 248 | is_latest; |
241 | 249 |
|
| 250 | +CREATE INDEX ON versions (ecosystem, COALESCE(namespace, ''), name, number); |
| 251 | + |
242 | 252 | -- ============================================================ |
243 | 253 | -- PACKAGE DEPENDENCIES — PARTITION BY HASH(depends_on_id) |
244 | 254 | -- |
@@ -658,7 +668,8 @@ CREATE UNIQUE INDEX ON advisory_affected_ranges ( |
658 | 668 | COALESCE(last_affected, '') |
659 | 669 | ); |
660 | 670 |
|
661 | | -CREATE INDEX ON advisory_affected_ranges (advisory_package_id); |
| 671 | +-- advisory_package_id prefix lookups are served by the UNIQUE index on |
| 672 | +-- (advisory_package_id, introduced_version, fixed_version) — no separate index needed. |
662 | 673 |
|
663 | 674 | -- ============================================================ |
664 | 675 | -- MAINTAINERS |
@@ -844,8 +855,9 @@ BEGIN |
844 | 855 | -- ranking effectively reduces to: |
845 | 856 | -- LN(1 + dependent_repos_count) * weight_dependent_repos |
846 | 857 | -- + LN(1 + dependent_packages_count) * weight_dependent_packages |
847 | | - UPDATE packages_universe SET last_rank_pass_at = NOW(); |
848 | | - |
| 858 | + -- |
| 859 | + -- last_rank_pass_at is set at INSERT time in rankPackagesUniverse activity (TRUNCATE + INSERT |
| 860 | + -- before each call), so no separate full-table UPDATE needed here. |
849 | 861 | WITH new_scores AS ( |
850 | 862 | SELECT |
851 | 863 | id, |
@@ -910,3 +922,56 @@ BEGIN |
910 | 922 | RETURN QUERY SELECT n_scored, n_ranked, n_propagated; |
911 | 923 | END; |
912 | 924 | $$; |
| 925 | + |
| 926 | +-- ============================================================ |
| 927 | +-- INGEST JOB TRACKING |
| 928 | +-- Tracks each BQ → GCS → Postgres ingest run per job_kind. |
| 929 | +-- snapshot_at = SnapshotAt date used as watermark for incremental diff. |
| 930 | +-- ============================================================ |
| 931 | +CREATE TABLE osspckgs_ingest_jobs ( |
| 932 | + id bigserial PRIMARY KEY, |
| 933 | + job_kind text NOT NULL CHECK (job_kind IN ( |
| 934 | + 'packages', 'versions', 'package_dependencies', |
| 935 | + 'repos', 'package_repos', |
| 936 | + 'advisories', 'advisory_packages', |
| 937 | + 'dependent_counts' |
| 938 | + )), |
| 939 | + status text NOT NULL CHECK (status IN ( |
| 940 | + 'pending', 'exporting', 'exported', |
| 941 | + 'loading', 'merging', 'done', 'failed', 'cleaned' |
| 942 | + )), |
| 943 | + sync_mode text NOT NULL DEFAULT 'incremental' |
| 944 | + CHECK (sync_mode IN ('full', 'incremental')), |
| 945 | + snapshot_at date, -- committed watermark: promoted from provisional unconditionally on 'done' (including 0-row quiet windows) |
| 946 | + provisional_snapshot_at date, -- set at job creation; promoted to snapshot_at when job reaches 'done' |
| 947 | + gcs_prefix text, -- gs://bucket/packages/2026-05-26T00-00-00Z/ |
| 948 | + row_count_bq bigint, |
| 949 | + row_count_staging bigint, -- rows loaded into staging table from GCS parquet files |
| 950 | + row_count_pg bigint, -- total rows inserted into final table(s) after merge |
| 951 | + table_row_counts jsonb, -- per-table inserted row counts, e.g. {"packages": 5000000} |
| 952 | + bq_bytes_billed bigint, -- totalBytesProcessed from BQ (cost metric, not GCS export size) |
| 953 | + bq_job_id text, -- GCP BigQuery job ID (project:location.jobId) |
| 954 | + bq_stats jsonb, -- full BQ job statistics: bytesProcessed, bytesBilled, slotMs, cacheHit, etc. |
| 955 | + bq_cost_usd numeric(12, 8) GENERATED ALWAYS AS ( |
| 956 | + ROUND(COALESCE(bq_bytes_billed, 0)::numeric / 1000000000000.0 * 5.0, 8) |
| 957 | + ) STORED, -- estimated BQ cost at $5/TB on-demand pricing |
| 958 | + export_name text, -- named export group (e.g. "cargo-may-2026") for --export-name bootstrap |
| 959 | + error_message text, |
| 960 | + started_at timestamptz NOT NULL DEFAULT NOW(), |
| 961 | + finished_at timestamptz, |
| 962 | + cleaned_at timestamptz |
| 963 | +); |
| 964 | + |
| 965 | +CREATE INDEX ON osspckgs_ingest_jobs (job_kind, started_at DESC); |
| 966 | + |
| 967 | +CREATE INDEX ON osspckgs_ingest_jobs (status) |
| 968 | +WHERE status NOT IN ('done', 'cleaned'); |
| 969 | + |
| 970 | +CREATE INDEX ON osspckgs_ingest_jobs (job_kind, snapshot_at DESC) |
| 971 | +WHERE status = 'done'; |
| 972 | + |
| 973 | +CREATE INDEX ON osspckgs_ingest_jobs (bq_job_id) |
| 974 | +WHERE bq_job_id IS NOT NULL; |
| 975 | + |
| 976 | +CREATE INDEX ON osspckgs_ingest_jobs (job_kind, export_name) |
| 977 | +WHERE export_name IS NOT NULL; |
0 commit comments