mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Remove cache from Template::Resolver
This commit is contained in:
parent
76561430e5
commit
4db7ae52f8
3 changed files with 1 additions and 112 deletions
|
@ -49,84 +49,18 @@ module ActionView
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Threadsafe template cache
|
|
||||||
class Cache # :nodoc:
|
|
||||||
class SmallCache < Concurrent::Map
|
|
||||||
def initialize(options = {})
|
|
||||||
super(options.merge(initial_capacity: 2))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Preallocate all the default blocks for performance/memory consumption reasons
|
|
||||||
PARTIAL_BLOCK = lambda { |cache, partial| cache[partial] = SmallCache.new }
|
|
||||||
PREFIX_BLOCK = lambda { |cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK) }
|
|
||||||
NAME_BLOCK = lambda { |cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK) }
|
|
||||||
KEY_BLOCK = lambda { |cache, key| cache[key] = SmallCache.new(&NAME_BLOCK) }
|
|
||||||
|
|
||||||
# Usually a majority of template look ups return nothing, use this canonical preallocated array to save memory
|
|
||||||
NO_TEMPLATES = [].freeze
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@data = SmallCache.new(&KEY_BLOCK)
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
"#{to_s[0..-2]} keys=#{@data.size}>"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Cache the templates returned by the block
|
|
||||||
def cache(key, name, prefix, partial, locals)
|
|
||||||
@data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear
|
|
||||||
@data.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the cache size. Do not call this
|
|
||||||
# method. This method is not guaranteed to be here ever.
|
|
||||||
def size # :nodoc:
|
|
||||||
size = 0
|
|
||||||
@data.each_value do |v1|
|
|
||||||
v1.each_value do |v2|
|
|
||||||
v2.each_value do |v3|
|
|
||||||
v3.each_value do |v4|
|
|
||||||
size += v4.size
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
size
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def canonical_no_templates(templates)
|
|
||||||
templates.empty? ? NO_TEMPLATES : templates
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
cattr_accessor :caching, default: true
|
cattr_accessor :caching, default: true
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
alias :caching? :caching
|
alias :caching? :caching
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
|
||||||
@cache = Cache.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_cache
|
def clear_cache
|
||||||
@cache.clear
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Normalizes the arguments and passes it on to find_templates.
|
# Normalizes the arguments and passes it on to find_templates.
|
||||||
def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
|
def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
|
||||||
locals = locals.map(&:to_s).sort!.freeze
|
_find_all(name, prefix, partial, details, key, locals)
|
||||||
|
|
||||||
cached(key, [name, prefix, partial], details, locals) do
|
|
||||||
_find_all(name, prefix, partial, details, key, locals)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def all_template_paths # :nodoc:
|
def all_template_paths # :nodoc:
|
||||||
|
@ -147,22 +81,6 @@ module ActionView
|
||||||
def find_templates(name, prefix, partial, details, locals = [])
|
def find_templates(name, prefix, partial, details, locals = [])
|
||||||
raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, locals = []) method"
|
raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, locals = []) method"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Handles templates caching. If a key is given and caching is on
|
|
||||||
# always check the cache before hitting the resolver. Otherwise,
|
|
||||||
# it always hits the resolver but if the key is present, check if the
|
|
||||||
# resolver is fresher before returning it.
|
|
||||||
def cached(key, path_info, details, locals)
|
|
||||||
name, prefix, partial = path_info
|
|
||||||
|
|
||||||
if key
|
|
||||||
@cache.cache(key, name, prefix, partial, locals) do
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
else
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A resolver that loads files from the filesystem.
|
# A resolver that loads files from the filesystem.
|
||||||
|
|
|
@ -285,25 +285,6 @@ module AbstractControllerTests
|
||||||
assert_equal "With String hello less than 3 bar", controller.response_body
|
assert_equal "With String hello less than 3 bar", controller.response_body
|
||||||
end
|
end
|
||||||
|
|
||||||
test "cache should not grow when locals change for a string template" do
|
|
||||||
cache = WithString.view_paths.paths.first.instance_variable_get(:@cache)
|
|
||||||
|
|
||||||
controller = WithString.new
|
|
||||||
controller.process(:index) # heat the cache
|
|
||||||
|
|
||||||
size = cache.size
|
|
||||||
|
|
||||||
10.times do |x|
|
|
||||||
controller = WithString.new
|
|
||||||
controller.define_singleton_method :index do
|
|
||||||
render template: ActionView::Template::Text.new("Hello string!"), locals: { "x#{x}": :omg }
|
|
||||||
end
|
|
||||||
controller.process(:index)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal size, cache.size
|
|
||||||
end
|
|
||||||
|
|
||||||
test "when layout is specified as a string, render with that layout" do
|
test "when layout is specified as a string, render with that layout" do
|
||||||
controller = WithString.new
|
controller = WithString.new
|
||||||
controller.process(:index)
|
controller.process(:index)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "abstract_unit"
|
|
||||||
|
|
||||||
class ResolverCacheTest < ActiveSupport::TestCase
|
|
||||||
def test_inspect_shields_cache_internals
|
|
||||||
ActionView::LookupContext::DetailsKey.clear
|
|
||||||
assert_match %r(#<ActionView::Resolver:0x[0-9a-f]+ @cache=#<ActionView::Resolver::Cache:0x[0-9a-f]+ keys=0>>), ActionView::Resolver.new.inspect
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in a new issue