diff options
-rw-r--r-- | activesupport/lib/active_support/cache.rb | 32 | ||||
-rw-r--r-- | activesupport/test/caching_test.rb | 67 |
2 files changed, 78 insertions, 21 deletions
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 3e3dc18263..57c6a6331d 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -21,7 +21,7 @@ module ActiveSupport expanded_cache_key = namespace ? "#{namespace}/" : "" if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"] - expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/" + expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/" end expanded_cache_key << case @@ -40,13 +40,8 @@ module ActiveSupport class Store cattr_accessor :logger - def initialize - end - def threadsafe! - @mutex = Mutex.new - self.class.send :include, ThreadSafety - self + extend ThreadSafety end # Pass <tt>:force => true</tt> to force a cache miss. @@ -110,29 +105,24 @@ module ActiveSupport nil end end - + private def log(operation, key, options) logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@logger_off end end - module ThreadSafety #:nodoc: - def read(key, options = nil) #:nodoc: - @mutex.synchronize { super } - end - - def write(key, value, options = nil) #:nodoc: - @mutex.synchronize { super } - end - - def delete(key, options = nil) #:nodoc: - @mutex.synchronize { super } + def self.extended(object) #:nodoc: + object.instance_variable_set(:@mutex, Mutex.new) end - def delete_matched(matcher, options = nil) #:nodoc: - @mutex.synchronize { super } + %w(read write delete delete_matched exist? increment decrement).each do |method| + module_eval <<-EOS, __FILE__, __LINE__ + def #{method}(*args) + @mutex.synchronize { super } + end + EOS end end end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index f3220d27aa..0af4251962 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -70,3 +70,70 @@ uses_mocha 'high-level cache store tests' do end end end + +class ThreadSafetyCacheStoreTest < Test::Unit::TestCase + def setup + @cache = ActiveSupport::Cache.lookup_store(:memory_store).threadsafe! + @cache.write('foo', 'bar') + + # No way to have mocha proxy to the original method + @mutex = @cache.instance_variable_get(:@mutex) + @mutex.instance_eval %( + def calls; @calls; end + def synchronize + @calls ||= 0 + @calls += 1 + yield + end + ) + end + + def test_read_is_synchronized + assert_equal 'bar', @cache.read('foo') + assert_equal 1, @mutex.calls + end + + def test_write_is_synchronized + @cache.write('foo', 'baz') + assert_equal 'baz', @cache.read('foo') + assert_equal 2, @mutex.calls + end + + def test_delete_is_synchronized + assert_equal 'bar', @cache.read('foo') + @cache.delete('foo') + assert_equal nil, @cache.read('foo') + assert_equal 3, @mutex.calls + end + + def test_delete_matched_is_synchronized + assert_equal 'bar', @cache.read('foo') + @cache.delete_matched(/foo/) + assert_equal nil, @cache.read('foo') + assert_equal 3, @mutex.calls + end + + def test_fetch_is_synchronized + assert_equal 'bar', @cache.fetch('foo') { 'baz' } + assert_equal 'fu', @cache.fetch('bar') { 'fu' } + assert_equal 3, @mutex.calls + end + + def test_exist_is_synchronized + assert @cache.exist?('foo') + assert !@cache.exist?('bar') + assert_equal 2, @mutex.calls + end + + def test_increment_is_synchronized + @cache.write('foo_count', 1) + assert_equal 2, @cache.increment('foo_count') + assert_equal 4, @mutex.calls + end + + def test_decrement_is_synchronized + @cache.write('foo_count', 1) + assert_equal 0, @cache.decrement('foo_count') + assert_equal 4, @mutex.calls + end +end |