summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Van Landuyt <bob@vanlanduyt.co>2017-11-30 14:26:08 +0100
committerBob Van Landuyt <bob@vanlanduyt.co>2017-12-04 17:43:48 +0100
commit20f78421c82d626a3b43924146b7878fe4777ae8 (patch)
treeb24c602574cb20c907a1ac228c8b00c104cbc836
parent07aaa59b1c28bc7be9fdd98c9334522f60306723 (diff)
downloadgitlab-ce-20f78421c82d626a3b43924146b7878fe4777ae8.tar.gz
Cache the forks in a namespace in the RequestStore
On the `show` of a project that is part of a fork network. We check if the user already created a fork of this project in their personal namespace. We do this in several places, so caching the result of this query in the request store prevents us from repeating it.
-rw-r--r--app/models/namespace.rb12
-rw-r--r--changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml5
-rw-r--r--spec/controllers/projects_controller_spec.rb23
-rw-r--r--spec/models/namespace_spec.rb10
4 files changed, 48 insertions, 2 deletions
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index fa76729a702..901dbf2ba69 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -139,7 +139,17 @@ class Namespace < ActiveRecord::Base
def find_fork_of(project)
return nil unless project.fork_network
- project.fork_network.find_forks_in(projects).first
+ if RequestStore.active?
+ forks_in_namespace = RequestStore.fetch("namespaces:#{id}:forked_projects") do
+ Hash.new do |found_forks, project|
+ found_forks[project] = project.fork_network.find_forks_in(projects).first
+ end
+ end
+
+ forks_in_namespace[project]
+ else
+ project.fork_network.find_forks_in(projects).first
+ end
end
def lfs_enabled?
diff --git a/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml b/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml
new file mode 100644
index 00000000000..299d9bf6b9c
--- /dev/null
+++ b/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce requests for project forks on show page of projects that have forks
+merge_request: 15663
+author:
+type: performance
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index e7ab714c550..39ee5e8691b 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -261,6 +261,29 @@ describe ProjectsController do
expect(response).to redirect_to(namespace_project_path)
end
end
+
+ context 'when the project is forked and has a repository', :request_store do
+ let(:public_project) { create(:project, :public, :repository) }
+
+ render_views
+
+ before do
+ # View the project as a user that does not have any rights
+ sign_in(create(:user))
+
+ fork_project(public_project)
+ end
+
+ it 'does not increase the number of queries when the project is forked' do
+ # When a project is part of a fork network, we check if the `current_user`
+ # has a fork in their own namespace. We query this several times. Caching
+ # the result in the RequestStore brings the number of queries for this
+ # request down from 64 to 59.
+
+ expect { get(:show, namespace_id: public_project.namespace, id: public_project) }
+ .not_to exceed_query_limit(59)
+ end
+ end
end
describe "#update" do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 90b768f595e..3817f20bfe7 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -531,7 +531,7 @@ describe Namespace do
end
end
- describe '#has_forks_of?' do
+ describe '#find_fork_of?' do
let(:project) { create(:project, :public) }
let!(:forked_project) { fork_project(project, namespace.owner, namespace: namespace) }
@@ -550,5 +550,13 @@ describe Namespace do
expect(other_namespace.find_fork_of(project)).to eq(other_fork)
end
+
+ context 'with request store enabled', :request_store do
+ it 'only queries once' do
+ expect(project.fork_network).to receive(:find_forks_in).once.and_call_original
+
+ 2.times { namespace.find_fork_of(project) }
+ end
+ end
end
end