class Sinatra::RedisCache::Cache

Public Instance Methods

all_keys(params={with_namespace: true}) click to toggle source
# File lib/sinatra/redis-cache.rb, line 100
def all_keys(params={with_namespace: true})
  redis.keys("#{namespace}:*").map{|k| params[:with_namespace] ? k : key_without_namespace(k) }
end
del(keys) click to toggle source
# File lib/sinatra/redis-cache.rb, line 104
def del(keys)
  debug_log "del #{keys.map{|k| key_without_namespace(k)}}"
  redis.del(keys)
end
do(key, expires=config.default_expires, block) click to toggle source
# File lib/sinatra/redis-cache.rb, line 32
def do(key, expires=config.default_expires, block)
  debug_log "do #{key_without_namespace(key)}"
  if Sinatra::RedisCache::Config.environments.include? Sinatra::Base.settings.environment
    try = 0
    begin
      redis.watch(key = key_with_namespace(key)) do |watched|
        object = get(key)
        unless object.empty?
          if object['locked']
            raise SinatraRedisCacheKeyLocked
          end
          object['object']
        else
          lock_key(key, watched, config.lock_timeout)
          new_object = block.call
          store(key, new_object, expires)
          new_object
        end
      end
    rescue SinatraRedisCacheKeyLocked
      sleeptime = (((try += 1)*50 + rand(100).to_f)/1000)
      debug_log "key is locked, waiting #{sleeptime}s for retry ##{try}."
      sleep sleeptime
      retry
    rescue SinatraRedisCacheKeyAlreadyLocked
      sleeptime = (((try += 1)*50 + rand(100).to_f)/1000)
      debug_log "failed to obtain lock, waiting #{sleeptime}s for retry ##{try}."
      sleep sleeptime
      retry
    end
  else
    # Just run the block without cache if we're not in an allowed environment
    block.call
  end
end
flush() click to toggle source
# File lib/sinatra/redis-cache.rb, line 109
def flush
  unless (keys = all_keys).empty?
    del(keys)
  end
end
get(key) click to toggle source
# File lib/sinatra/redis-cache.rb, line 68
def get(key)
  debug_log "get #{key_without_namespace(key)}"
  unless (hash = redis.hgetall(key_with_namespace(key))).nil?
    hash.each{|k,v| hash[k]=deserialize(v)}
  else
    false
  end
end
properties(key) click to toggle source
# File lib/sinatra/redis-cache.rb, line 90
def properties(key)
  unless (string = redis.hget(key_with_namespace(key), 'properties')).nil?
    deserialize(string)
  end
end
store(key, object, expires=config.default_expires) click to toggle source
# File lib/sinatra/redis-cache.rb, line 77
def store(key, object, expires=config.default_expires)
  debug_log "store #{key_without_namespace(key)}"
  properties = { created_at: Time.now.utc.to_i }
  redis.watch(key = key_with_namespace(key)) do |watched|
    watched.multi do |multi|
      multi.hset(key, 'object',     serialize(object))
      multi.hset(key, 'properties', serialize(properties))
      multi.hdel(key, 'locked')
      multi.expire(key, expires)
    end
  end
end
ttl(key) click to toggle source
# File lib/sinatra/redis-cache.rb, line 96
def ttl(key)
  redis.ttl(key_with_namespace(key))
end

Private Instance Methods

config() click to toggle source
# File lib/sinatra/redis-cache.rb, line 117
def config
  Sinatra::RedisCache::Config
end
debug_log(message) click to toggle source
# File lib/sinatra/redis-cache.rb, line 121
def debug_log(message)
  if config.logger
    config.logger.debug("sinatra-redis-cache/#{Process.pid}/#{Thread.current.__id__}") { message }
  end
end
deserialize(string) click to toggle source
# File lib/sinatra/redis-cache.rb, line 155
def deserialize(string)
  Marshal.load(string)
end
key_with_namespace(key) click to toggle source
# File lib/sinatra/redis-cache.rb, line 135
def key_with_namespace(key)
  if key.start_with? namespace
    key
  else
    "#{namespace}:#{key}"
  end
end
key_without_namespace(key) click to toggle source
# File lib/sinatra/redis-cache.rb, line 143
def key_without_namespace(key)
  if key.start_with? namespace
    key.gsub(/^#{namespace}:/,'')
  else
    key
  end
end
lock_key(key, redis, timeout=config.lock_timeout) click to toggle source
# File lib/sinatra/redis-cache.rb, line 159
def lock_key(key, redis, timeout=config.lock_timeout)
  debug_log "locking #{key_without_namespace(key)} for #{timeout}s"
  unless redis.multi do |multi|
    multi.hsetnx(key, 'locked', serialize(true))
    multi.expire(key, timeout)
  end.eql? [true,true]
    raise SinatraRedisCacheKeyAlreadyLocked
  end

end
namespace() click to toggle source
# File lib/sinatra/redis-cache.rb, line 131
def namespace
  config.namespace
end
redis() click to toggle source
# File lib/sinatra/redis-cache.rb, line 127
def redis
  config.redis_conn
end
serialize(object) click to toggle source
# File lib/sinatra/redis-cache.rb, line 151
def serialize(object)
  Marshal.dump(object)
end