debian-mirror-gitlab/lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb
2023-07-09 08:55:56 +05:30

87 lines
2.7 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Database
module MigrationHelpers
module WraparoundVacuumHelpers
class WraparoundCheck
WraparoundError = Class.new(StandardError)
def initialize(table_name, migration:)
@migration = migration
@table_name = table_name
validate_table_existence!
end
def execute
return if disabled?
return unless wraparound_vacuum.present?
log "Autovacuum with wraparound prevention mode is running on `#{table_name}`", title: true
log "This process prevents the migration from acquiring the necessary locks"
log "Query: `#{wraparound_vacuum[:query]}`"
log "Current duration: #{wraparound_vacuum[:duration].inspect}"
log "You can wait until it completes or if absolutely necessary interrupt it, " \
"but be aware that a new process will kick in immediately, so multiple interruptions " \
"might be required to time it right with the locks retry mechanism"
end
private
attr_reader :table_name
delegate :say, :connection, to: :@migration
def wraparound_vacuum
@wraparound_vacuum ||= transform_wraparound_vacuum
end
def transform_wraparound_vacuum
result = raw_wraparound_vacuum
values = Array.wrap(result.cast_values.first)
result.columns.zip(values).to_h.with_indifferent_access.compact
end
def raw_wraparound_vacuum
connection.select_all(<<~SQL.squish)
SELECT age(clock_timestamp(), query_start) as duration, query
FROM postgres_pg_stat_activity_autovacuum()
WHERE query ILIKE '%VACUUM%' || #{quoted_table_name} || '%(to prevent wraparound)'
LIMIT 1
SQL
end
def validate_table_existence!
return if connection.table_exists?(table_name)
raise WraparoundError, "Table #{table_name} does not exist"
end
def quoted_table_name
connection.quote(table_name)
end
def disabled?
return true unless wraparound_check_allowed?
Gitlab::Utils.to_boolean(ENV['GITLAB_MIGRATIONS_DISABLE_WRAPAROUND_CHECK'])
end
def wraparound_check_allowed?
Gitlab.com? || Gitlab.dev_or_test_env?
end
def log(text, title: false)
say text, !title
end
end
def check_if_wraparound_in_progress(table_name)
WraparoundCheck.new(table_name, migration: self).execute
end
end
end
end
end