diff options
Diffstat (limited to 'lib/gitlab/database/ci_builds_partitioning.rb')
-rw-r--r-- | lib/gitlab/database/ci_builds_partitioning.rb | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/lib/gitlab/database/ci_builds_partitioning.rb b/lib/gitlab/database/ci_builds_partitioning.rb deleted file mode 100644 index 9f8b19f2d23..00000000000 --- a/lib/gitlab/database/ci_builds_partitioning.rb +++ /dev/null @@ -1,224 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Database - class CiBuildsPartitioning - include AsyncDdlExclusiveLeaseGuard - - ATTEMPTS = 5 - LOCK_TIMEOUT = 10.seconds - LEASE_TIMEOUT = 30.minutes - - FK_NAME = :fk_e20479742e_p - TEMP_FK_NAME = :temp_fk_e20479742e_p - NEXT_PARTITION_ID = 101 - BUILDS_PARTITION_NAME = 'gitlab_partitions_dynamic.ci_builds_101' - ANNOTATION_PARTITION_NAME = 'gitlab_partitions_dynamic.ci_job_annotations_101' - RUNNER_MACHINE_PARTITION_NAME = 'gitlab_partitions_dynamic.ci_runner_machine_builds_101' - - def initialize(logger: Gitlab::AppLogger) - @connection = ::Ci::ApplicationRecord.connection - @timing_configuration = Array.new(ATTEMPTS) { [LOCK_TIMEOUT, 3.minutes] } - @logger = logger - end - - def execute - return unless can_execute? - - try_obtain_lease do - swap_foreign_keys - create_new_ci_builds_partition - create_new_job_annotations_partition - create_new_runner_machine_partition - end - - rescue StandardError => e - log_info("Failed to execute: #{e.message}") - end - - private - - attr_reader :connection, :timing_configuration, :logger - - delegate :quote_table_name, :quote_column_name, to: :connection - - def swap_foreign_keys - if new_foreign_key_exists? - log_info('Foreign key already renamed, nothing to do') - - return - end - - with_lock_retries do - connection.execute drop_old_foreign_key_sql - - rename_constraint :p_ci_builds_metadata, TEMP_FK_NAME, FK_NAME - - each_partition do |partition| - rename_constraint partition.identifier, TEMP_FK_NAME, FK_NAME - end - end - - log_info('Foreign key successfully renamed') - end - - def create_new_ci_builds_partition - if connection.table_exists?(BUILDS_PARTITION_NAME) - log_info('p_ci_builds partition exists, nothing to do') - return - end - - with_lock_retries do - connection.execute new_ci_builds_partition_sql - end - - log_info('Partition for p_ci_builds successfully created') - end - - def create_new_job_annotations_partition - if connection.table_exists?(ANNOTATION_PARTITION_NAME) - log_info('p_ci_job_annotations partition exists, nothing to do') - return - end - - with_lock_retries do - connection.execute new_job_annotations_partition_sql - end - - log_info('Partition for p_ci_job_annotations successfully created') - end - - def create_new_runner_machine_partition - if connection.table_exists?(RUNNER_MACHINE_PARTITION_NAME) - log_info('p_ci_runner_machine_builds partition exists, nothing to do') - return - end - - with_lock_retries do - connection.execute new_runner_machine_partition_sql - end - - log_info('Partition for p_ci_runner_machine_builds successfully created') - end - - def can_execute? - return false if process_disabled? - return false unless Gitlab.com? - - if vacuum_running? - log_info('Autovacuum detected') - - return false - end - - true - end - - def process_disabled? - ::Feature.disabled?(:complete_p_ci_builds_partitioning) - end - - def new_foreign_key_exists? - Gitlab::Database::SharedModel.using_connection(connection) do - Gitlab::Database::PostgresForeignKey - .by_constrained_table_name_or_identifier(:p_ci_builds_metadata) - .by_referenced_table_name(:p_ci_builds) - .by_name(FK_NAME) - .exists? - end - end - - def vacuum_running? - Gitlab::Database::SharedModel.using_connection(connection) do - Gitlab::Database::PostgresAutovacuumActivity - .wraparound_prevention - .for_tables(%i[ci_builds ci_builds_metadata]) - .any? - end - end - - def drop_old_foreign_key_sql - <<~SQL.squish - SET LOCAL statement_timeout TO '11s'; - - LOCK TABLE ci_builds, p_ci_builds_metadata IN ACCESS EXCLUSIVE MODE; - - ALTER TABLE p_ci_builds_metadata DROP CONSTRAINT #{FK_NAME}; - SQL - end - - def rename_constraint(table_name, old_name, new_name) - connection.execute <<~SQL - ALTER TABLE #{quote_table_name(table_name)} - RENAME CONSTRAINT #{quote_column_name(old_name)} TO #{quote_column_name(new_name)} - SQL - end - - def new_ci_builds_partition_sql - <<~SQL - SET LOCAL statement_timeout TO '11s'; - - LOCK ci_pipelines, ci_stages IN SHARE ROW EXCLUSIVE MODE; - LOCK TABLE ONLY p_ci_builds IN ACCESS EXCLUSIVE MODE; - - CREATE TABLE IF NOT EXISTS #{BUILDS_PARTITION_NAME} - PARTITION OF p_ci_builds - FOR VALUES IN (#{NEXT_PARTITION_ID}); - SQL - end - - def new_job_annotations_partition_sql - <<~SQL - SET LOCAL statement_timeout TO '11s'; - - LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE; - LOCK TABLE ONLY p_ci_job_annotations IN ACCESS EXCLUSIVE MODE; - - CREATE TABLE IF NOT EXISTS #{ANNOTATION_PARTITION_NAME} - PARTITION OF p_ci_job_annotations - FOR VALUES IN (#{NEXT_PARTITION_ID}); - SQL - end - - def new_runner_machine_partition_sql - <<~SQL - SET LOCAL statement_timeout TO '11s'; - - LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE; - LOCK TABLE ONLY p_ci_runner_machine_builds IN ACCESS EXCLUSIVE MODE; - - CREATE TABLE IF NOT EXISTS #{RUNNER_MACHINE_PARTITION_NAME} - PARTITION OF p_ci_runner_machine_builds - FOR VALUES IN (#{NEXT_PARTITION_ID}); - SQL - end - - def with_lock_retries(&block) - Gitlab::Database::WithLockRetries.new( - timing_configuration: timing_configuration, - connection: connection, - logger: logger, - klass: self.class - ).run(raise_on_exhaustion: true, &block) - end - - def each_partition(&block) - Gitlab::Database::SharedModel.using_connection(connection) do - Gitlab::Database::PostgresPartitionedTable.each_partition(:p_ci_builds_metadata, &block) - end - end - - def log_info(message) - logger.info(message: message, class: self.class.to_s) - end - - def connection_db_config - ::Ci::ApplicationRecord.connection_db_config - end - - def lease_timeout - LEASE_TIMEOUT - end - end - end -end |