Created
September 1, 2011 16:23
-
-
Save nel/1186564 to your computer and use it in GitHub Desktop.
Memcache Store with controlled expiration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ActiveSupport | |
module Cache | |
class AtomicMemCacheStore < MemCacheStore | |
ALREADY_STORED = "STORED\r\n" | |
cattr_accessor :grace_period | |
@@grace_period = 3.minutes | |
def read(key, options = nil) | |
result = super | |
if result.present? | |
timer_key = timer_key(key) | |
#check whether the cache is expired | |
if @data.get(timer_key, true).nil? | |
#optimistic lock to avoid concurrent recalculation | |
if @data.add(timer_key, '', self.class.grace_period, true) != ALREADY_STORED | |
#extend current cache key life | |
@data.set(key, result, self.class.grace_period, options && options[:raw]) | |
#trigger cache recalculation | |
return handle_expired_read(key,result) | |
end | |
#already recalculated or expirated in another process/thread | |
end | |
#key not expired | |
end | |
result | |
end | |
def write(key, value, options = nil) | |
if expiry = expires_in(options) | |
#extend write expiration period and reset expiration timer | |
options[:expires_in] = expiry + self.class.grace_period | |
end | |
@data.set(timer_key(key), '', expiry, true) | |
super | |
end | |
protected | |
#simulate empty cache to trigger synchronous cache recalculation | |
def handle_expired_read(key,result) | |
nil | |
end | |
private | |
def timer_key(key) | |
"tk:#{key}" | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment