Commit 20f78421 authored by Bob Van Landuyt's avatar Bob Van Landuyt

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.
parent 07aaa59b
...@@ -139,8 +139,18 @@ class Namespace < ActiveRecord::Base ...@@ -139,8 +139,18 @@ class Namespace < ActiveRecord::Base
def find_fork_of(project) def find_fork_of(project)
return nil unless project.fork_network return nil unless project.fork_network
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 project.fork_network.find_forks_in(projects).first
end end
end
def lfs_enabled? def lfs_enabled?
# User namespace will always default to the global setting # User namespace will always default to the global setting
......
---
title: Reduce requests for project forks on show page of projects that have forks
merge_request: 15663
author:
type: performance
...@@ -261,6 +261,29 @@ describe ProjectsController do ...@@ -261,6 +261,29 @@ describe ProjectsController do
expect(response).to redirect_to(namespace_project_path) expect(response).to redirect_to(namespace_project_path)
end end
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 end
describe "#update" do describe "#update" do
......
...@@ -531,7 +531,7 @@ describe Namespace do ...@@ -531,7 +531,7 @@ describe Namespace do
end end
end end
describe '#has_forks_of?' do describe '#find_fork_of?' do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let!(:forked_project) { fork_project(project, namespace.owner, namespace: namespace) } let!(:forked_project) { fork_project(project, namespace.owner, namespace: namespace) }
...@@ -550,5 +550,13 @@ describe Namespace do ...@@ -550,5 +550,13 @@ describe Namespace do
expect(other_namespace.find_fork_of(project)).to eq(other_fork) expect(other_namespace.find_fork_of(project)).to eq(other_fork)
end 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
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment