diff options
author | Tom Clarke <tom@u2i.com> | 2012-05-21 09:41:04 -0400 |
---|---|---|
committer | Tom Clarke <tom@u2i.com> | 2012-05-21 15:24:15 -0400 |
commit | 63f3393f88a160d5bf87c84d7317a16379587280 (patch) | |
tree | c1321e2d5d84977ae0a0b84a6a1ba8337d2512e3 /actionpack | |
parent | 2a121870a6aba2b40d65e75d8fa4f7b959aac2c9 (diff) | |
download | rails-63f3393f88a160d5bf87c84d7317a16379587280.tar.gz rails-63f3393f88a160d5bf87c84d7317a16379587280.tar.bz2 rails-63f3393f88a160d5bf87c84d7317a16379587280.zip |
More granular locking of the Resolver template cache
In order to avoid holding a global lock when doing template
resolution, instead add individual locks on a per cache entry
basis. The global lock is now only used for manipulation of the main
cache data structure.
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/lib/action_view/template/resolver.rb | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index b33aebd3bc..8f87d6da8b 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -27,6 +27,16 @@ module ActionView # Threadsafe template cache class Cache #:nodoc: + class CacheEntry + attr_accessor :templates + + delegate :synchronize, :to => "@mutex" + + def initialize + @mutex = Mutex.new + end + end + def initialize @data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } @@ -35,24 +45,32 @@ module ActionView # Cache the templates returned by the block def cache(key, name, prefix, partial, locals) + cache_entry = nil + + # first obtain a lock on the main data structure to create the cache entry @mutex.synchronize do + cache_entry = @data[key][name][prefix][partial][locals] ||= CacheEntry.new + end + + # then to avoid a long lasting global lock, obtain a more granular lock + # on the CacheEntry itself + cache_entry.synchronize do if Resolver.caching? # all templates are cached forever the first time they are accessed - @data[key][name][prefix][partial][locals] ||= yield + cache_entry.templates ||= yield else # templates are still cached, but are only returned if they are # all still current fresh = yield - cache = @data[key][name][prefix][partial][locals] - mtime = cache && cache.map(&:updated_at).max + mtime = cache_entry.templates && cache_entry.templates.map(&:updated_at).max newer = !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } if newer - @data[key][name][prefix][partial][locals] = fresh + cache_entry.templates = fresh else - @data[key][name][prefix][partial][locals] + cache_entry.templates end end end |