Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/database/migration_helpers/v2.rb')
-rw-r--r--lib/gitlab/database/migration_helpers/v2.rb112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/gitlab/database/migration_helpers/v2.rb b/lib/gitlab/database/migration_helpers/v2.rb
index f20a9b30fa7..0e7f6075196 100644
--- a/lib/gitlab/database/migration_helpers/v2.rb
+++ b/lib/gitlab/database/migration_helpers/v2.rb
@@ -6,6 +6,118 @@ module Gitlab
module V2
include Gitlab::Database::MigrationHelpers
+ # Superseded by `create_table` override below
+ def create_table_with_constraints(*_)
+ raise <<~EOM
+ #create_table_with_constraints is not supported anymore - use #create_table instead, for example:
+
+ create_table :db_guides do |t|
+ t.bigint :stars, default: 0, null: false
+ t.text :title, limit: 128
+ t.text :notes, limit: 1024
+
+ t.check_constraint 'stars > 1000', name: 'so_many_stars'
+ end
+
+ See https://docs.gitlab.com/ee/development/database/strings_and_the_text_data_type.html
+ EOM
+ end
+
+ # Creates a new table, optionally allowing the caller to add text limit constraints to the table.
+ # This method only extends Rails' `create_table` method
+ #
+ # Example:
+ #
+ # create_table :db_guides do |t|
+ # t.bigint :stars, default: 0, null: false
+ # t.text :title, limit: 128
+ # t.text :notes, limit: 1024
+ #
+ # t.check_constraint 'stars > 1000', name: 'so_many_stars'
+ # end
+ #
+ # See Rails' `create_table` for more info on the available arguments.
+ #
+ # When adding foreign keys to other tables, consider wrapping the call into a with_lock_retries block
+ # to avoid traffic stalls.
+ def create_table(table_name, *args, **kwargs, &block)
+ helper_context = self
+
+ super do |t|
+ t.define_singleton_method(:text) do |column_name, **kwargs|
+ limit = kwargs.delete(:limit)
+
+ super(column_name, **kwargs)
+
+ if limit
+ # rubocop:disable GitlabSecurity/PublicSend
+ name = helper_context.send(:text_limit_name, table_name, column_name)
+ # rubocop:enable GitlabSecurity/PublicSend
+
+ column_name = helper_context.quote_column_name(column_name)
+ definition = "char_length(#{column_name}) <= #{limit}"
+
+ t.check_constraint(definition, name: name)
+ end
+ end
+
+ t.instance_eval(&block) unless block.nil?
+ end
+ end
+
+ # Executes the block with a retry mechanism that alters the +lock_timeout+ and +sleep_time+ between attempts.
+ # The timings can be controlled via the +timing_configuration+ parameter.
+ # If the lock was not acquired within the retry period, a last attempt is made without using +lock_timeout+.
+ #
+ # In order to retry the block, the method wraps the block into a transaction.
+ #
+ # When called inside an open transaction it will execute the block directly if lock retries are enabled
+ # with `enable_lock_retries!` at migration level, otherwise it will raise an error.
+ #
+ # ==== Examples
+ # # Invoking without parameters
+ # with_lock_retries do
+ # drop_table :my_table
+ # end
+ #
+ # # Invoking with custom +timing_configuration+
+ # t = [
+ # [1.second, 1.second],
+ # [2.seconds, 2.seconds]
+ # ]
+ #
+ # with_lock_retries(timing_configuration: t) do
+ # drop_table :my_table # this will be retried twice
+ # end
+ #
+ # # Disabling the retries using an environment variable
+ # > export DISABLE_LOCK_RETRIES=true
+ #
+ # with_lock_retries do
+ # drop_table :my_table # one invocation, it will not retry at all
+ # end
+ #
+ # ==== Parameters
+ # * +timing_configuration+ - [[ActiveSupport::Duration, ActiveSupport::Duration], ...] lock timeout for the block, sleep time before the next iteration, defaults to `Gitlab::Database::WithLockRetries::DEFAULT_TIMING_CONFIGURATION`
+ # * +logger+ - [Gitlab::JsonLogger]
+ # * +env+ - [Hash] custom environment hash, see the example with `DISABLE_LOCK_RETRIES`
+ def with_lock_retries(*args, **kwargs, &block)
+ if transaction_open?
+ if enable_lock_retries?
+ Gitlab::AppLogger.warn 'Lock retries already enabled, executing the block directly'
+ yield
+ else
+ raise <<~EOF
+ #{__callee__} can not be run inside an already open transaction
+
+ Use migration-level lock retries instead, see https://docs.gitlab.com/ee/development/migration_style_guide.html#retry-mechanism-when-acquiring-database-locks
+ EOF
+ end
+ else
+ super(*args, **kwargs.merge(allow_savepoints: false), &block)
+ end
+ end
+
# Renames a column without requiring downtime.
#
# Concurrent renames work by using database triggers to ensure both the