Commit 57bde0ce authored by Yorick Peterse's avatar Yorick Peterse

Cache Banzai projects/objects using RequestStore

This was originally suggested by @ayufan and modified to be a bit
cleaner and use RequestStore instead of a regular Hash.

By caching the output of the two methods involved the number of queries
is reduced significantly. For example, for an issue with 200 notes (of
which 100 reference a number of merge requests) this cuts down the
amount of queries from around 6300 to around 3300.
parent fee7ad86
...@@ -214,7 +214,7 @@ gem 'jquery-rails', '~> 4.0.0' ...@@ -214,7 +214,7 @@ gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3' gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 5.0.0' gem 'jquery-ui-rails', '~> 5.0.0'
gem 'raphael-rails', '~> 2.1.2' gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0' gem 'request_store', '~> 1.3.0'
gem 'select2-rails', '~> 3.5.9' gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1' gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1' gem 'net-ssh', '~> 3.0.1'
......
...@@ -652,7 +652,7 @@ GEM ...@@ -652,7 +652,7 @@ GEM
redis-store (~> 1.1.0) redis-store (~> 1.1.0)
redis-store (1.1.7) redis-store (1.1.7)
redis (>= 2.2) redis (>= 2.2)
request_store (1.2.1) request_store (1.3.0)
rerun (0.11.0) rerun (0.11.0)
listen (~> 3.0) listen (~> 3.0)
responders (2.1.1) responders (2.1.1)
...@@ -1011,7 +1011,7 @@ DEPENDENCIES ...@@ -1011,7 +1011,7 @@ DEPENDENCIES
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis-namespace redis-namespace
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
request_store (~> 1.2.0) request_store (~> 1.3.0)
rerun (~> 0.11.0) rerun (~> 0.11.0)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 1.10.1) rouge (~> 1.10.1)
......
...@@ -62,11 +62,53 @@ module Banzai ...@@ -62,11 +62,53 @@ module Banzai
# Example: project.merge_requests.find # Example: project.merge_requests.find
end end
def find_object_cached(project, id)
if RequestStore.active?
cache = find_objects_cache[object_class][project.id]
if cache.key?(id)
cache[id]
else
cache[id] = find_object(project, id)
end
else
find_object(project, id)
end
end
def project_from_ref_cache(ref)
if RequestStore.active?
cache = project_refs_cache
if cache.key?(ref)
cache[ref]
else
cache[ref] = project_from_ref(ref)
end
else
project_from_ref(ref)
end
end
def url_for_object(object, project) def url_for_object(object, project)
# Implement in child class # Implement in child class
# Example: project_merge_request_url # Example: project_merge_request_url
end end
def url_for_object_cached(object, project)
if RequestStore.active?
cache = url_for_object_cache[object_class][project.id]
if cache.key?(object)
cache[object]
else
cache[object] = url_for_object(object, project)
end
else
url_for_object(object, project)
end
end
def call def call
if object_class.reference_pattern if object_class.reference_pattern
# `#123` # `#123`
...@@ -109,9 +151,9 @@ module Banzai ...@@ -109,9 +151,9 @@ module Banzai
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
def object_link_filter(text, pattern, link_text: nil) def object_link_filter(text, pattern, link_text: nil)
references_in(text, pattern) do |match, id, project_ref, matches| references_in(text, pattern) do |match, id, project_ref, matches|
project = project_from_ref(project_ref) project = project_from_ref_cache(project_ref)
if project && object = find_object(project, id) if project && object = find_object_cached(project, id)
title = object_link_title(object) title = object_link_title(object)
klass = reference_class(object_sym) klass = reference_class(object_sym)
...@@ -121,8 +163,11 @@ module Banzai ...@@ -121,8 +163,11 @@ module Banzai
object_sym => object.id object_sym => object.id
) )
url = matches[:url] if matches.names.include?("url") if matches.names.include?("url") && matches[:url]
url ||= url_for_object(object, project) url = matches[:url]
else
url = url_for_object_cached(object, project)
end
text = link_text || object_link_text(object, matches) text = link_text || object_link_text(object, matches)
...@@ -157,6 +202,24 @@ module Banzai ...@@ -157,6 +202,24 @@ module Banzai
text text
end end
private
def project_refs_cache
RequestStore[:banzai_project_refs] ||= {}
end
def find_objects_cache
RequestStore[:banzai_find_objects_cache] ||= Hash.new do |hash, key|
hash[key] = Hash.new { |h, k| h[k] = {} }
end
end
def url_for_object_cache
RequestStore[:banzai_url_for_object] ||= Hash.new do |hash, key|
hash[key] = Hash.new { |h, k| h[k] = {} }
end
end
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