diff --git a/db/docs/batched_background_migrations/backfill_wiki_page_slugs_namespace_id.yml b/db/docs/batched_background_migrations/backfill_wiki_page_slugs_namespace_id.yml new file mode 100644 index 0000000000000000000000000000000000000000..d8767e948e3f5076e25af38392fa1147e6ef0672 --- /dev/null +++ b/db/docs/batched_background_migrations/backfill_wiki_page_slugs_namespace_id.yml @@ -0,0 +1,8 @@ +--- +migration_job_name: BackfillWikiPageSlugsNamespaceId +description: Backfills sharding key `wiki_page_slugs.namespace_id` from `wiki_page_meta`. +feature_category: wiki +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183332 +milestone: '17.10' +queued_migration_version: 20250304103246 +finalized_by: # version of the migration that finalized this BBM diff --git a/db/docs/wiki_page_slugs.yml b/db/docs/wiki_page_slugs.yml index 377b512018889aaba65bcc8989797983d32b8379..b16db528650d975b0b7a2b0ce381a8cd21e64f60 100644 --- a/db/docs/wiki_page_slugs.yml +++ b/db/docs/wiki_page_slugs.yml @@ -17,5 +17,15 @@ desired_sharding_key: table: wiki_page_meta sharding_key: project_id belongs_to: wiki_page_meta -desired_sharding_key_migration_job_name: BackfillWikiPageSlugsProjectId + namespace_id: + references: namespaces + backfill_via: + parent: + foreign_key: wiki_page_meta_id + table: wiki_page_meta + sharding_key: namespace_id + belongs_to: wiki_page_meta table_size: small +desired_sharding_key_migration_job_name: +- BackfillWikiPageSlugsNamespaceId +- BackfillWikiPageSlugsProjectId diff --git a/db/migrate/20250304103242_add_namespace_id_to_wiki_page_slugs.rb b/db/migrate/20250304103242_add_namespace_id_to_wiki_page_slugs.rb new file mode 100644 index 0000000000000000000000000000000000000000..071d073d2c2ad1c1c8851da6c063e72235b0c2d4 --- /dev/null +++ b/db/migrate/20250304103242_add_namespace_id_to_wiki_page_slugs.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddNamespaceIdToWikiPageSlugs < Gitlab::Database::Migration[2.2] + milestone '17.10' + + def change + add_column :wiki_page_slugs, :namespace_id, :bigint + end +end diff --git a/db/post_migrate/20250304103243_index_wiki_page_slugs_on_namespace_id.rb b/db/post_migrate/20250304103243_index_wiki_page_slugs_on_namespace_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..4b162cafcd3e44b326c2d7f0ebb85621fe79f2c8 --- /dev/null +++ b/db/post_migrate/20250304103243_index_wiki_page_slugs_on_namespace_id.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class IndexWikiPageSlugsOnNamespaceId < Gitlab::Database::Migration[2.2] + milestone '17.10' + disable_ddl_transaction! + + INDEX_NAME = 'index_wiki_page_slugs_on_namespace_id' + + def up + add_concurrent_index :wiki_page_slugs, :namespace_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :wiki_page_slugs, INDEX_NAME + end +end diff --git a/db/post_migrate/20250304103244_add_wiki_page_slugs_namespace_id_fk.rb b/db/post_migrate/20250304103244_add_wiki_page_slugs_namespace_id_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..19b57b48533572e68e57f99671aefc0ce78b1940 --- /dev/null +++ b/db/post_migrate/20250304103244_add_wiki_page_slugs_namespace_id_fk.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AddWikiPageSlugsNamespaceIdFk < Gitlab::Database::Migration[2.2] + milestone '17.10' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key( + :wiki_page_slugs, + :namespaces, + column: :namespace_id, + on_delete: :cascade, + reverse_lock_order: true + ) + end + + def down + with_lock_retries do + remove_foreign_key_if_exists :wiki_page_slugs, column: :namespace_id, reverse_lock_order: true + end + end +end diff --git a/db/post_migrate/20250304103245_add_wiki_page_slugs_namespace_id_trigger.rb b/db/post_migrate/20250304103245_add_wiki_page_slugs_namespace_id_trigger.rb new file mode 100644 index 0000000000000000000000000000000000000000..267718e59e33ac88d3dceeebb9f23dad2a41bf57 --- /dev/null +++ b/db/post_migrate/20250304103245_add_wiki_page_slugs_namespace_id_trigger.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddWikiPageSlugsNamespaceIdTrigger < Gitlab::Database::Migration[2.2] + milestone '17.10' + + def up + install_sharding_key_assignment_trigger( + table: :wiki_page_slugs, + sharding_key: :namespace_id, + parent_table: :wiki_page_meta, + parent_sharding_key: :namespace_id, + foreign_key: :wiki_page_meta_id + ) + end + + def down + remove_sharding_key_assignment_trigger( + table: :wiki_page_slugs, + sharding_key: :namespace_id, + parent_table: :wiki_page_meta, + parent_sharding_key: :namespace_id, + foreign_key: :wiki_page_meta_id + ) + end +end diff --git a/db/post_migrate/20250304103246_queue_backfill_wiki_page_slugs_namespace_id.rb b/db/post_migrate/20250304103246_queue_backfill_wiki_page_slugs_namespace_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..54c9b975a8045fe9464b6054db07a553b5567ef5 --- /dev/null +++ b/db/post_migrate/20250304103246_queue_backfill_wiki_page_slugs_namespace_id.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class QueueBackfillWikiPageSlugsNamespaceId < Gitlab::Database::Migration[2.2] + milestone '17.10' + restrict_gitlab_migration gitlab_schema: :gitlab_main_cell + + MIGRATION = "BackfillWikiPageSlugsNamespaceId" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :wiki_page_slugs, + :id, + :namespace_id, + :wiki_page_meta, + :namespace_id, + :wiki_page_meta_id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration( + MIGRATION, + :wiki_page_slugs, + :id, + [ + :namespace_id, + :wiki_page_meta, + :namespace_id, + :wiki_page_meta_id + ] + ) + end +end diff --git a/db/schema_migrations/20250304103242 b/db/schema_migrations/20250304103242 new file mode 100644 index 0000000000000000000000000000000000000000..009a18866d7000b8b03afe88b40b5d3605d9fde4 --- /dev/null +++ b/db/schema_migrations/20250304103242 @@ -0,0 +1 @@ +3a85cad62b63cc3e1fe9001c74054b7b0e6f365ede2594470b182fa615a944bb \ No newline at end of file diff --git a/db/schema_migrations/20250304103243 b/db/schema_migrations/20250304103243 new file mode 100644 index 0000000000000000000000000000000000000000..187d946912074649ee9c3ecf3bdab5adb61f3018 --- /dev/null +++ b/db/schema_migrations/20250304103243 @@ -0,0 +1 @@ +1621aae0e24776efeb3b94400cad5388edb22220ce08d2460dc57c722ea6c75e \ No newline at end of file diff --git a/db/schema_migrations/20250304103244 b/db/schema_migrations/20250304103244 new file mode 100644 index 0000000000000000000000000000000000000000..f2b3837a6122c8597ef18013f252e5970404b23a --- /dev/null +++ b/db/schema_migrations/20250304103244 @@ -0,0 +1 @@ +b5d5f6dc858c8959964628fa6bebb54fbc01fa8a3b49a6bd6c9d1957161a6f45 \ No newline at end of file diff --git a/db/schema_migrations/20250304103245 b/db/schema_migrations/20250304103245 new file mode 100644 index 0000000000000000000000000000000000000000..6bf5619f028f4eea54f4c10fe0fe65c314908bfc --- /dev/null +++ b/db/schema_migrations/20250304103245 @@ -0,0 +1 @@ +2bfd60f5dcd1038c9450f93c55fa3990262806204d9e8847bd4a88cd3c3de13a \ No newline at end of file diff --git a/db/schema_migrations/20250304103246 b/db/schema_migrations/20250304103246 new file mode 100644 index 0000000000000000000000000000000000000000..586abeb36889f094b841702b5ed0f93098ac1c19 --- /dev/null +++ b/db/schema_migrations/20250304103246 @@ -0,0 +1 @@ +23fd391a2ebaa94e9568601d33a56dd8d17907bcbc81e2f669d94c809184cfbc \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 09a8768752dc9db3f00f4daf7c450cef5b9482d1..9dc876f8fe3393e5d4a64d0e1ae0f3c1abceacf4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -3012,6 +3012,22 @@ RETURN NEW; END $$; +CREATE FUNCTION trigger_9e875cabe9c9() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."namespace_id" IS NULL THEN + SELECT "namespace_id" + INTO NEW."namespace_id" + FROM "wiki_page_meta" + WHERE "wiki_page_meta"."id" = NEW."wiki_page_meta_id"; +END IF; + +RETURN NEW; + +END +$$; + CREATE FUNCTION trigger_9f3745f8fe32() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -24217,7 +24233,8 @@ CREATE TABLE wiki_page_slugs ( created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, slug character varying(2048) NOT NULL, - project_id bigint + project_id bigint, + namespace_id bigint ); CREATE SEQUENCE wiki_page_slugs_id_seq @@ -36138,6 +36155,8 @@ CREATE INDEX index_wiki_page_meta_user_mentions_on_namespace_id ON wiki_page_met CREATE INDEX index_wiki_page_meta_user_mentions_on_note_id ON wiki_page_meta_user_mentions USING btree (note_id); +CREATE INDEX index_wiki_page_slugs_on_namespace_id ON wiki_page_slugs USING btree (namespace_id); + CREATE INDEX index_wiki_page_slugs_on_project_id ON wiki_page_slugs USING btree (project_id); CREATE UNIQUE INDEX index_wiki_page_slugs_on_slug_and_wiki_page_meta_id ON wiki_page_slugs USING btree (slug, wiki_page_meta_id); @@ -38938,6 +38957,8 @@ CREATE TRIGGER trigger_9b944f36fdac BEFORE INSERT OR UPDATE ON approval_merge_re CREATE TRIGGER trigger_9e137c16de79 BEFORE INSERT OR UPDATE ON vulnerability_findings_remediations FOR EACH ROW EXECUTE FUNCTION trigger_9e137c16de79(); +CREATE TRIGGER trigger_9e875cabe9c9 BEFORE INSERT OR UPDATE ON wiki_page_slugs FOR EACH ROW EXECUTE FUNCTION trigger_9e875cabe9c9(); + CREATE TRIGGER trigger_9f3745f8fe32 BEFORE INSERT OR UPDATE ON merge_requests_closing_issues FOR EACH ROW EXECUTE FUNCTION trigger_9f3745f8fe32(); CREATE TRIGGER trigger_9f3de326ea61 BEFORE INSERT OR UPDATE ON ci_pipeline_schedule_variables FOR EACH ROW EXECUTE FUNCTION trigger_9f3de326ea61(); @@ -41042,6 +41063,9 @@ ALTER TABLE ONLY clusters ALTER TABLE ONLY vulnerability_external_issue_links ADD CONSTRAINT fk_f07bb8233d FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE; +ALTER TABLE ONLY wiki_page_slugs + ADD CONSTRAINT fk_f07dd9db19 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY epics ADD CONSTRAINT fk_f081aa4489 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; diff --git a/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id.rb b/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..b2a6fdc2345352630ca4ec08596edd45fb5a9f6d --- /dev/null +++ b/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + class BackfillWikiPageSlugsNamespaceId < BackfillDesiredShardingKeyJob + operation_name :backfill_wiki_page_slugs_namespace_id + feature_category :wiki + end + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id_spec.rb b/spec/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..da70bad0a2e6529c2da6d6d5c4fb80487d5cc13c --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_wiki_page_slugs_namespace_id_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillWikiPageSlugsNamespaceId, + feature_category: :wiki, + schema: 20250304103242 do + include_examples 'desired sharding key backfill job' do + let(:batch_table) { :wiki_page_slugs } + let(:backfill_column) { :namespace_id } + let(:backfill_via_table) { :wiki_page_meta } + let(:backfill_via_column) { :namespace_id } + let(:backfill_via_foreign_key) { :wiki_page_meta_id } + end +end diff --git a/spec/migrations/20250304103246_queue_backfill_wiki_page_slugs_namespace_id_spec.rb b/spec/migrations/20250304103246_queue_backfill_wiki_page_slugs_namespace_id_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..71f5290c4f1e76512e344106377c8144b15d51b3 --- /dev/null +++ b/spec/migrations/20250304103246_queue_backfill_wiki_page_slugs_namespace_id_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillWikiPageSlugsNamespaceId, feature_category: :wiki do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :wiki_page_slugs, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + gitlab_schema: :gitlab_main_cell, + job_arguments: [ + :namespace_id, + :wiki_page_meta, + :namespace_id, + :wiki_page_meta_id + ] + ) + } + end + end +end