aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
authorLourens Naude <lourens@methodmissing.com>2009-01-17 18:05:48 -0600
committerJoshua Peek <josh@joshpeek.com>2009-01-17 18:05:48 -0600
commitb08c96887538cf53670bb882e79996582375e6c9 (patch)
treea124364059632725b7e40bf58dfb35afdf995dd6 /activesupport/lib/active_support
parent29e7a0242853a5e102b6846b87723fc26a1ffb08 (diff)
downloadrails-b08c96887538cf53670bb882e79996582375e6c9.tar.gz
rails-b08c96887538cf53670bb882e79996582375e6c9.tar.bz2
rails-b08c96887538cf53670bb882e79996582375e6c9.zip
Decouple the local cache strategy from MemCacheStore for reuse with other remote stores [#1653 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/cache.rb4
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb64
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb104
3 files changed, 114 insertions, 58 deletions
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 6a6c861458..83174d3a85 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -10,6 +10,10 @@ module ActiveSupport
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'
+ end
+
# Creates a new CacheStore object according to the given options.
#
# If no arguments are passed to this method, then a new
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index eed9faac6d..4d8e1fdd67 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -23,24 +23,6 @@ module ActiveSupport
DELETED = "DELETED\r\n"
end
- # this allows caching of the fact that there is nothing in the remote cache
- NULL = 'mem_cache_store:null'
-
- THREAD_LOCAL_KEY = :mem_cache_store_cache
-
- class LocalCache
- def initialize(app)
- @app = app
- end
-
- def call(env)
- Thread.current[THREAD_LOCAL_KEY] = MemoryStore.new
- @app.call(env)
- ensure
- Thread.current[THREAD_LOCAL_KEY] = nil
- end
- end
-
attr_reader :addresses
# Creates a new MemCacheStore object, with the given memcached server
@@ -57,22 +39,13 @@ module ActiveSupport
addresses = ["localhost"] if addresses.empty?
@addresses = addresses
@data = MemCache.new(addresses, options)
+
+ extend Strategy::LocalCache
end
def read(key, options = nil) # :nodoc:
super
-
- value = local_cache && local_cache.read(key)
- if value == NULL
- nil
- elsif value.nil?
- value = @data.get(key, raw?(options))
- local_cache.write(key, value || NULL) if local_cache
- value
- else
- # forcing the value to be immutable
- value.dup
- end
+ @data.get(key, raw?(options))
rescue MemCache::MemCacheError => e
logger.error("MemCacheError (#{e}): #{e.message}")
nil
@@ -91,7 +64,6 @@ module ActiveSupport
# memcache-client will break the connection if you send it an integer
# in raw mode, so we convert it to a string to be sure it continues working.
value = value.to_s if raw?(options)
- local_cache.write(key, value || NULL) if local_cache
response = @data.send(method, key, value, expires_in(options), raw?(options))
response == Response::STORED
rescue MemCache::MemCacheError => e
@@ -101,7 +73,6 @@ module ActiveSupport
def delete(key, options = nil) # :nodoc:
super
- local_cache.write(key, NULL) if local_cache
response = @data.delete(key, expires_in(options))
response == Response::DELETED
rescue MemCache::MemCacheError => e
@@ -113,40 +84,22 @@ module ActiveSupport
# Doesn't call super, cause exist? in memcache is in fact a read
# But who cares? Reading is very fast anyway
# Local cache is checked first, if it doesn't know then memcache itself is read from
- value = local_cache.read(key) if local_cache
- if value == NULL
- false
- elsif value
- true
- else
- !read(key, options).nil?
- end
+ !read(key, options).nil?
end
def increment(key, amount = 1) # :nodoc:
log("incrementing", key, amount)
response = @data.incr(key, amount)
- unless response == Response::NOT_FOUND
- local_cache.write(key, response.to_s) if local_cache
- response
- else
- nil
- end
+ response == Response::NOT_FOUND ? nil : response
rescue MemCache::MemCacheError
nil
end
def decrement(key, amount = 1) # :nodoc:
log("decrement", key, amount)
-
response = @data.decr(key, amount)
- unless response == Response::NOT_FOUND
- local_cache.write(key, response.to_s) if local_cache
- response
- else
- nil
- end
+ response == Response::NOT_FOUND ? nil : response
rescue MemCache::MemCacheError
nil
end
@@ -159,7 +112,6 @@ module ActiveSupport
end
def clear
- local_cache.clear if local_cache
@data.flush_all
end
@@ -168,10 +120,6 @@ module ActiveSupport
end
private
- def local_cache
- Thread.current[THREAD_LOCAL_KEY]
- end
-
def expires_in(options)
(options && options[:expires_in]) || 0
end
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
new file mode 100644
index 0000000000..621358d701
--- /dev/null
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -0,0 +1,104 @@
+module ActiveSupport
+ module Cache
+ module Strategy
+ module LocalCache
+ # this allows caching of the fact that there is nothing in the remote cache
+ NULL = 'remote_cache_store:null'
+
+ def with_local_cache
+ Thread.current[thread_local_key] = MemoryStore.new
+ yield
+ ensure
+ Thread.current[thread_local_key] = nil
+ end
+
+ def middleware
+ @middleware ||= begin
+ klass = Class.new
+ klass.class_eval(<<-EOS, __FILE__, __LINE__)
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ Thread.current[:#{thread_local_key}] = MemoryStore.new
+ @app.call(env)
+ ensure
+ Thread.current[:#{thread_local_key}] = nil
+ end
+ EOS
+ klass
+ end
+ end
+
+ def read(key, options = nil)
+ value = local_cache && local_cache.read(key)
+ if value == NULL
+ nil
+ elsif value.nil?
+ value = super
+ local_cache.write(key, value || NULL) if local_cache
+ value
+ else
+ # forcing the value to be immutable
+ value.dup
+ end
+ end
+
+ def write(key, value, options = nil)
+ value = value.to_s if respond_to?(:raw?) && raw?(options)
+ local_cache.write(key, value || NULL) if local_cache
+ super
+ end
+
+ def delete(key, options = nil)
+ local_cache.write(key, NULL) if local_cache
+ super
+ end
+
+ def exist(key, options = nil)
+ value = local_cache.read(key) if local_cache
+ if value == NULL
+ false
+ elsif value
+ true
+ else
+ super
+ end
+ end
+
+ def increment(key, amount = 1)
+ if value = super
+ local_cache.write(key, value.to_s) if local_cache
+ value
+ else
+ nil
+ end
+ end
+
+ def decrement(key, amount = 1)
+ if value = super
+ local_cache.write(key, value.to_s) if local_cache
+ value
+ else
+ nil
+ end
+ end
+
+ def clear
+ local_cache.clear if local_cache
+ super
+ end
+
+ private
+ def thread_local_key
+ @thread_local_key ||= "#{self.class.name.underscore}_local_cache".gsub("/", "_").to_sym
+ end
+
+ def local_cache
+ Thread.current[thread_local_key]
+ end
+ end
+ end
+ end
+end