lib/active_support/cache.rb in activesupport-2.3.18 vs lib/active_support/cache.rb in activesupport-3.0.0.beta
- old
+ new
@@ -1,14 +1,19 @@
require 'benchmark'
+require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/benchmark'
+require 'active_support/core_ext/exception'
+require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/core_ext/object/to_param'
+require 'active_support/core_ext/string/inflections'
module ActiveSupport
# See ActiveSupport::Cache::Store for documentation.
module Cache
autoload :FileStore, 'active_support/cache/file_store'
autoload :MemoryStore, 'active_support/cache/memory_store'
autoload :SynchronizedMemoryStore, 'active_support/cache/synchronized_memory_store'
- autoload :DRbStore, 'active_support/cache/drb_store'
autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
autoload :CompressedMemCacheStore, 'active_support/cache/compressed_mem_cache_store'
module Strategy
autoload :LocalCache, 'active_support/cache/strategy/local_cache'
@@ -23,14 +28,14 @@
# store class under the ActiveSupport::Cache namespace will be created.
# For example:
#
# ActiveSupport::Cache.lookup_store(:memory_store)
# # => returns a new ActiveSupport::Cache::MemoryStore object
- #
- # ActiveSupport::Cache.lookup_store(:drb_store)
- # # => returns a new ActiveSupport::Cache::DRbStore object
#
+ # ActiveSupport::Cache.lookup_store(:mem_cache_store)
+ # # => returns a new ActiveSupport::Cache::MemCacheStore object
+ #
# Any additional arguments will be passed to the corresponding cache store
# class's constructor:
#
# ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
# # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
@@ -38,37 +43,45 @@
# If the first argument is not a Symbol, then it will simply be returned:
#
# ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
# # => returns MyOwnCacheStore.new
def self.lookup_store(*store_option)
- store, *parameters = *([ store_option ].flatten)
+ store, *parameters = *Array.wrap(store_option).flatten
case store
when Symbol
- store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize)
+ store_class_name = store.to_s.camelize
store_class = ActiveSupport::Cache.const_get(store_class_name)
store_class.new(*parameters)
when nil
ActiveSupport::Cache::MemoryStore.new
else
store
end
end
+ RAILS_CACHE_ID = ENV["RAILS_CACHE_ID"]
+ RAILS_APP_VERION = ENV["RAILS_APP_VERION"]
+ EXPANDED_CACHE = RAILS_CACHE_ID || RAILS_APP_VERION
+
def self.expand_cache_key(key, namespace = nil)
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"]}/"
+ if EXPANDED_CACHE
+ expanded_cache_key << "#{RAILS_CACHE_ID || RAILS_APP_VERION}/"
end
- expanded_cache_key << case
- when key.respond_to?(:cache_key)
+ expanded_cache_key <<
+ if key.respond_to?(:cache_key)
key.cache_key
- when key.is_a?(Array)
- key.collect { |element| expand_cache_key(element) }.to_param
- when key
+ elsif key.is_a?(Array)
+ if key.size > 1
+ key.collect { |element| expand_cache_key(element) }.to_param
+ else
+ key.first.to_param
+ end
+ elsif key
key.to_param
end.to_s
expanded_cache_key
end
@@ -82,34 +95,41 @@
# ActiveSupport::Cache::Store is meant for caching strings. Some cache
# store implementations, like MemoryStore, are able to cache arbitrary
# Ruby objects, but don't count on every cache store to be able to do that.
#
# cache = ActiveSupport::Cache::MemoryStore.new
- #
+ #
# cache.read("city") # => nil
# cache.write("city", "Duckburgh")
# cache.read("city") # => "Duckburgh"
class Store
- cattr_accessor :logger
+ cattr_accessor :logger, :instance_writter => false
- attr_reader :silence, :logger_off
+ attr_reader :silence
+ alias :silence? :silence
def silence!
@silence = true
self
end
- alias silence? silence
- alias logger_off? logger_off
-
def mute
previous_silence, @silence = defined?(@silence) && @silence, true
yield
ensure
@silence = previous_silence
end
+ # Set to true if cache stores should be instrumented. By default is false.
+ def self.instrument=(boolean)
+ Thread.current[:instrument_cache_store] = boolean
+ end
+
+ def self.instrument
+ Thread.current[:instrument_cache_store] || false
+ end
+
# Fetches data from the cache, using the given key. If there is data in
# the cache with the given key, then that data is returned.
#
# If there is no such data in the cache (a cache miss occurred), then
# then nil will be returned. However, if a block has been passed, then
@@ -117,11 +137,11 @@
# of the block will be written to the cache under the given cache key,
# and that return value will be returned.
#
# cache.write("today", "Monday")
# cache.fetch("today") # => "Monday"
- #
+ #
# cache.fetch("city") # => nil
# cache.fetch("city") do
# "Duckburgh"
# end
# cache.fetch("city") # => "Duckburgh"
@@ -136,113 +156,113 @@
# Internally, #fetch calls #read, and calls #write on a cache miss.
# +options+ will be passed to the #read and #write calls.
#
# For example, MemCacheStore's #write method supports the +:expires_in+
# option, which tells the memcached server to automatically expire the
- # cache item after a certain period. We can use this option with #fetch
- # too:
+ # cache item after a certain period. This options is also supported by
+ # FileStore's #read method. We can use this option with #fetch too:
#
# cache = ActiveSupport::Cache::MemCacheStore.new
# cache.fetch("foo", :force => true, :expires_in => 5.seconds) do
# "bar"
# end
# cache.fetch("foo") # => "bar"
# sleep(6)
# cache.fetch("foo") # => nil
- def fetch(key, options = {})
- @logger_off = true
+ def fetch(key, options = {}, &block)
if !options[:force] && value = read(key, options)
- @logger_off = false
- log("hit", key, options)
value
elsif block_given?
- @logger_off = false
- log("miss", key, options)
-
- value = nil
- ms = Benchmark.ms { value = yield }
-
- @logger_off = true
- write(key, value, options)
- @logger_off = false
-
- log('write (will save %.2fms)' % ms, key, nil)
-
- value
+ result = instrument(:generate, key, options, &block)
+ write(key, result, options)
+ result
end
end
# Fetches data from the cache, using the given key. If there is data in
# the cache with the given key, then that data is returned. Otherwise,
# nil is returned.
#
# You may also specify additional options via the +options+ argument.
# The specific cache store implementation will decide what to do with
# +options+.
- def read(key, options = nil)
- log("read", key, options)
+ #
+ # For example, FileStore supports the +:expires_in+ option, which
+ # makes the method return nil for cache items older than the specified
+ # period.
+ def read(key, options = nil, &block)
+ instrument(:read, key, options, &block)
end
# Writes the given value to the cache, with the given key.
#
# You may also specify additional options via the +options+ argument.
# The specific cache store implementation will decide what to do with
# +options+.
- #
+ #
# For example, MemCacheStore supports the +:expires_in+ option, which
# tells the memcached server to automatically expire the cache item after
# a certain period:
#
# cache = ActiveSupport::Cache::MemCacheStore.new
# cache.write("foo", "bar", :expires_in => 5.seconds)
# cache.read("foo") # => "bar"
# sleep(6)
# cache.read("foo") # => nil
- def write(key, value, options = nil)
- log("write", key, options)
+ def write(key, value, options = nil, &block)
+ instrument(:write, key, options, &block)
end
- def delete(key, options = nil)
- log("delete", key, options)
+ def delete(key, options = nil, &block)
+ instrument(:delete, key, options, &block)
end
- def delete_matched(matcher, options = nil)
- log("delete matched", matcher.inspect, options)
+ def delete_matched(matcher, options = nil, &block)
+ instrument(:delete_matched, matcher.inspect, options, &block)
end
- def exist?(key, options = nil)
- log("exist?", key, options)
+ def exist?(key, options = nil, &block)
+ instrument(:exist?, key, options, &block)
end
def increment(key, amount = 1)
- log("incrementing", key, amount)
if num = read(key)
write(key, num + amount)
else
nil
end
end
def decrement(key, amount = 1)
- log("decrementing", key, amount)
if num = read(key)
write(key, num - amount)
else
nil
end
end
private
def expires_in(options)
expires_in = options && options[:expires_in]
-
raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric)
-
expires_in || 0
end
+ def instrument(operation, key, options)
+ log(operation, key, options)
+
+ if self.class.instrument
+ payload = { :key => key }
+ payload.merge!(options) if options.is_a?(Hash)
+ ActiveSupport::Notifications.instrument("active_support.cache_#{operation}", payload){ yield }
+ else
+ yield
+ end
+ end
+
def log(operation, key, options)
- logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !silence? && !logger_off?
+ return unless logger && !silence?
+ logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}")
end
end
end
end