1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #23756 from tenderlove/move_digest_cache

move digest cache on to the DetailsKey object
This commit is contained in:
Aaron Patterson 2016-02-18 09:23:59 -08:00
commit 3bd9fe1708
4 changed files with 28 additions and 14 deletions

View file

@ -4,13 +4,11 @@ require 'monitor'
module ActionView
class Digestor
cattr_reader(:cache)
@@cache = Concurrent::Map.new
@@digest_monitor = Monitor.new
class PerRequestDigestCacheExpiry < Struct.new(:app) # :nodoc:
def call(env)
ActionView::Digestor.cache.clear
ActionView::LookupContext::DetailsKey.clear
app.call(env)
end
end
@ -25,12 +23,12 @@ module ActionView
def digest(name:, finder:, **options)
options.assert_valid_keys(:dependencies, :partial)
cache_key = ([ name, finder.details_key.hash ].compact + Array.wrap(options[:dependencies])).join('.')
cache_key = ([ name ].compact + Array.wrap(options[:dependencies])).join('.')
# this is a correctly done double-checked locking idiom
# (Concurrent::Map's lookups have volatile semantics)
@@cache[cache_key] || @@digest_monitor.synchronize do
@@cache.fetch(cache_key) do # re-check under lock
finder.digest_cache[cache_key] || @@digest_monitor.synchronize do
finder.digest_cache.fetch(cache_key) do # re-check under lock
compute_and_store_digest(cache_key, name, finder, options)
end
end
@ -42,16 +40,16 @@ module ActionView
# Prevent re-entry or else recursive templates will blow the stack.
# There is no need to worry about other threads seeing the +false+ value,
# as they will then have to wait for this thread to let go of the @@digest_monitor lock.
pre_stored = @@cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion
pre_stored = finder.digest_cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion
PartialDigestor
else
Digestor
end
@@cache[cache_key] = stored_digest = klass.new(name, finder, options).digest
finder.digest_cache[cache_key] = stored_digest = klass.new(name, finder, options).digest
ensure
# something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
@@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
finder.digest_cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
end
end

View file

@ -69,6 +69,18 @@ module ActionView
def self.clear
@details_keys.clear
end
def self.empty?; @details_keys.empty?; end
def self.digest_caches
@details_keys.values.map(&:digest_cache)
end
attr_reader :digest_cache
def initialize
@digest_cache = Concurrent::Map.new
end
end
# Add caching behavior on top of Details.
@ -194,6 +206,10 @@ module ActionView
self.view_paths = view_paths
end
def digest_cache
details_key.digest_cache
end
def initialize_details(target, details)
registered_details.each do |k|
target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call

View file

@ -33,7 +33,6 @@ class TemplateDigestorTest < ActionView::TestCase
def teardown
Dir.chdir @cwd
FileUtils.rm_r @tmp_dir
ActionView::Digestor.cache.clear
end
def test_top_level_change_reflected
@ -301,12 +300,12 @@ class TemplateDigestorTest < ActionView::TestCase
def assert_digest_difference(template_name, options = {})
previous_digest = digest(template_name, options)
ActionView::Digestor.cache.clear
finder.digest_cache.clear
yield
assert_not_equal previous_digest, digest(template_name, options), "digest didn't change"
ActionView::Digestor.cache.clear
finder.digest_cache.clear
end
def digest(template_name, options = {})

View file

@ -50,12 +50,13 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase
get '/customers'
assert_equal 200, last_response.status
assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], ActionView::Digestor.cache.values
values = ActionView::LookupContext::DetailsKey.digest_caches.first.values
assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], values
assert_equal %w(david dingus), last_response.body.split.map(&:strip)
end
test "template digests are cleared before a request" do
assert_called(ActionView::Digestor.cache, :clear) do
assert_called(ActionView::LookupContext::DetailsKey, :clear) do
get '/customers'
assert_equal 200, last_response.status
end