diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
commit | 71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch) | |
tree | 6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /app/models/namespaces/traversal/linear.rb | |
parent | a7253423e3403b8c08f8a161e5937e1488f5f407 (diff) | |
download | gitlab-ce-71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e.tar.gz |
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'app/models/namespaces/traversal/linear.rb')
-rw-r--r-- | app/models/namespaces/traversal/linear.rb | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index 16a9c20dfdc..0e9760832af 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -47,6 +47,9 @@ module Namespaces # This uses rails internal before_commit API to sync traversal_ids on namespace create, right before transaction is committed. # This helps reduce the time during which the root namespace record is locked to ensure updated traversal_ids are valid before_commit :sync_traversal_ids, on: [:create] + after_commit :set_traversal_ids, + if: -> { traversal_ids.empty? || saved_change_to_parent_id? }, + on: [:create, :update] define_model_callbacks :sync_traversal_ids end @@ -78,6 +81,15 @@ module Namespaces end end + def traversal_ids=(ids) + super(ids) + self.transient_traversal_ids = nil + end + + def traversal_ids + read_attribute(:traversal_ids).presence || transient_traversal_ids || [] + end + def use_traversal_ids? return false unless Feature.enabled?(:use_traversal_ids) @@ -174,12 +186,11 @@ module Namespaces # we need to preserve those specific parameters for super. hierarchy_order ||= :desc - # Get all ancestor IDs inclusively between top and our parent. - top_index = top ? traversal_ids.find_index(top.id) : 0 - ids = traversal_ids[top_index...-1] - ids_string = ids.map { |id| Integer(id) }.join(',') + top_index = ancestors_upto_top_index(top) + ids = traversal_ids[top_index...-1].reverse # WITH ORDINALITY lets us order the result to match traversal_ids order. + ids_string = ids.map { |id| Integer(id) }.join(',') from_sql = <<~SQL unnest(ARRAY[#{ids_string}]::bigint[]) WITH ORDINALITY AS ancestors(id, ord) INNER JOIN namespaces ON namespaces.id = ancestors.id @@ -206,6 +217,8 @@ module Namespaces private + attr_accessor :transient_traversal_ids + # Update the traversal_ids for the full hierarchy. # # NOTE: self.traversal_ids will be stale. Reload for a fresh record. @@ -218,6 +231,27 @@ module Namespaces end end + def set_traversal_ids + # This is a temporary guard and will be removed. + return if is_a?(Namespaces::ProjectNamespace) + + return unless Feature.enabled?(:set_traversal_ids_on_save, root_ancestor) + + self.transient_traversal_ids = if parent_id + parent.traversal_ids + [id] + else + [id] + end + + # Clear root_ancestor memo if changed. + if read_attribute(traversal_ids)&.first != transient_traversal_ids.first + clear_memoization(:root_ancestor) + end + + # Update traversal_ids for any associated child objects. + children.each(&:reload) if children.loaded? + end + # Lock the root of the hierarchy we just left, and lock the root of the hierarchy # we just joined. In most cases the two hierarchies will be the same. def lock_both_roots @@ -266,6 +300,17 @@ module Namespaces skope end + + def ancestors_upto_top_index(top) + return 0 if top.nil? + + index = traversal_ids.find_index(top.id) + if index.nil? + 0 + else + index + 1 + end + end end end end |