diff options
author | Yorick Peterse <yorickpeterse@gmail.com> | 2016-03-24 17:53:38 +0300 |
---|---|---|
committer | Yorick Peterse <yorickpeterse@gmail.com> | 2016-04-04 11:44:35 +0300 |
commit | 57bde0ce65caf2cbbb6a57f21435639cdaa06225 (patch) | |
tree | 3ed5e29ecdaa249bcde9a6fdb3ee7ab5732d644a /lib | |
parent | fee7ad86273b17100d541b68c670a20ca954d673 (diff) |
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.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/banzai/filter/abstract_reference_filter.rb | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 34c38913474..41fd4be76ac 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -62,11 +62,53 @@ module Banzai # Example: project.merge_requests.find 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) # Implement in child class # Example: project_merge_request_url 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 if object_class.reference_pattern # `#123` @@ -109,9 +151,9 @@ module Banzai # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. def object_link_filter(text, pattern, link_text: nil) 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) klass = reference_class(object_sym) @@ -121,8 +163,11 @@ module Banzai object_sym => object.id ) - url = matches[:url] if matches.names.include?("url") - url ||= url_for_object(object, project) + if matches.names.include?("url") && matches[:url] + url = matches[:url] + else + url = url_for_object_cached(object, project) + end text = link_text || object_link_text(object, matches) @@ -157,6 +202,24 @@ module Banzai text 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 |