diff --git a/db/post_migrate/20221220131020_bump_default_partition_id_value_for_ci_tables.rb b/db/post_migrate/20221220131020_bump_default_partition_id_value_for_ci_tables.rb new file mode 100644 index 0000000000000000000000000000000000000000..3d06f02a6d67f4ec8bbbad58cb2d926716116aea --- /dev/null +++ b/db/post_migrate/20221220131020_bump_default_partition_id_value_for_ci_tables.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class BumpDefaultPartitionIdValueForCiTables < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + TABLES = { + ci_build_needs: [:partition_id], + ci_build_pending_states: [:partition_id], + ci_build_report_results: [:partition_id], + ci_build_trace_chunks: [:partition_id], + ci_build_trace_metadata: [:partition_id], + ci_builds: [:partition_id], + ci_builds_runner_session: [:partition_id], + ci_job_artifacts: [:partition_id], + ci_job_variables: [:partition_id], + ci_pending_builds: [:partition_id], + ci_pipeline_variables: [:partition_id], + ci_pipelines: [:partition_id], + ci_running_builds: [:partition_id], + ci_sources_pipelines: [:partition_id, :source_partition_id], + ci_stages: [:partition_id], + ci_unit_test_failures: [:partition_id], + p_ci_builds_metadata: [:partition_id] + } + + def up + change_partitions_default_value(from: 100, to: 101) + end + + def down + change_partitions_default_value(from: 101, to: 100) + end + + private + + def change_partitions_default_value(from:, to:) + return unless Gitlab.com? + + TABLES.each do |table_name, columns| + next if columns.all? { |column_name| default_value_for(table_name, column_name) == to } + + with_lock_retries do + columns.each do |column_name| # rubocop:disable Migration/WithLockRetriesDisallowedMethod + change_column_default(table_name, column_name, from: from, to: to) + end + end + end + end + + def default_value_for(table_name, column_name) + connection + .columns(table_name) + .find { |column| column.name == column_name.to_s } + .default&.to_i + end +end diff --git a/db/schema_migrations/20221220131020 b/db/schema_migrations/20221220131020 new file mode 100644 index 0000000000000000000000000000000000000000..36c041b1a33027fd50effc9078676313b6142647 --- /dev/null +++ b/db/schema_migrations/20221220131020 @@ -0,0 +1 @@ +8adf517eb859b5c945f70fbdeb911d398cf0a25c75b39b5991280390b70d1adf \ No newline at end of file diff --git a/spec/migrations/20221220131020_bump_default_partition_id_value_for_ci_tables_spec.rb b/spec/migrations/20221220131020_bump_default_partition_id_value_for_ci_tables_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..1a2300eb4af64c513b2315293b58dca93643469b --- /dev/null +++ b/spec/migrations/20221220131020_bump_default_partition_id_value_for_ci_tables_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BumpDefaultPartitionIdValueForCiTables, :migration, feature_category: :continuous_integration_scaling do + context 'when on sass' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'changes default values' do + reversible_migration do |migration| + migration.before -> { + expect(default_values).not_to include(101) + } + + migration.after -> { + expect(default_values).to match_array([101]) + } + end + end + + context 'with tables already changed' do + before do + active_record_base.connection.execute(<<~SQL) + ALTER TABLE ci_builds ALTER COLUMN partition_id SET DEFAULT 101 + SQL + end + + after do + schema_migrate_down! + end + + let(:alter_query) do + /ALTER TABLE "ci_builds" ALTER COLUMN "partition_id" SET DEFAULT 101/ + end + + it 'skips updating already changed tables' do + recorder = ActiveRecord::QueryRecorder.new { migrate! } + + expect(recorder.log.any?(alter_query)).to be_falsey + expect(default_values).to match_array([101]) + end + end + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + it 'does not change default values' do + reversible_migration do |migration| + migration.before -> { + expect(default_values).not_to include(101) + } + + migration.after -> { + expect(default_values).not_to include(101) + } + end + end + end + + def default_values + values = described_class::TABLES.flat_map do |table_name, columns| + active_record_base + .connection + .columns(table_name) + .select { |column| columns.include?(column.name.to_sym) } + .map { |column| column.default&.to_i } + end + + values.uniq + end +end