Commit 01575e99 authored by Yorick Peterse's avatar Yorick Peterse

Reduce Namespace queries in UserReferenceFilter

This changes UserReferenceFilter so it operates using the following
steps:

1. Grab all username references from the input document.
2. Query the corresponding Namespace objects using a single query.
3. Iterate over all nodes to build links while re-using the objects
   queried in step 2.

The impact of these changes is that a comment mentioning 5 different
usernames no longer runs 5 different queries (1 for every username),
instead it only runs a single query.
parent 8a6c3f27
......@@ -26,6 +26,7 @@ v 8.9.0 (unreleased)
- Measure queue duration between gitlab-workhorse and Rails
- Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min)
- Reduce number of SQL queries when rendering user references
v 8.8.3
- Fix incorrect links on pipeline page when merge request created from fork
......
......@@ -29,7 +29,7 @@ module Banzai
ref_pattern = User.reference_pattern
ref_pattern_start = /\A#{ref_pattern}\z/
each_node do |node|
nodes.each do |node|
if text_node?(node)
replace_text_when_pattern_matches(node, ref_pattern) do |content|
user_link_filter(content)
......@@ -59,7 +59,7 @@ module Banzai
self.class.references_in(text) do |match, username|
if username == 'all'
link_to_all(link_text: link_text)
elsif namespace = Namespace.find_by(path: username)
elsif namespace = namespaces[username]
link_to_namespace(namespace, link_text: link_text) || match
else
match
......@@ -67,6 +67,31 @@ module Banzai
end
end
# Returns a Hash containing all Namespace objects for the username
# references in the current document.
#
# The keys of this Hash are the namespace paths, the values the
# corresponding Namespace objects.
def namespaces
@namespaces ||=
Namespace.where(path: usernames).each_with_object({}) do |row, hash|
hash[row.path] = row
end
end
# Returns all usernames referenced in the current document.
def usernames
refs = Set.new
nodes.each do |node|
node.to_html.scan(User.reference_pattern) do
refs << $~[:user]
end
end
refs.to_a
end
private
def urls
......
......@@ -136,4 +136,23 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
end
end
describe '#namespaces' do
it 'returns a Hash containing all Namespaces' do
document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
filter = described_class.new(document, project: project)
ns = user.namespace
expect(filter.namespaces).to eq({ ns.path => ns })
end
end
describe '#usernames' do
it 'returns the usernames mentioned in a document' do
document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
filter = described_class.new(document, project: project)
expect(filter.usernames).to eq([user.username])
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