aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support/cache.rb66
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb60
2 files changed, 75 insertions, 51 deletions
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 5a5548d567..6a1f1fefb8 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -275,34 +275,14 @@ module ActiveSupport
if block_given?
options = merged_options(options)
key = namespaced_key(name, options)
- unless options[:force]
- entry = instrument(:read, name, options) do |payload|
- payload[:super_operation] = :fetch if payload
- read_entry(key, options)
- end
- end
- if entry && entry.expired?
- race_ttl = options[:race_condition_ttl].to_i
- if race_ttl && (Time.now - entry.expires_at <= race_ttl)
- # When an entry has :race_condition_ttl defined, put the stale entry back into the cache
- # for a brief period while the entry is begin recalculated.
- entry.expires_at = Time.now + race_ttl
- write_entry(key, entry, :expires_in => race_ttl * 2)
- else
- delete_entry(key, options)
- end
- entry = nil
- end
+
+ cached_entry = find_cached_entry(key, name, options) unless options[:force]
+ entry = handle_expired_entry(cached_entry, key, options)
if entry
- instrument(:fetch_hit, name, options) { |payload| }
- entry.value
+ get_entry_value(entry, name, options)
else
- result = instrument(:generate, name, options) do |payload|
- yield(name)
- end
- write(name, result, options)
- result
+ save_block_result_to_cache(name, options) { |name| yield name }
end
else
read(name, options)
@@ -531,6 +511,42 @@ module ActiveSupport
return unless logger && logger.debug? && !silence?
logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
end
+
+ def find_cached_entry(key, name, options)
+ instrument(:read, name, options) do |payload|
+ payload[:super_operation] = :fetch if payload
+ read_entry(key, options)
+ end
+ end
+
+ def handle_expired_entry(entry, key, options)
+ if entry && entry.expired?
+ race_ttl = options[:race_condition_ttl].to_i
+ if race_ttl && (Time.now - entry.expires_at <= race_ttl)
+ # When an entry has :race_condition_ttl defined, put the stale entry back into the cache
+ # for a brief period while the entry is begin recalculated.
+ entry.expires_at = Time.now + race_ttl
+ write_entry(key, entry, :expires_in => race_ttl * 2)
+ else
+ delete_entry(key, options)
+ end
+ entry = nil
+ end
+ entry
+ end
+
+ def get_entry_value(entry, name, options)
+ instrument(:fetch_hit, name, options) { |payload| }
+ entry.value
+ end
+
+ def save_block_result_to_cache(name, options)
+ result = instrument(:generate, name, options) do |payload|
+ yield(name)
+ end
+ write(name, result, options)
+ result
+ end
end
# This class is used to represent cache entries. Cache entries have a value and an optional
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index aa87598926..e4f8959e7a 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -43,32 +43,36 @@ module ActiveSupport
module Isolation
require 'thread'
- class ParallelEach
- include Enumerable
-
- # default to 2 cores
- CORES = (ENV['TEST_CORES'] || 2).to_i
-
- def initialize list
- @list = list
- @queue = SizedQueue.new CORES
- end
+ # Recent versions of MiniTest (such as the one shipped with Ruby 2.0) already define
+ # a ParallelEach class.
+ unless defined? ParallelEach
+ class ParallelEach
+ include Enumerable
+
+ # default to 2 cores
+ CORES = (ENV['TEST_CORES'] || 2).to_i
+
+ def initialize list
+ @list = list
+ @queue = SizedQueue.new CORES
+ end
- def grep pattern
- self.class.new super
- end
+ def grep pattern
+ self.class.new super
+ end
- def each
- threads = CORES.times.map {
- Thread.new {
- while job = @queue.pop
- yield job
- end
+ def each
+ threads = CORES.times.map {
+ Thread.new {
+ while job = @queue.pop
+ yield job
+ end
+ }
}
- }
- @list.each { |i| @queue << i }
- CORES.times { @queue << nil }
- threads.each(&:join)
+ @list.each { |i| @queue << i }
+ CORES.times { @queue << nil }
+ threads.each(&:join)
+ end
end
end
@@ -84,10 +88,14 @@ module ActiveSupport
!ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
end
+ @@class_setup_mutex = Mutex.new
+
def _run_class_setup # class setup method should only happen in parent
- unless defined?(@@ran_class_setup) || ENV['ISOLATION_TEST']
- self.class.setup if self.class.respond_to?(:setup)
- @@ran_class_setup = true
+ @@class_setup_mutex.synchronize do
+ unless defined?(@@ran_class_setup) || ENV['ISOLATION_TEST']
+ self.class.setup if self.class.respond_to?(:setup)
+ @@ran_class_setup = true
+ end
end
end