From df9045fddfb740142aa93df0555aac12749412a2 Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu <heinrich@gitlab.com> Date: Wed, 4 Aug 2021 16:03:32 +0000 Subject: [PATCH] Revert "Merge branch '335733-recursive-ci-runners-query' into 'master'" This reverts merge request !65891 --- app/models/namespaces/traversal/linear.rb | 19 +++++- .../namespaces/traversal/linear_scopes.rb | 59 ------------------- app/models/namespaces/traversal/recursive.rb | 1 - .../namespaces/traversal/recursive_scopes.rb | 25 -------- spec/models/namespace_spec.rb | 16 +---- .../namespaces/linear_traversal_examples.rb | 23 ++++++++ .../namespaces/traversal_scope_examples.rb | 51 ---------------- 7 files changed, 40 insertions(+), 154 deletions(-) delete mode 100644 app/models/namespaces/traversal/linear_scopes.rb delete mode 100644 app/models/namespaces/traversal/recursive_scopes.rb create mode 100644 spec/support/shared_examples/namespaces/linear_traversal_examples.rb delete mode 100644 spec/support/shared_examples/namespaces/traversal_scope_examples.rb diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index 79df466fd641b..3d78f3846348e 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -37,7 +37,6 @@ module Namespaces module Traversal module Linear extend ActiveSupport::Concern - include LinearScopes UnboundedSearch = Class.new(StandardError) @@ -45,6 +44,14 @@ module Linear before_update :lock_both_roots, if: -> { sync_traversal_ids? && parent_id_changed? } 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) } + # When filtering namespaces by the traversal_ids column to compile a + # list of namespace IDs, it's much faster to reference the ID in + # traversal_ids than the primary key ID column. + # WARNING This scope must be used behind a linear query feature flag + # such as `use_traversal_ids`. + scope :as_ids, -> { select('traversal_ids[array_length(traversal_ids, 1)] AS id') } end def sync_traversal_ids? @@ -157,14 +164,20 @@ def lock_both_roots Namespace.lock.select(:id).where(id: roots).order(id: :asc).load 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: nil, bottom: nil, hierarchy_order: nil) raise UnboundedSearch, 'Must bound search by either top or bottom' unless top || bottom - skope = self.class.without_sti_condition + skope = without_sti_condition if top - skope = skope.where("traversal_ids @> ('{?}')", top.id) + skope = skope.traversal_ids_contains("{#{top.id}}") end if bottom diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb deleted file mode 100644 index f352497e6deca..0000000000000 --- a/app/models/namespaces/traversal/linear_scopes.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Namespaces - module Traversal - module LinearScopes - extend ActiveSupport::Concern - - class_methods do - # When filtering namespaces by the traversal_ids column to compile a - # list of namespace IDs, it can be faster to reference the ID in - # traversal_ids than the primary key ID column. - def as_ids - return super unless use_traversal_ids? - - select('namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)] AS id') - end - - def self_and_descendants - return super unless use_traversal_ids? - - without_dups = self_and_descendants_with_duplicates - .select('DISTINCT on(namespaces.id) namespaces.*') - - # Wrap the `SELECT DISTINCT on(....)` with a normal query so we - # retain expected Rails behavior. Otherwise count and other - # aggregates won't work. - unscoped.without_sti_condition.from(without_dups, :namespaces) - end - - def self_and_descendant_ids - return super unless use_traversal_ids? - - self_and_descendants_with_duplicates.select('DISTINCT namespaces.id') - 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 - unscope(where: :type) - end - - private - - def use_traversal_ids? - Feature.enabled?(:use_traversal_ids, default_enabled: :yaml) - end - - def self_and_descendants_with_duplicates - base_ids = select(:id) - - unscoped - .without_sti_condition - .from("namespaces, (#{base_ids.to_sql}) base") - .where('namespaces.traversal_ids @> ARRAY[base.id]') - end - end - end - end -end diff --git a/app/models/namespaces/traversal/recursive.rb b/app/models/namespaces/traversal/recursive.rb index c1ada715d6dcb..d9e8743aa50a3 100644 --- a/app/models/namespaces/traversal/recursive.rb +++ b/app/models/namespaces/traversal/recursive.rb @@ -4,7 +4,6 @@ module Namespaces module Traversal module Recursive extend ActiveSupport::Concern - include RecursiveScopes def root_ancestor return self if parent.nil? diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb deleted file mode 100644 index 0dcb23b656743..0000000000000 --- a/app/models/namespaces/traversal/recursive_scopes.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Namespaces - module Traversal - module RecursiveScopes - extend ActiveSupport::Concern - - class_methods do - def as_ids - select('id') - end - - def self_and_descendants - Gitlab::ObjectHierarchy.new(all).base_and_descendants - end - alias_method :recursive_self_and_descendants, :self_and_descendants - - def self_and_descendant_ids - self_and_descendants.as_ids - end - alias_method :recursive_self_and_descendant_ids, :self_and_descendant_ids - end - end - end -end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index e2700378f5f6a..b945fa34ebb4a 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -208,23 +208,9 @@ it { is_expected.to include_module(Gitlab::VisibilityLevel) } it { is_expected.to include_module(Namespaces::Traversal::Recursive) } it { is_expected.to include_module(Namespaces::Traversal::Linear) } - it { is_expected.to include_module(Namespaces::Traversal::RecursiveScopes) } - it { is_expected.to include_module(Namespaces::Traversal::LinearScopes) } end - context 'traversal scopes' do - context 'recursive' do - before do - stub_feature_flags(use_traversal_ids: false) - end - - it_behaves_like 'namespace traversal scopes' - end - - context 'linear' do - it_behaves_like 'namespace traversal scopes' - end - end + it_behaves_like 'linear namespace traversal' context 'traversal_ids on create' do context 'default traversal_ids' do diff --git a/spec/support/shared_examples/namespaces/linear_traversal_examples.rb b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb new file mode 100644 index 0000000000000..2fd90c36953b1 --- /dev/null +++ b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Traversal examples common to linear and recursive methods are in +# spec/support/shared_examples/namespaces/traversal_examples.rb + +RSpec.shared_examples 'linear namespace traversal' do + context 'when use_traversal_ids feature flag is enabled' do + before do + stub_feature_flags(use_traversal_ids: true) + end + + context 'scopes' do + describe '.as_ids' do + let_it_be(:namespace1) { create(:group) } + let_it_be(:namespace2) { create(:group) } + + subject { Namespace.where(id: [namespace1, namespace2]).as_ids.pluck(:id) } + + it { is_expected.to contain_exactly(namespace1.id, namespace2.id) } + end + end + end +end diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb deleted file mode 100644 index bc17d104034fc..0000000000000 --- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'namespace traversal scopes' do - # Hierarchy 1 - let_it_be(:group_1) { create(:group) } - let_it_be(:nested_group_1) { create(:group, parent: group_1) } - let_it_be(:deep_nested_group_1) { create(:group, parent: nested_group_1) } - - # Hierarchy 2 - let_it_be(:group_2) { create(:group) } - let_it_be(:nested_group_2) { create(:group, parent: group_2) } - let_it_be(:deep_nested_group_2) { create(:group, parent: nested_group_2) } - - # All groups - let_it_be(:groups) do - [ - group_1, nested_group_1, deep_nested_group_1, - group_2, nested_group_2, deep_nested_group_2 - ] - end - - describe '.as_ids' do - subject { described_class.where(id: [group_1, group_2]).as_ids.pluck(:id) } - - it { is_expected.to contain_exactly(group_1.id, group_2.id) } - end - - describe '.without_sti_condition' do - subject { described_class.without_sti_condition } - - it { expect(subject.where_values_hash).not_to have_key(:type) } - end - - describe '.self_and_descendants' do - subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendants } - - it { is_expected.to contain_exactly(nested_group_1, deep_nested_group_1, nested_group_2, deep_nested_group_2) } - - context 'with duplicate descendants' do - subject { described_class.where(id: [group_1, group_2, nested_group_1]).self_and_descendants } - - it { is_expected.to match_array(groups) } - end - end - - describe '.self_and_descendant_ids' do - subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendant_ids.pluck(:id) } - - it { is_expected.to contain_exactly(nested_group_1.id, deep_nested_group_1.id, nested_group_2.id, deep_nested_group_2.id) } - end -end -- GitLab