From 5bffbad5917195c4eff72570a5798e5a5aa81d29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= <fjlopez@gitlab.com>
Date: Mon, 20 Sep 2021 13:06:13 +0200
Subject: [PATCH] Use GroupPlansPreloader linear ancestor scopes

In this commit we're replacing the recursive ancestors scope in
the `GroupPlansPreloader` class, for their linear version.

Changelog: performance
EE: true
---
 ..._group_plans_preloaded_ancestor_scopes.yml |  8 +++
 ee/lib/gitlab/group_plans_preloader.rb        | 12 +++--
 .../lib/gitlab/group_plans_preloader_spec.rb  | 50 ++++++++++++-------
 3 files changed, 48 insertions(+), 22 deletions(-)
 create mode 100644 config/feature_flags/development/linear_group_plans_preloaded_ancestor_scopes.yml

diff --git a/config/feature_flags/development/linear_group_plans_preloaded_ancestor_scopes.yml b/config/feature_flags/development/linear_group_plans_preloaded_ancestor_scopes.yml
new file mode 100644
index 0000000000000000..d45b8d71a20cacc6
--- /dev/null
+++ b/config/feature_flags/development/linear_group_plans_preloaded_ancestor_scopes.yml
@@ -0,0 +1,8 @@
+---
+name: linear_group_plans_preloaded_ancestor_scopes
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70685
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341349
+milestone: '14.4'
+type: development
+group: group::access
+default_enabled: false
diff --git a/ee/lib/gitlab/group_plans_preloader.rb b/ee/lib/gitlab/group_plans_preloader.rb
index fb28ad93b056a0f1..ae18d578c1d2a294 100644
--- a/ee/lib/gitlab/group_plans_preloader.rb
+++ b/ee/lib/gitlab/group_plans_preloader.rb
@@ -57,9 +57,15 @@ def preload(groups)
     # Returns an ActiveRecord::Relation that includes the given groups, and all
     # their (recursive) ancestors.
     def groups_and_ancestors_for(groups)
-      Gitlab::ObjectHierarchy
-        .new(groups)
-        .base_and_ancestors
+      groups_and_ancestors = if ::Feature.enabled?(:linear_group_plans_preloaded_ancestor_scopes, default_enabled: :yaml)
+                               groups.self_and_ancestors
+                             else
+                               Gitlab::ObjectHierarchy
+                                 .new(groups)
+                                 .base_and_ancestors
+                             end
+
+      groups_and_ancestors
         .join_gitlab_subscription
         .select('namespaces.id', 'namespaces.parent_id', 'gitlab_subscriptions.hosted_plan_id')
     end
diff --git a/ee/spec/lib/gitlab/group_plans_preloader_spec.rb b/ee/spec/lib/gitlab/group_plans_preloader_spec.rb
index 2a7f68f5d3e10b1b..d9a185f30e56aedd 100644
--- a/ee/spec/lib/gitlab/group_plans_preloader_spec.rb
+++ b/ee/spec/lib/gitlab/group_plans_preloader_spec.rb
@@ -23,30 +23,42 @@
       create(:group, name: 'group-3', parent: group1)
     end
 
-    it 'only executes three SQL queries to preload the data' do
-      amount = ActiveRecord::QueryRecorder
-        .new { preloaded_groups }
-        .count
-
-      # One query to get the groups and their ancestors, one query to get their
-      # plans, and one query to _just_ get the groups.
-      expect(amount).to eq(3)
-    end
+    shared_examples 'preloading cases' do
+      it 'only executes three SQL queries to preload the data' do
+        amount = ActiveRecord::QueryRecorder
+          .new { preloaded_groups }
+          .count
+
+        # One query to get the groups and their ancestors, one query to get their
+        # plans, and one query to _just_ get the groups.
+        expect(amount).to eq(3)
+      end
+
+      it 'associates the correct plans with the correct groups' do
+        expect(preloaded_groups[0].plans).to match_array([plan1])
+        expect(preloaded_groups[1].plans).to match_array([plan2])
+        expect(preloaded_groups[2].plans).to match_array([plan1])
+      end
+
+      it 'does not execute any queries for preloaded plans' do
+        preloaded_groups
+
+        amount = ActiveRecord::QueryRecorder
+          .new { preloaded_groups.each(&:plans) }
+          .count
 
-    it 'associates the correct plans with the correct groups' do
-      expect(preloaded_groups[0].plans).to eq([plan1])
-      expect(preloaded_groups[1].plans).to eq([plan2])
-      expect(preloaded_groups[2].plans).to eq([plan1])
+        expect(amount).to be_zero
+      end
     end
 
-    it 'does not execute any queries for preloaded plans' do
-      preloaded_groups
+    it_behaves_like 'preloading cases'
 
-      amount = ActiveRecord::QueryRecorder
-        .new { preloaded_groups.each(&:plans) }
-        .count
+    context 'when feature flag :linear_group_plans_preloaded_ancestor_scopes is disabled' do
+      before do
+        stub_feature_flags(linear_group_plans_preloaded_ancestor_scopes: false)
+      end
 
-      expect(amount).to be_zero
+      it_behaves_like 'preloading cases'
     end
   end
 end
-- 
GitLab