From fd0f7a053d2c4953a57bc48ad54290313ba2e60e Mon Sep 17 00:00:00 2001 From: Tianwen Chen <tchen@gitlab.com> Date: Thu, 11 Jul 2024 10:02:21 +0000 Subject: [PATCH] Create table p_ci_build_tags Changelog: other --- app/models/ci/build_tag.rb | 18 +++++++ .../concerns/ci/partitionable/testing.rb | 1 + config/gitlab_loose_foreign_keys.yml | 4 ++ config/initializers/postgres_partitioning.rb | 1 + db/docs/p_ci_build_tags.yml | 12 +++++ ...0703043908_create_table_p_ci_build_tags.rb | 31 ++++++++++++ ...01_ensure_unique_id_for_p_ci_build_tags.rb | 20 ++++++++ ...3_create_partitions_for_p_ci_build_tags.rb | 34 +++++++++++++ ..._fk_from_p_ci_build_tags_to_p_ci_builds.rb | 39 +++++++++++++++ ...831_add_fk_from_p_ci_build_tags_to_tags.rb | 37 ++++++++++++++ db/schema_migrations/20240703043908 | 1 + db/schema_migrations/20240703054001 | 1 + db/schema_migrations/20240703082453 | 1 + db/schema_migrations/20240703094839 | 1 + db/schema_migrations/20240703104831 | 1 + db/structure.sql | 48 +++++++++++++++++++ spec/factories/ci/build_tag.rb | 9 ++++ spec/factories/tag.rb | 7 +++ spec/models/ci/build_tag_spec.rb | 31 ++++++++++++ spec/models/concerns/ci/partitionable_spec.rb | 1 + 20 files changed, 298 insertions(+) create mode 100644 app/models/ci/build_tag.rb create mode 100644 db/docs/p_ci_build_tags.yml create mode 100644 db/migrate/20240703043908_create_table_p_ci_build_tags.rb create mode 100644 db/migrate/20240703054001_ensure_unique_id_for_p_ci_build_tags.rb create mode 100644 db/migrate/20240703082453_create_partitions_for_p_ci_build_tags.rb create mode 100644 db/post_migrate/20240703094839_add_fk_from_p_ci_build_tags_to_p_ci_builds.rb create mode 100644 db/post_migrate/20240703104831_add_fk_from_p_ci_build_tags_to_tags.rb create mode 100644 db/schema_migrations/20240703043908 create mode 100644 db/schema_migrations/20240703054001 create mode 100644 db/schema_migrations/20240703082453 create mode 100644 db/schema_migrations/20240703094839 create mode 100644 db/schema_migrations/20240703104831 create mode 100644 spec/factories/ci/build_tag.rb create mode 100644 spec/factories/tag.rb create mode 100644 spec/models/ci/build_tag_spec.rb diff --git a/app/models/ci/build_tag.rb b/app/models/ci/build_tag.rb new file mode 100644 index 0000000000000..30436f2da73af --- /dev/null +++ b/app/models/ci/build_tag.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Ci + class BuildTag < Ci::ApplicationRecord + include Ci::Partitionable + + self.table_name = :p_ci_build_tags + + query_constraints :build_id, :partition_id + partitionable scope: :build, partitioned: true + + belongs_to :build, ->(build_tag) { in_partition(build_tag) }, # rubocop:disable Rails/InverseOf -- Will be added once association on build is added + class_name: 'Ci::Build', partition_foreign_key: :partition_id, optional: false + belongs_to :tag, class_name: 'ActsAsTaggableOn::Tag', optional: false + + validates :project_id, presence: true + end +end diff --git a/app/models/concerns/ci/partitionable/testing.rb b/app/models/concerns/ci/partitionable/testing.rb index d397244cd9016..db34be42541fb 100644 --- a/app/models/concerns/ci/partitionable/testing.rb +++ b/app/models/concerns/ci/partitionable/testing.rb @@ -14,6 +14,7 @@ module Testing Ci::BuildReportResult Ci::BuildRunnerSession Ci::BuildSource + Ci::BuildTag Ci::BuildTraceChunk Ci::BuildTraceMetadata Ci::BuildPendingState diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml index 79ebc52ddf674..8f51d7869c551 100644 --- a/config/gitlab_loose_foreign_keys.yml +++ b/config/gitlab_loose_foreign_keys.yml @@ -293,6 +293,10 @@ p_ci_build_sources: - table: projects column: project_id on_delete: async_delete +p_ci_build_tags: + - table: projects + column: project_id + on_delete: async_delete p_ci_builds: - table: users column: user_id diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb index 1fca5d738a1b9..f7c3560d3949c 100644 --- a/config/initializers/postgres_partitioning.rb +++ b/config/initializers/postgres_partitioning.rb @@ -17,6 +17,7 @@ Ci::BuildMetadata, Ci::BuildExecutionConfig, Ci::BuildName, + Ci::BuildTag, Ci::BuildSource, Ci::Catalog::Resources::Components::Usage, Ci::Catalog::Resources::SyncEvent, diff --git a/db/docs/p_ci_build_tags.yml b/db/docs/p_ci_build_tags.yml new file mode 100644 index 0000000000000..bfd2146ba0acf --- /dev/null +++ b/db/docs/p_ci_build_tags.yml @@ -0,0 +1,12 @@ +--- +table_name: p_ci_build_tags +classes: +- Ci::BuildTag +feature_categories: +- continuous_integration +description: Routing table that holds information for build tags +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158327 +milestone: '17.2' +gitlab_schema: gitlab_ci +sharding_key: + project_id: projects diff --git a/db/migrate/20240703043908_create_table_p_ci_build_tags.rb b/db/migrate/20240703043908_create_table_p_ci_build_tags.rb new file mode 100644 index 0000000000000..528dcb27d9546 --- /dev/null +++ b/db/migrate/20240703043908_create_table_p_ci_build_tags.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class CreateTablePCiBuildTags < Gitlab::Database::Migration[2.2] + milestone '17.3' + + enable_lock_retries! + + OPTIONS = { + if_not_exists: true, + options: 'PARTITION BY LIST (partition_id)', + primary_key: [:id, :partition_id] + } + + def up + create_table(:p_ci_build_tags, **OPTIONS) do |t| # rubocop:disable Migration/EnsureFactoryForTable -- https://gitlab.com/gitlab-org/gitlab/-/issues/468630 + t.bigserial :id, null: false + t.bigint :tag_id, null: false + t.bigint :build_id, null: false + t.bigint :partition_id, null: false + t.bigint :project_id, null: false + + t.index [:tag_id, :build_id, :partition_id], unique: true + t.index [:build_id, :partition_id] + t.index [:project_id] + end + end + + def down + drop_table :p_ci_build_tags + end +end diff --git a/db/migrate/20240703054001_ensure_unique_id_for_p_ci_build_tags.rb b/db/migrate/20240703054001_ensure_unique_id_for_p_ci_build_tags.rb new file mode 100644 index 0000000000000..7b6c8735074c7 --- /dev/null +++ b/db/migrate/20240703054001_ensure_unique_id_for_p_ci_build_tags.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class EnsureUniqueIdForPCiBuildTags < Gitlab::Database::Migration[2.2] + include Gitlab::Database::PartitioningMigrationHelpers::UniquenessHelpers + + milestone '17.3' + + enable_lock_retries! + + TABLE_NAME = :p_ci_build_tags + SEQ_NAME = :p_ci_build_tags_id_seq + + def up + ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end + + def down + revert_ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end +end diff --git a/db/migrate/20240703082453_create_partitions_for_p_ci_build_tags.rb b/db/migrate/20240703082453_create_partitions_for_p_ci_build_tags.rb new file mode 100644 index 0000000000000..862bc88cd64c6 --- /dev/null +++ b/db/migrate/20240703082453_create_partitions_for_p_ci_build_tags.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class CreatePartitionsForPCiBuildTags < Gitlab::Database::Migration[2.2] + milestone '17.3' + + enable_lock_retries! + + def up + connection.execute(<<~SQL) + LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE; + LOCK TABLE ONLY p_ci_build_tags IN ACCESS EXCLUSIVE MODE; + + CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_build_tags_100 + PARTITION OF p_ci_build_tags + FOR VALUES IN (100); + + CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_build_tags_101 + PARTITION OF p_ci_build_tags + FOR VALUES IN (101); + + CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_build_tags_102 + PARTITION OF p_ci_build_tags + FOR VALUES IN (102); + SQL + end + + def down + connection.execute(<<~SQL) + DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_build_tags_100; + DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_build_tags_101; + DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_build_tags_102; + SQL + end +end diff --git a/db/post_migrate/20240703094839_add_fk_from_p_ci_build_tags_to_p_ci_builds.rb b/db/post_migrate/20240703094839_add_fk_from_p_ci_build_tags_to_p_ci_builds.rb new file mode 100644 index 0000000000000..a1608ddc40a4e --- /dev/null +++ b/db/post_migrate/20240703094839_add_fk_from_p_ci_build_tags_to_p_ci_builds.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class AddFkFromPCiBuildTagsToPCiBuilds < Gitlab::Database::Migration[2.2] + include Gitlab::Database::PartitioningMigrationHelpers + + milestone '17.3' + + disable_ddl_transaction! + + SOURCE_TABLE_NAME = :p_ci_build_tags + TARGET_TABLE_NAME = :p_ci_builds + FK_NAME = :fk_rails_d7bd025909 + COLUMN = [:partition_id, :build_id] + TARGET_COLUMN = [:partition_id, :id] + + def up + add_concurrent_partitioned_foreign_key( + SOURCE_TABLE_NAME, TARGET_TABLE_NAME, + column: COLUMN, + target_column: TARGET_COLUMN, + validate: true, + on_update: :cascade, + on_delete: :cascade, + reverse_lock_order: true, + name: FK_NAME + ) + end + + def down + with_lock_retries do + remove_foreign_key_if_exists( + SOURCE_TABLE_NAME, + TARGET_TABLE_NAME, + name: FK_NAME, + reverse_lock_order: true + ) + end + end +end diff --git a/db/post_migrate/20240703104831_add_fk_from_p_ci_build_tags_to_tags.rb b/db/post_migrate/20240703104831_add_fk_from_p_ci_build_tags_to_tags.rb new file mode 100644 index 0000000000000..3fefb702add5a --- /dev/null +++ b/db/post_migrate/20240703104831_add_fk_from_p_ci_build_tags_to_tags.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class AddFkFromPCiBuildTagsToTags < Gitlab::Database::Migration[2.2] + include Gitlab::Database::PartitioningMigrationHelpers + + milestone '17.3' + + disable_ddl_transaction! + + SOURCE_TABLE_NAME = :p_ci_build_tags + TARGET_TABLE_NAME = :tags + FK_NAME = :fk_rails_8284d35c66 + COLUMN = [:tag_id] + TARGET_COLUMN = [:id] + + def up + add_concurrent_partitioned_foreign_key( + SOURCE_TABLE_NAME, TARGET_TABLE_NAME, + column: COLUMN, + target_column: TARGET_COLUMN, + validate: true, + on_delete: :cascade, + reverse_lock_order: true, + name: FK_NAME + ) + end + + def down + with_lock_retries do + remove_foreign_key_if_exists( + SOURCE_TABLE_NAME, TARGET_TABLE_NAME, + name: FK_NAME, + reverse_lock_order: true + ) + end + end +end diff --git a/db/schema_migrations/20240703043908 b/db/schema_migrations/20240703043908 new file mode 100644 index 0000000000000..c5930f70f0543 --- /dev/null +++ b/db/schema_migrations/20240703043908 @@ -0,0 +1 @@ +69b8dd14f4840ae66d09270323512c8d123fb1fdf5d9b9b120377c103d4c7af4 \ No newline at end of file diff --git a/db/schema_migrations/20240703054001 b/db/schema_migrations/20240703054001 new file mode 100644 index 0000000000000..c4577af110a89 --- /dev/null +++ b/db/schema_migrations/20240703054001 @@ -0,0 +1 @@ +ff5f6d4be9bfba44bd9b0040a3a99188f96cb6e12b8df79d1aa2ff60942427a8 \ No newline at end of file diff --git a/db/schema_migrations/20240703082453 b/db/schema_migrations/20240703082453 new file mode 100644 index 0000000000000..87f750b1b10d2 --- /dev/null +++ b/db/schema_migrations/20240703082453 @@ -0,0 +1 @@ +48a77d2758bfe22bb6dc6b607cf7d19c45e46a05858f1d671cbd578b4bae2f10 \ No newline at end of file diff --git a/db/schema_migrations/20240703094839 b/db/schema_migrations/20240703094839 new file mode 100644 index 0000000000000..497388816919b --- /dev/null +++ b/db/schema_migrations/20240703094839 @@ -0,0 +1 @@ +4823f3b810910b92631acb55ce019c13184b199aa0cd0bf35380e3f39403d6d0 \ No newline at end of file diff --git a/db/schema_migrations/20240703104831 b/db/schema_migrations/20240703104831 new file mode 100644 index 0000000000000..6ceb8d39a53da --- /dev/null +++ b/db/schema_migrations/20240703104831 @@ -0,0 +1 @@ +05182f84a8444fb8a9c683a33ae70b91516e6ae17e2587cf41ebf179b18ed772 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 671e9130e13c5..91ebc3a786550 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10,6 +10,19 @@ CREATE EXTENSION IF NOT EXISTS btree_gist; CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE FUNCTION assign_p_ci_build_tags_id_value() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."id" IS NOT NULL THEN + RAISE WARNING 'Manually assigning ids is not allowed, the value will be ignored'; +END IF; +NEW."id" := nextval('p_ci_build_tags_id_seq'::regclass); +RETURN NEW; + +END +$$; + CREATE FUNCTION assign_p_ci_builds_execution_configs_id_value() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -2130,6 +2143,15 @@ CREATE TABLE p_ci_build_sources ( ) PARTITION BY LIST (partition_id); +CREATE TABLE p_ci_build_tags ( + id bigint NOT NULL, + tag_id bigint NOT NULL, + build_id bigint NOT NULL, + partition_id bigint NOT NULL, + project_id bigint NOT NULL +) +PARTITION BY LIST (partition_id); + CREATE TABLE p_ci_builds ( status character varying, finished_at timestamp without time zone, @@ -13907,6 +13929,15 @@ CREATE SEQUENCE p_catalog_resource_sync_events_id_seq ALTER SEQUENCE p_catalog_resource_sync_events_id_seq OWNED BY p_catalog_resource_sync_events.id; +CREATE SEQUENCE p_ci_build_tags_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE p_ci_build_tags_id_seq OWNED BY p_ci_build_tags.id; + CREATE SEQUENCE p_ci_builds_execution_configs_id_seq START WITH 1 INCREMENT BY 1 @@ -23520,6 +23551,9 @@ ALTER TABLE ONLY p_ci_build_names ALTER TABLE ONLY p_ci_build_sources ADD CONSTRAINT p_ci_build_sources_pkey PRIMARY KEY (build_id, partition_id); +ALTER TABLE ONLY p_ci_build_tags + ADD CONSTRAINT p_ci_build_tags_pkey PRIMARY KEY (id, partition_id); + ALTER TABLE ONLY p_ci_builds_execution_configs ADD CONSTRAINT p_ci_builds_execution_configs_pkey PRIMARY KEY (id, partition_id); @@ -28267,6 +28301,12 @@ CREATE INDEX index_p_ci_build_names_on_search_vector ON ONLY p_ci_build_names US CREATE INDEX index_p_ci_build_sources_on_project_id_and_build_id ON ONLY p_ci_build_sources USING btree (project_id, build_id); +CREATE INDEX index_p_ci_build_tags_on_build_id_and_partition_id ON ONLY p_ci_build_tags USING btree (build_id, partition_id); + +CREATE INDEX index_p_ci_build_tags_on_project_id ON ONLY p_ci_build_tags USING btree (project_id); + +CREATE UNIQUE INDEX index_p_ci_build_tags_on_tag_id_and_build_id_and_partition_id ON ONLY p_ci_build_tags USING btree (tag_id, build_id, partition_id); + CREATE INDEX index_p_ci_builds_execution_configs_on_pipeline_id ON ONLY p_ci_builds_execution_configs USING btree (pipeline_id); CREATE INDEX index_p_ci_builds_execution_configs_on_project_id ON ONLY p_ci_builds_execution_configs USING btree (project_id); @@ -31593,6 +31633,8 @@ ALTER INDEX p_ci_job_artifacts_expire_at_job_id_idx1 ATTACH PARTITION tmp_index_ ALTER INDEX p_ci_builds_token_encrypted_partition_id_idx ATTACH PARTITION unique_ci_builds_token_encrypted_and_partition_id; +CREATE TRIGGER assign_p_ci_build_tags_id_trigger BEFORE INSERT ON p_ci_build_tags FOR EACH ROW EXECUTE FUNCTION assign_p_ci_build_tags_id_value(); + CREATE TRIGGER assign_p_ci_builds_execution_configs_id_trigger BEFORE INSERT ON p_ci_builds_execution_configs FOR EACH ROW EXECUTE FUNCTION assign_p_ci_builds_execution_configs_id_value(); CREATE TRIGGER assign_p_ci_builds_id_trigger BEFORE INSERT ON p_ci_builds FOR EACH ROW EXECUTE FUNCTION assign_p_ci_builds_id_value(); @@ -34293,6 +34335,9 @@ ALTER TABLE ONLY audit_events_instance_streaming_event_type_filters ALTER TABLE ONLY required_code_owners_sections ADD CONSTRAINT fk_rails_817708cf2d FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE; +ALTER TABLE p_ci_build_tags + ADD CONSTRAINT fk_rails_8284d35c66 FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE; + ALTER TABLE ONLY namespace_ldap_settings ADD CONSTRAINT fk_rails_82cd0ad4bb FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; @@ -34938,6 +34983,9 @@ ALTER TABLE ONLY packages_rpm_repository_files ALTER TABLE ONLY packages_rpm_metadata ADD CONSTRAINT fk_rails_d79f02264b FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE CASCADE; +ALTER TABLE p_ci_build_tags + ADD CONSTRAINT fk_rails_d7bd025909 FOREIGN KEY (partition_id, build_id) REFERENCES p_ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE; + ALTER TABLE ONLY note_metadata ADD CONSTRAINT fk_rails_d853224d37 FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE; diff --git a/spec/factories/ci/build_tag.rb b/spec/factories/ci/build_tag.rb new file mode 100644 index 0000000000000..08bd426f30169 --- /dev/null +++ b/spec/factories/ci/build_tag.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :ci_build_tag, class: 'Ci::BuildTag' do + build factory: :ci_build + tag factory: :tag + project_id { build.project_id } + end +end diff --git a/spec/factories/tag.rb b/spec/factories/tag.rb new file mode 100644 index 0000000000000..f51c2b061b6de --- /dev/null +++ b/spec/factories/tag.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :tag, class: 'ActsAsTaggableOn::Tag' do + name { generate(:name) } + end +end diff --git a/spec/models/ci/build_tag_spec.rb b/spec/models/ci/build_tag_spec.rb new file mode 100644 index 0000000000000..49d4de50d8a31 --- /dev/null +++ b/spec/models/ci/build_tag_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::BuildTag, feature_category: :continuous_integration do + it { is_expected.to belong_to(:build).optional(false) } + it { is_expected.to belong_to(:tag).optional(false) } + + describe 'validations' do + it { is_expected.to validate_presence_of(:project_id) } + end + + describe 'partitioning' do + context 'with build' do + let_it_be(:build) { FactoryBot.build(:ci_build, partition_id: ci_testing_partition_id) } + let_it_be(:build_tag) { FactoryBot.build(:ci_build_tag, build: build) } + + it 'sets partition_id to the current partition value' do + expect { build_tag.valid? }.to change { build_tag.partition_id }.to(ci_testing_partition_id) + end + + context 'when it is already set' do + let_it_be(:build_tag) { FactoryBot.build(:ci_build_tag, partition_id: 125) } + + it 'does not change the partition_id value' do + expect { build_tag.valid? }.not_to change { build_tag.partition_id } + end + end + end + end +end diff --git a/spec/models/concerns/ci/partitionable_spec.rb b/spec/models/concerns/ci/partitionable_spec.rb index 70fe5677c2d12..11a0bd5be4100 100644 --- a/spec/models/concerns/ci/partitionable_spec.rb +++ b/spec/models/concerns/ci/partitionable_spec.rb @@ -194,6 +194,7 @@ Ci::BuildMetadata Ci::BuildExecutionConfig Ci::BuildName + Ci::BuildTag Ci::BuildSource Ci::JobAnnotation Ci::JobArtifact -- GitLab