diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-22 00:09:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-22 00:09:40 +0300 |
commit | db115d5ac71e57b2dad327004de7660e353dcd1c (patch) | |
tree | 440519fe8dd6439577258fa671274d6b9a0d7813 /lib | |
parent | aed8f5ecc5f9a09e3af9c32f7b02743d317a4116 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
3 files changed, 64 insertions, 47 deletions
diff --git a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb index b89ea7dc250..c7226b41bab 100644 --- a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb +++ b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb @@ -2,8 +2,8 @@ module Gitlab module BackgroundMigration - # Background migration that updates the value of a - # column using the value of another column in the same table. + # Background migration that updates the value of one or more + # columns using the value of other columns in the same table. # # - The {start_id, end_id} arguments are at the start so that it can be used # with `queue_batched_background_migration` @@ -25,17 +25,21 @@ module Gitlab # sub_batch_size - We don't want updates to take more than ~100ms # This allows us to run multiple smaller batches during # the minimum 2.minute interval that we can schedule jobs - # copy_from - The column containing the data to copy. - # copy_to - The column to copy the data to. + # copy_from - List of columns containing the data to copy. + # copy_to - List of columns to copy the data to. Order must match the order in `copy_from`. def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, copy_from, copy_to) - quoted_copy_from = connection.quote_column_name(copy_from) - quoted_copy_to = connection.quote_column_name(copy_to) + copy_from = Array.wrap(copy_from) + copy_to = Array.wrap(copy_to) + + raise ArgumentError, 'number of source and destination columns must match' unless copy_from.count == copy_to.count + + assignment_clauses = column_assignment_clauses(copy_from, copy_to) parent_batch_relation = relation_scoped_to_range(batch_table, batch_column, start_id, end_id) parent_batch_relation.each_batch(column: batch_column, of: sub_batch_size) do |sub_batch| batch_metrics.time_operation(:update_all) do - sub_batch.update_all("#{quoted_copy_to}=#{quoted_copy_from}") + sub_batch.update_all(assignment_clauses) end sleep(PAUSE_SECONDS) @@ -55,6 +59,17 @@ module Gitlab def relation_scoped_to_range(source_table, source_key_column, start_id, stop_id) define_batchable_model(source_table).where(source_key_column => start_id..stop_id) end + + def column_assignment_clauses(copy_from, copy_to) + assignments = copy_from.zip(copy_to).map do |from_column, to_column| + from_column = connection.quote_column_name(from_column) + to_column = connection.quote_column_name(to_column) + + "#{to_column} = #{from_column}" + end + + assignments.join(', ') + end end end end diff --git a/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb b/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb index 9ecf53317d0..c01545e5dca 100644 --- a/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb +++ b/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb @@ -8,18 +8,15 @@ module Gitlab class MoveContainerRegistryEnabledToProjectFeature MAX_BATCH_SIZE = 300 - module Migratable - # Migration model namespace isolated from application code. - class ProjectFeature < ActiveRecord::Base - ENABLED = 20 - DISABLED = 0 - end - end + ENABLED = 20 + DISABLED = 0 def perform(from_id, to_id) (from_id..to_id).each_slice(MAX_BATCH_SIZE) do |batch| process_batch(batch.first, batch.last) end + + Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded('MoveContainerRegistryEnabledToProjectFeature', [from_id, to_id]) end private @@ -37,9 +34,9 @@ module Gitlab <<~SQL UPDATE project_features SET container_registry_access_level = (CASE p.container_registry_enabled - WHEN true THEN #{ProjectFeature::ENABLED} - WHEN false THEN #{ProjectFeature::DISABLED} - ELSE #{ProjectFeature::DISABLED} + WHEN true THEN #{ENABLED} + WHEN false THEN #{DISABLED} + ELSE #{DISABLED} END) FROM projects p WHERE project_id = p.id AND diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index d06a73da8ac..25ae72370fe 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -905,7 +905,7 @@ module Gitlab end end - # Initializes the conversion of an integer column to bigint + # Initializes the conversion of a set of integer columns to bigint # # It can be used for converting both a Primary Key and any Foreign Keys # that may reference it or any other integer column that we may want to @@ -923,14 +923,14 @@ module Gitlab # Note: this helper is intended to be used in a regular (pre-deployment) migration. # # This helper is part 1 of a multi-step migration process: - # 1. initialize_conversion_of_integer_to_bigint to create the new column and database triggers + # 1. initialize_conversion_of_integer_to_bigint to create the new columns and database trigger # 2. backfill_conversion_of_integer_to_bigint to copy historic data using background migrations # 3. remaining steps TBD, see #288005 # # table - The name of the database table containing the column - # column - The name of the column that we want to convert to bigint. + # columns - The name, or array of names, of the column(s) that we want to convert to bigint. # primary_key - The name of the primary key column (most often :id) - def initialize_conversion_of_integer_to_bigint(table, column, primary_key: :id) + def initialize_conversion_of_integer_to_bigint(table, columns, primary_key: :id) unless table_exists?(table) raise "Table #{table} does not exist" end @@ -939,34 +939,40 @@ module Gitlab raise "Column #{primary_key} does not exist on #{table}" end - unless column_exists?(table, column) - raise "Column #{column} does not exist on #{table}" + columns = Array.wrap(columns) + columns.each do |column| + next if column_exists?(table, column) + + raise ArgumentError, "Column #{column} does not exist on #{table}" end check_trigger_permissions!(table) - old_column = column_for(table, column) - tmp_column = "#{column}_convert_to_bigint" + conversions = columns.to_h { |column| [column, "#{column}_convert_to_bigint"] } with_lock_retries do - if (column.to_s == primary_key.to_s) || !old_column.null - # If the column to be converted is either a PK or is defined as NOT NULL, - # set it to `NOT NULL DEFAULT 0` and we'll copy paste the correct values bellow - # That way, we skip the expensive validation step required to add - # a NOT NULL constraint at the end of the process - add_column(table, tmp_column, :bigint, default: old_column.default || 0, null: false) - else - add_column(table, tmp_column, :bigint, default: old_column.default) + conversions.each do |(source_column, temporary_name)| + column = column_for(table, source_column) + + if (column.name.to_s == primary_key.to_s) || !column.null + # If the column to be converted is either a PK or is defined as NOT NULL, + # set it to `NOT NULL DEFAULT 0` and we'll copy paste the correct values bellow + # That way, we skip the expensive validation step required to add + # a NOT NULL constraint at the end of the process + add_column(table, temporary_name, :bigint, default: column.default || 0, null: false) + else + add_column(table, temporary_name, :bigint, default: column.default) + end end - install_rename_triggers(table, column, tmp_column) + install_rename_triggers(table, conversions.keys, conversions.values) end end - # Backfills the new column used in the conversion of an integer column to bigint using background migrations. + # Backfills the new columns used in an integer-to-bigint conversion using background migrations. # # - This helper should be called from a post-deployment migration. - # - In order for this helper to work properly, the new column must be first initialized with + # - In order for this helper to work properly, the new columns must be first initialized with # the `initialize_conversion_of_integer_to_bigint` helper. # - It tracks the scheduled background jobs through Gitlab::Database::BackgroundMigration::BatchedMigration, # which allows a more thorough check that all jobs succeeded in the @@ -976,12 +982,12 @@ module Gitlab # deployed (including background job changes) before we begin processing the background migration. # # This helper is part 2 of a multi-step migration process: - # 1. initialize_conversion_of_integer_to_bigint to create the new column and database triggers + # 1. initialize_conversion_of_integer_to_bigint to create the new columns and database trigger # 2. backfill_conversion_of_integer_to_bigint to copy historic data using background migrations # 3. remaining steps TBD, see #288005 # # table - The name of the database table containing the column - # column - The name of the column that we want to convert to bigint. + # columns - The name, or an array of names, of the column(s) we want to convert to bigint. # primary_key - The name of the primary key column (most often :id) # batch_size - The number of rows to schedule in a single background migration # sub_batch_size - The smaller batches that will be used by each scheduled job @@ -1001,7 +1007,7 @@ module Gitlab # between the scheduled jobs def backfill_conversion_of_integer_to_bigint( table, - column, + columns, primary_key: :id, batch_size: 20_000, sub_batch_size: 1000, @@ -1016,22 +1022,21 @@ module Gitlab raise "Column #{primary_key} does not exist on #{table}" end - unless column_exists?(table, column) - raise "Column #{column} does not exist on #{table}" - end + conversions = Array.wrap(columns).to_h do |column| + raise ArgumentError, "Column #{column} does not exist on #{table}" unless column_exists?(table, column) - tmp_column = "#{column}_convert_to_bigint" + temporary_name = "#{column}_convert_to_bigint" + raise ArgumentError, "Column #{temporary_name} does not exist on #{table}" unless column_exists?(table, temporary_name) - unless column_exists?(table, tmp_column) - raise 'The temporary column does not exist, initialize it with `initialize_conversion_of_integer_to_bigint`' + [column, temporary_name] end batched_migration = queue_batched_background_migration( 'CopyColumnUsingBackgroundMigrationJob', table, primary_key, - column, - tmp_column, + conversions.keys, + conversions.values, job_interval: interval, batch_size: batch_size, sub_batch_size: sub_batch_size) |