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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-01 09:09:00 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-01 09:09:00 +0300
commitdbc554cda7f86f22d34fd1e3a4ec4ab677d55879 (patch)
treee4a8f34cf3e1494b29c1eaaa021ea0e1dfc8f7e5 /app/models
parenta3c1c29aa588228a2ae9c000620d1b73ff159fe3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models')
-rw-r--r--app/models/concerns/loose_foreign_key.rb95
-rw-r--r--app/models/environment.rb41
2 files changed, 100 insertions, 36 deletions
diff --git a/app/models/concerns/loose_foreign_key.rb b/app/models/concerns/loose_foreign_key.rb
new file mode 100644
index 00000000000..4e822a04869
--- /dev/null
+++ b/app/models/concerns/loose_foreign_key.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+module LooseForeignKey
+ extend ActiveSupport::Concern
+
+ # This concern adds loose foreign key support to ActiveRecord models.
+ # Loose foreign keys allow delayed processing of associated database records
+ # with similar guarantees than a database foreign key.
+ #
+ # TODO: finalize this later once the async job is in place
+ #
+ # Prerequisites:
+ #
+ # To start using the concern, you'll need to install a database trigger to the parent
+ # table in a standard DB migration (not post-migration).
+ #
+ # > add_loose_foreign_key_support(:projects, :gitlab_main)
+ #
+ # Usage:
+ #
+ # > class Ci::Build < ApplicationRecord
+ # >
+ # > loose_foreign_key :security_scans, :build_id, on_delete: :async_delete, gitlab_schema: :gitlab_main
+ # >
+ # > # associations can be still defined, the dependent options is no longer necessary:
+ # > has_many :security_scans, class_name: 'Security::Scan'
+ # >
+ # > end
+ #
+ # Options for on_delete:
+ #
+ # - :async_delete - deletes the children rows via an asynchronous process.
+ # - :async_nullify - sets the foreign key column to null via an asynchronous process.
+ #
+ # Options for gitlab_schema:
+ #
+ # - :gitlab_ci
+ # - :gitlab_main
+ #
+ # The value can be determined by calling `Model.gitlab_schema` where the Model represents
+ # the model for the child table.
+ #
+ # How it works:
+ #
+ # When adding loose foreign key support to the table, a DELETE trigger is installed
+ # which tracks the record deletions (stores primary key value of the deleted row) in
+ # a database table.
+ #
+ # These deletion records are processed asynchronously and records are cleaned up
+ # according to the loose foreign key definitions described in the model.
+ #
+ # The cleanup happens in batches, which reduces the likelyhood of statement timeouts.
+ #
+ # When all associations related to the deleted record are cleaned up, the record itself
+ # is deleted.
+ included do
+ class_attribute :loose_foreign_key_definitions, default: []
+ end
+
+ class_methods do
+ def loose_foreign_key(to_table, column, options)
+ symbolized_options = options.symbolize_keys
+
+ unless base_class?
+ raise <<~MSG
+ loose_foreign_key can be only used on base classes, inherited classes are not supported.
+ Please define the loose_foreign_key on the #{base_class.name} class.
+ MSG
+ end
+
+ on_delete_options = %i[async_delete async_nullify]
+ gitlab_schema_options = [ApplicationRecord.gitlab_schema, Ci::ApplicationRecord.gitlab_schema]
+
+ unless on_delete_options.include?(symbolized_options[:on_delete]&.to_sym)
+ raise "Invalid on_delete option given: #{symbolized_options[:on_delete]}. Valid options: #{on_delete_options.join(', ')}"
+ end
+
+ unless gitlab_schema_options.include?(symbolized_options[:gitlab_schema]&.to_sym)
+ raise "Invalid gitlab_schema option given: #{symbolized_options[:gitlab_schema]}. Valid options: #{gitlab_schema_options.join(', ')}"
+ end
+
+ definition = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
+ table_name.to_s,
+ to_table.to_s,
+ {
+ column: column.to_s,
+ on_delete: symbolized_options[:on_delete].to_sym,
+ gitlab_schema: symbolized_options[:gitlab_schema].to_sym
+ }
+ )
+
+ self.loose_foreign_key_definitions += [definition]
+ end
+ end
+end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 963249c018a..a4084565579 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -77,6 +77,7 @@ class Environment < ApplicationRecord
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
scope :preload_cluster, -> { preload(last_deployment: :cluster) }
+ scope :preload_project, -> { preload(:project) }
scope :auto_stoppable, -> (limit) { available.where('auto_stop_at < ?', Time.zone.now).limit(limit) }
scope :auto_deletable, -> (limit) { stopped.where('auto_delete_at < ?', Time.zone.now).limit(limit) }
@@ -132,6 +133,10 @@ class Environment < ApplicationRecord
state :available
state :stopped
+ before_transition any => :stopped do |environment|
+ environment.auto_stop_at = nil
+ end
+
after_transition do |environment|
environment.expire_etag_cache
end
@@ -168,33 +173,6 @@ class Environment < ApplicationRecord
end
class << self
- ##
- # This method returns stop actions (jobs) for multiple environments within one
- # query. It's useful to avoid N+1 problem.
- #
- # NOTE: The count of environments should be small~medium (e.g. < 5000)
- def stop_actions
- cte = cte_for_deployments_with_stop_action
- ci_builds = Ci::Build.arel_table
-
- inner_join_stop_actions = ci_builds.join(cte.table).on(
- ci_builds[:project_id].eq(cte.table[:project_id])
- .and(ci_builds[:ref].eq(cte.table[:ref]))
- .and(ci_builds[:name].eq(cte.table[:on_stop]))
- ).join_sources
-
- pipeline_ids = ci_builds.join(cte.table).on(
- ci_builds[:id].eq(cte.table[:deployable_id])
- ).project(:commit_id)
-
- Ci::Build.joins(inner_join_stop_actions)
- .with(cte.to_arel)
- .where(ci_builds[:commit_id].in(pipeline_ids))
- .where(status: Ci::HasStatus::BLOCKED_STATUS)
- .preload_project_and_pipeline_project
- .preload(:user, :metadata, :deployment)
- end
-
def count_by_state
environments_count_by_state = group(:state).count
@@ -202,15 +180,6 @@ class Environment < ApplicationRecord
count_hash[state] = environments_count_by_state[state.to_s] || 0
end
end
-
- private
-
- def cte_for_deployments_with_stop_action
- Gitlab::SQL::CTE.new(:deployments_with_stop_action,
- Deployment.where(environment_id: select(:id))
- .distinct_on_environment
- .stoppable)
- end
end
def clear_prometheus_reactive_cache!(query_name)