class ActiveSupport::Cache::RedisStore

Constants

ERRORS_TO_RESCUE

Attributes

data[R]

Public Class Methods

new(*addresses) click to toggle source

Instantiate the store.

Example:

RedisStore.new
  # => host: localhost,   port: 6379,  db: 0

RedisStore.new client: Redis.new(url: "redis://127.0.0.1:6380/1")
  # => host: localhost,   port: 6379,  db: 0

RedisStore.new "example.com"
  # => host: example.com, port: 6379,  db: 0

RedisStore.new "example.com:23682"
  # => host: example.com, port: 23682, db: 0

RedisStore.new "example.com:23682/1"
  # => host: example.com, port: 23682, db: 1

RedisStore.new "example.com:23682/1/theplaylist"
  # => host: example.com, port: 23682, db: 1, namespace: theplaylist

RedisStore.new "localhost:6379/0", "localhost:6380/0"
  # => instantiate a cluster

RedisStore.new "localhost:6379/0", "localhost:6380/0", pool_size: 5, pool_timeout: 10
  # => use a ConnectionPool

RedisStore.new "localhost:6379/0", "localhost:6380/0",
  pool: ::ConnectionPool.new(size: 1, timeout: 1) { ::Redis::Store::Factory.create("localhost:6379/0") })
  # => supply an existing connection pool (e.g. for use with redis-sentinel or redis-failover)
Calls superclass method
# File lib/active_support/cache/redis_store.rb, line 47
def initialize(*addresses)
  @options = addresses.extract_options!
  addresses = addresses.compact.map(&:dup)

  @data = if @options[:pool]
            raise "pool must be an instance of ConnectionPool" unless @options[:pool].is_a?(ConnectionPool)
            @pooled = true
            @options[:pool]
          elsif [:pool_size, :pool_timeout].any? { |key| @options.has_key?(key) }
            pool_options           = {}
            pool_options[:size]    = options[:pool_size] if options[:pool_size]
            pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
            @pooled = true
            ::ConnectionPool.new(pool_options) { ::Redis::Store::Factory.create(*addresses, @options) }
          elsif @options[:client]
            @options[:client]
          else
            ::Redis::Store::Factory.create(*addresses, @options)
          end

  super(@options)
end

Public Instance Methods

clear() click to toggle source

Clear all the data from the store.

# File lib/active_support/cache/redis_store.rb, line 226
def clear
  instrument(:clear, nil, nil) do
    with(&:flushdb)
  end
end
decrement(key, amount = 1, options = {}) click to toggle source

Decrement a key in the store

If the key doesn't exist it will be initialized on 0. If the key exist but it isn't a Fixnum it will be initialized on 0.

Example:

We have two objects in cache:
  counter # => 23
  rabbit  # => #<Rabbit:0x5eee6c>

cache.decrement "counter"
cache.read "counter", :raw => true      # => "22"

cache.decrement "counter", 2
cache.read "counter", :raw => true      # => "20"

cache.decrement "a counter"
cache.read "a counter", :raw => true    # => "-1"

cache.decrement "rabbit"
cache.read "rabbit", :raw => true       # => "-1"
# File lib/active_support/cache/redis_store.rb, line 213
def decrement(key, amount = 1, options = {})
  options = merged_options(options)
  instrument(:decrement, key, :amount => amount) do
    with{|c| c.decrby normalize_key(key, options), amount}
  end
end
delete_matched(matcher, options = nil) click to toggle source

Delete objects for matched keys.

Performance note: this operation can be dangerous for large production databases, as it uses the Redis “KEYS” command, which is O(N) over the total number of keys in the database. Users of large Redis caches should avoid this method.

Example:

cache.delete_matched "rab*"
# File lib/active_support/cache/redis_store.rb, line 90
def delete_matched(matcher, options = nil)
  options = merged_options(options)
  instrument(:delete_matched, matcher.inspect) do
    matcher = key_matcher(matcher, options)
    begin
      with do |store|
        !(keys = store.keys(matcher)).empty? && store.del(*keys)
      end
    rescue *ERRORS_TO_RESCUE
      raise if raise_errors?
      false
    end
  end
end
exist?(name, options = nil) click to toggle source

fixed problem with invalid exists? method github.com/rails/rails/commit/cad2c8f5791d5bd4af0f240d96e00bae76eabd2f

Calls superclass method
# File lib/active_support/cache/redis_store.rb, line 234
def exist?(name, options = nil)
  res = super(name, options)
  res || false
end
expire(key, ttl) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 220
def expire(key, ttl)
  options = merged_options(nil)
  with { |c| c.expire normalize_key(key, options), ttl }
