aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/cache/mem_cache_store.rb
diff options
context:
space:
mode:
authorNahum Wild <nahum.wild@gmail.com>2009-01-15 21:28:10 -0600
committerJoshua Peek <josh@joshpeek.com>2009-01-15 21:29:32 -0600
commita53ad5bba37199047ba20194933e122bf6b0252f (patch)
tree65766ed28fb8518f706b39a688c974a1fed6519b /activesupport/lib/active_support/cache/mem_cache_store.rb
parent7a0e7c7270548138a333bc39aab5aec80580174b (diff)
downloadrails-a53ad5bba37199047ba20194933e122bf6b0252f.tar.gz
rails-a53ad5bba37199047ba20194933e122bf6b0252f.tar.bz2
rails-a53ad5bba37199047ba20194933e122bf6b0252f.zip
Added in a local per request cache to MemCacheStore. It acts as a buffer to stop unneccessary requests being sent through to memcache [#1653 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
Diffstat (limited to 'activesupport/lib/active_support/cache/mem_cache_store.rb')
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb65
1 files changed, 61 insertions, 4 deletions
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index f9a7fb1440..eed9faac6d 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -13,6 +13,7 @@ module ActiveSupport
# server goes down, then MemCacheStore will ignore it until it goes back
# online.
# - Time-based expiry support. See #write and the +:expires_in+ option.
+ # - Per-request in memory cache for all communication with the MemCache server(s).
class MemCacheStore < Store
module Response # :nodoc:
STORED = "STORED\r\n"
@@ -22,6 +23,24 @@ 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
@@ -42,7 +61,18 @@ module ActiveSupport
def read(key, options = nil) # :nodoc:
super
- @data.get(key, raw?(options))
+
+ 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
rescue MemCache::MemCacheError => e
logger.error("MemCacheError (#{e}): #{e.message}")
nil
@@ -61,6 +91,7 @@ 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
@@ -70,6 +101,7 @@ 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
@@ -80,14 +112,27 @@ module ActiveSupport
def exist?(key, options = nil) # :nodoc:
# Doesn't call super, cause exist? in memcache is in fact a read
# But who cares? Reading is very fast anyway
- !read(key, options).nil?
+ # 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
end
def increment(key, amount = 1) # :nodoc:
log("incrementing", key, amount)
response = @data.incr(key, amount)
- response == Response::NOT_FOUND ? nil : response
+ unless response == Response::NOT_FOUND
+ local_cache.write(key, response.to_s) if local_cache
+ response
+ else
+ nil
+ end
rescue MemCache::MemCacheError
nil
end
@@ -96,17 +141,25 @@ module ActiveSupport
log("decrement", key, amount)
response = @data.decr(key, amount)
- response == Response::NOT_FOUND ? nil : response
+ unless response == Response::NOT_FOUND
+ local_cache.write(key, response.to_s) if local_cache
+ response
+ else
+ nil
+ end
rescue MemCache::MemCacheError
nil
end
def delete_matched(matcher, options = nil) # :nodoc:
+ # don't do any local caching at present, just pass
+ # through and let the error happen
super
raise "Not supported by Memcache"
end
def clear
+ local_cache.clear if local_cache
@data.flush_all
end
@@ -115,6 +168,10 @@ module ActiveSupport
end
private
+ def local_cache
+ Thread.current[THREAD_LOCAL_KEY]
+ end
+
def expires_in(options)
(options && options[:expires_in]) || 0
end