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-03-25 15:09:19 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-25 15:09:19 +0300
commita156fc95eb8499fec9cd081d30629f0faf18bfe9 (patch)
treeff59d44794ba9d8084e4d59057ec9507b3ba8e2f /app/models/namespaces/traversal/linear.rb
parent618be8f52d6349533c709a1d702e45b84338c36a (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models/namespaces/traversal/linear.rb')
-rw-r--r--app/models/namespaces/traversal/linear.rb48
1 files changed, 48 insertions, 0 deletions
diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb
index 8c042e5409d..294ef83b9b4 100644
--- a/app/models/namespaces/traversal/linear.rb
+++ b/app/models/namespaces/traversal/linear.rb
@@ -38,15 +38,31 @@ module Namespaces
module Linear
extend ActiveSupport::Concern
+ UnboundedSearch = Class.new(StandardError)
+
included do
after_create :sync_traversal_ids, if: -> { sync_traversal_ids? }
after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent_id? }
+
+ scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) }
end
def sync_traversal_ids?
Feature.enabled?(:sync_traversal_ids, root_ancestor, default_enabled: :yaml)
end
+ def use_traversal_ids?
+ Feature.enabled?(:use_traversal_ids, root_ancestor, default_enabled: :yaml)
+ end
+
+ def self_and_descendants
+ if use_traversal_ids?
+ lineage(self)
+ else
+ super
+ end
+ end
+
private
# Update the traversal_ids for the full hierarchy.
@@ -58,6 +74,38 @@ module Namespaces
Namespace::TraversalHierarchy.for_namespace(root_ancestor).sync_traversal_ids!
end
+
+ # Make sure we drop the STI `type = 'Group'` condition for better performance.
+ # Logically equivalent so long as hierarchies remain homogeneous.
+ def without_sti_condition
+ self.class.unscope(where: :type)
+ end
+
+ # Search this namespace's lineage. Bound inclusively by top node.
+ def lineage(top)
+ raise UnboundedSearch.new('Must bound search by a top') unless top
+
+ without_sti_condition
+ .traversal_ids_contains(latest_traversal_ids(top))
+ end
+
+ # traversal_ids are a cached value.
+ #
+ # The traversal_ids value in a loaded object can become stale when compared
+ # to the database value. For example, if you load a hierarchy and then move
+ # a group, any previously loaded descendant objects will have out of date
+ # traversal_ids.
+ #
+ # To solve this problem, we never depend on the object's traversal_ids
+ # value. We always query the database first with a sub-select for the
+ # latest traversal_ids.
+ #
+ # Note that ActiveRecord will cache query results. You can avoid this by
+ # using `Model.uncached { ... }`
+ def latest_traversal_ids(namespace = self)
+ without_sti_condition.where('id = (?)', namespace)
+ .select('traversal_ids as latest_traversal_ids')
+ end
end
end
end