4
# See ActiveSupport::Cache::Store for documentation.
6
autoload :FileStore, 'active_support/cache/file_store'
7
autoload :MemoryStore, 'active_support/cache/memory_store'
8
autoload :SynchronizedMemoryStore, 'active_support/cache/synchronized_memory_store'
9
autoload :DRbStore, 'active_support/cache/drb_store'
10
autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
11
autoload :CompressedMemCacheStore, 'active_support/cache/compressed_mem_cache_store'
14
autoload :LocalCache, 'active_support/cache/strategy/local_cache'
17
# Creates a new CacheStore object according to the given options.
19
# If no arguments are passed to this method, then a new
20
# ActiveSupport::Cache::MemoryStore object will be returned.
22
# If you pass a Symbol as the first argument, then a corresponding cache
23
# store class under the ActiveSupport::Cache namespace will be created.
26
# ActiveSupport::Cache.lookup_store(:memory_store)
27
# # => returns a new ActiveSupport::Cache::MemoryStore object
29
# ActiveSupport::Cache.lookup_store(:drb_store)
30
# # => returns a new ActiveSupport::Cache::DRbStore object
32
# Any additional arguments will be passed to the corresponding cache store
33
# class's constructor:
35
# ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
36
# # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
38
# If the first argument is not a Symbol, then it will simply be returned:
40
# ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
41
# # => returns MyOwnCacheStore.new
42
def self.lookup_store(*store_option)
43
store, *parameters = *([ store_option ].flatten)
47
store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize)
48
store_class = ActiveSupport::Cache.const_get(store_class_name)
49
store_class.new(*parameters)
51
ActiveSupport::Cache::MemoryStore.new
57
def self.expand_cache_key(key, namespace = nil)
58
expanded_cache_key = namespace ? "#{namespace}/" : ""
60
if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
61
expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/"
64
expanded_cache_key << case
65
when key.respond_to?(:cache_key)
68
key.collect { |element| expand_cache_key(element) }.to_param
76
# An abstract cache store class. There are multiple cache store
77
# implementations, each having its own additional features. See the classes
78
# under the ActiveSupport::Cache module, e.g.
79
# ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most
80
# popular cache store for large production websites.
82
# ActiveSupport::Cache::Store is meant for caching strings. Some cache
83
# store implementations, like MemoryStore, are able to cache arbitrary
84
# Ruby objects, but don't count on every cache store to be able to do that.
86
# cache = ActiveSupport::Cache::MemoryStore.new
88
# cache.read("city") # => nil
89
# cache.write("city", "Duckburgh")
90
# cache.read("city") # => "Duckburgh"
92
cattr_accessor :logger
94
attr_reader :silence, :logger_off
101
alias silence? silence
102
alias logger_off? logger_off
105
previous_silence, @silence = defined?(@silence) && @silence, true
108
@silence = previous_silence
111
# Fetches data from the cache, using the given key. If there is data in
112
# the cache with the given key, then that data is returned.
114
# If there is no such data in the cache (a cache miss occurred), then
115
# then nil will be returned. However, if a block has been passed, then
116
# that block will be run in the event of a cache miss. The return value
117
# of the block will be written to the cache under the given cache key,
118
# and that return value will be returned.
120
# cache.write("today", "Monday")
121
# cache.fetch("today") # => "Monday"
123
# cache.fetch("city") # => nil
124
# cache.fetch("city") do
127
# cache.fetch("city") # => "Duckburgh"
129
# You may also specify additional options via the +options+ argument.
130
# Setting <tt>:force => true</tt> will force a cache miss:
132
# cache.write("today", "Monday")
133
# cache.fetch("today", :force => true) # => nil
135
# Other options will be handled by the specific cache store implementation.
136
# Internally, #fetch calls #read, and calls #write on a cache miss.
137
# +options+ will be passed to the #read and #write calls.
139
# For example, MemCacheStore's #write method supports the +:expires_in+
140
# option, which tells the memcached server to automatically expire the
141
# cache item after a certain period. We can use this option with #fetch
144
# cache = ActiveSupport::Cache::MemCacheStore.new
145
# cache.fetch("foo", :force => true, :expires_in => 5.seconds) do
148
# cache.fetch("foo") # => "bar"
150
# cache.fetch("foo") # => nil
151
def fetch(key, options = {})
153
if !options[:force] && value = read(key, options)
155
log("hit", key, options)
159
log("miss", key, options)
162
ms = Benchmark.ms { value = yield }
165
write(key, value, options)
168
log('write (will save %.2fms)' % ms, key, nil)
174
# Fetches data from the cache, using the given key. If there is data in
175
# the cache with the given key, then that data is returned. Otherwise,
178
# You may also specify additional options via the +options+ argument.
179
# The specific cache store implementation will decide what to do with
181
def read(key, options = nil)
182
log("read", key, options)
185
# Writes the given value to the cache, with the given key.
187
# You may also specify additional options via the +options+ argument.
188
# The specific cache store implementation will decide what to do with
191
# For example, MemCacheStore supports the +:expires_in+ option, which
192
# tells the memcached server to automatically expire the cache item after
195
# cache = ActiveSupport::Cache::MemCacheStore.new
196
# cache.write("foo", "bar", :expires_in => 5.seconds)
197
# cache.read("foo") # => "bar"
199
# cache.read("foo") # => nil
200
def write(key, value, options = nil)
201
log("write", key, options)
204
def delete(key, options = nil)
205
log("delete", key, options)
208
def delete_matched(matcher, options = nil)
209
log("delete matched", matcher.inspect, options)
212
def exist?(key, options = nil)
213
log("exist?", key, options)
216
def increment(key, amount = 1)
217
log("incrementing", key, amount)
219
write(key, num + amount)
225
def decrement(key, amount = 1)
226
log("decrementing", key, amount)
228
write(key, num - amount)
235
def expires_in(options)
236
expires_in = options && options[:expires_in]
238
raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric)
243
def log(operation, key, options)
244
logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !silence? && !logger_off?