end
fetch_multi(*names) { |name| ... } click to toggle source
# File lib/active_support/cache/redis_store.rb, line 132
def fetch_multi(*names)
  options = names.extract_options!
  return {} if names == []

  results = read_multi(*names, options)
  need_writes = {}

  fetched = names.inject({}) do |memo, name|
    memo[name] = results.fetch(name) do
      value = yield name
      need_writes[name] = value
      value
    end

    memo
  end

  begin
    with do |c|
      c.multi do
        need_writes.each do |name, value|
          write(name, value, options)
        end
      end
    end
  rescue *ERRORS_TO_RESCUE
    raise if raise_errors?
  end

  fetched
end
increment(key, amount = 1, options = {}) click to toggle source

Increment a key in the store.

If the key doesn't exist it will be initialized on 0. If the key exist but it isn't a Fixnum it will be initialized on 0.

Example:

We have two objects in cache:
  counter # => 23
  rabbit  # => #<Rabbit:0x5eee6c>

cache.increment "counter"
cache.read "counter", :raw => true      # => "24"

cache.increment "counter", 6
cache.read "counter", :raw => true      # => "30"

cache.increment "a counter"
cache.read "a counter", :raw => true    # => "1"

cache.increment "rabbit"
cache.read "rabbit", :raw => true       # => "1"
# File lib/active_support/cache/redis_store.rb, line 185
def increment(key, amount = 1, options = {})
  options = merged_options(options)
  instrument(:increment, key, :amount => amount) do
    with{|c| c.incrby normalize_key(key, options), amount}
  end
end
read_multi(*names) click to toggle source

Reads multiple keys from the cache using a single call to the servers for all keys. Options can be passed in the last argument.

Example:

cache.read_multi "rabbit", "white-rabbit"
cache.read_multi "rabbit", "white-rabbit", :raw => true
# File lib/active_support/cache/redis_store.rb, line 111
def read_multi(*names)
  options = names.extract_options!
  return {} if names == []

  keys = names.map{|name| normalize_key(name, options)}
  args = [keys, options]
  args.flatten!

  instrument(:read_multi, names) do |payload|
    values = with { |c| c.mget(*args) }
    values.map! { |v| v.is_a?(ActiveSupport::Cache::Entry) ? v.value : v }

    Hash[names.zip(values)].reject{|k,v| v.nil?}.tap do |result|
      payload[:hits] = result.keys if payload
    end
  end
rescue *ERRORS_TO_RESCUE
  raise if raise_errors?
  {}
end
reconnect() click to toggle source
# File lib/active_support/cache/redis_store.rb, line 251
def reconnect
  @data.reconnect if @data.respond_to?(:reconnect)
end
stats() click to toggle source
# File lib/active_support/cache/redis_store.rb, line 239
def stats
  with(&:info)
end
with(&block) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 243
def with(&block)
  if defined?(@pooled) && @pooled
    @data.with(&block)
  else
    block.call(@data)
  end
end
write(name, value, options = nil) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 70
def write(name, value, options = nil)
  options = merged_options(options)
  instrument(:write, name, options) do |payload|
    entry = options[:raw].present? ? value : Entry.new(value, options)
    if options[:expires_in].present? && options[:race_condition_ttl].present? && options[:raw].blank?
      options[:expires_in] = options[:expires_in].to_f + options[:race_condition_ttl].to_f
    end
    write_entry(normalize_key(name, options), entry, options)
  end
end

Protected Instance Methods

delete_entry(key, options) click to toggle source

Implement the ActiveSupport::Cache#delete_entry

It's really needed and use

# File lib/active_support/cache/redis_store.rb, line 278
def delete_entry(key, options)
  with { |c| c.del key }
rescue *ERRORS_TO_RESCUE
  raise if raise_errors?
  false
end
key_matcher(pattern, options) click to toggle source

Add the namespace defined in the options to a pattern designed to match keys.

This implementation is __different__ than ActiveSupport: __it doesn't accept Regular expressions__, because the Redis matcher is designed only for strings with wildcards.

# File lib/active_support/cache/redis_store.rb, line 294
def key_matcher(pattern, options)
  prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]

  pattern = pattern.inspect[1..-2] if pattern.is_a? Regexp

  if prefix
    "#{prefix}:#{pattern}"
  else
    pattern
  end
end
raise_errors?() click to toggle source
# File lib/active_support/cache/redis_store.rb, line 285
def raise_errors?
  !!@options[:raise_errors]
end
read_entry(key, options) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 264
def read_entry(key, options)
  entry = with { |c| c.get key, options }
  return unless entry
  entry.is_a?(Entry) ? entry : Entry.new(entry)
rescue *ERRORS_TO_RESCUE
  raise if raise_errors?
  nil
end
write_entry(key, entry, options) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 256
def write_entry(key, entry, options)
  method = options && options[:unless_exist] ? :setnx : :set
  with { |client| client.send method, key, entry, options }
rescue *ERRORS_TO_RESCUE
  raise if raise_errors?
  false
end

Private Instance Methods

normalize_key(*args) click to toggle source
# File lib/active_support/cache/redis_store.rb, line 309
def normalize_key(*args)
  namespaced_key(*args)
end