Commit 04a882d8 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'bvl-limit-fork-queries-on-project-show' into 'master'

Cache the forks in a namespace in the RequestStore

Closes #40625

See merge request gitlab-org/gitlab-ce!15663
parents 4258bfcb 3d4ba90c
...@@ -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,27 @@ describe ProjectsController do ...@@ -261,6 +261,27 @@ 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) }
let(:other_user) { create(:user) }
render_views
before do
# View the project as a user that does not have any rights
sign_in(other_user)
fork_project(public_project)
end
it 'does not increase the number of queries when the project is forked' do
expected_query = /#{public_project.fork_network.find_forks_in(other_user.namespace).to_sql}/
expect { get(:show, namespace_id: public_project.namespace, id: public_project) }
.not_to exceed_query_limit(1).for_query(expected_query)
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
...@@ -41,7 +41,8 @@ RSpec::Matchers.define :exceed_query_limit do |expected| ...@@ -41,7 +41,8 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
supports_block_expectations supports_block_expectations
match do |block| match do |block|
query_count(&block) > expected_count + threshold @subject_block = block
actual_count > expected_count + threshold
end end
failure_message_when_negated do |actual| failure_message_when_negated do |actual|
...@@ -55,6 +56,11 @@ RSpec::Matchers.define :exceed_query_limit do |expected| ...@@ -55,6 +56,11 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
self self
end end
def for_query(query)
@query = query
self
end
def threshold def threshold
@threshold.to_i @threshold.to_i
end end
...@@ -68,12 +74,15 @@ RSpec::Matchers.define :exceed_query_limit do |expected| ...@@ -68,12 +74,15 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
end end
def actual_count def actual_count
@recorder.count @actual_count ||= if @query
recorder.log.select { |recorded| recorded =~ @query }.size
else
recorder.count
end
end end
def query_count(&block) def recorder
@recorder = ActiveRecord::QueryRecorder.new(&block) @recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block)
@recorder.count
end end
def count_queries(queries) def count_queries(queries)
......
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