Class: ActiveSupport::Cache::RedisStore

Inherits:
Store
  • Object
show all
Defined in:
lib/active_support/cache/redis_store.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*addresses) ⇒ RedisStore

Instantiate the store.

Example:

RedisStore.new
  # => 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)


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/active_support/cache/redis_store.rb', line 36

def initialize(*addresses)
  @options = addresses.dup.extract_options!

  @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) }
          else
            ::Redis::Store::Factory.create(*addresses)
          end

  super(@options)
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



7
8
9
# File 'lib/active_support/cache/redis_store.rb', line 7

def data
  @data
end

Instance Method Details

#clearObject

Clear all the data from the store.



199
200
201
202
203
# File 'lib/active_support/cache/redis_store.rb', line 199

def clear
  instrument(:clear, nil, nil) do
    with(&:flushdb)
  end
end

#decrement(key, amount = 1, options = {}) ⇒ Object

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"


186
187
188
189
190
191
# File 'lib/active_support/cache/redis_store.rb', line 186

def decrement(key, amount = 1, options = {})
  options = merged_options(options)
  instrument(:decrement, key, :amount => amount) do
    with{|c| c.decrby namespaced_key(key, options), amount}
  end
end

#delete_matched(matcher, options = nil) ⇒ Object

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*"


73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/active_support/cache/redis_store.rb', line 73

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 Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Redis::CannotConnectError
      raise if raise_errors?
      false
    end
  end
end

#exist?(name, options = nil) ⇒ Boolean

Returns:

  • (Boolean)


207
208
209
210
# File 'lib/active_support/cache/redis_store.rb', line 207

def exist?(name, options = nil)
  res = super(name, options)
  res || false
end

#expire(key, ttl) ⇒ Object



193
194
195
196
# File 'lib/active_support/cache/redis_store.rb', line 193

def expire(key, ttl)
  options = merged_options(nil)
  with { |c| c.expire namespaced_key(key, options), ttl }
end

#fetch_multi(*names) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/active_support/cache/redis_store.rb', line 109

def fetch_multi(*names)
  return {} if names == []
  results = read_multi(*names)
  options = names.extract_options!
  fetched = {}
  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

  with do |c|
    c.multi do
      need_writes.each do |name, value|
        write(name, value, options)
      end
    end
  end

  fetched
end

#increment(key, amount = 1, options = {}) ⇒ Object

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"


158
159
160
161
162
163
# File 'lib/active_support/cache/redis_store.rb', line 158

def increment(key, amount = 1, options = {})
  options = merged_options(options)
  instrument(:increment, key, :amount => amount) do
    with{|c| c.incrby namespaced_key(key, options), amount}
  end
end

#read_multi(*names) ⇒ Object

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


94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/active_support/cache/redis_store.rb', line 94

def read_multi(*names)
  return {} if names == []
  options = names.extract_options!
  keys = names.map{|name| normalize_key(name, options)}
  values = with { |c| c.mget(*keys) }
  values.map! { |v| v.is_a?(ActiveSupport::Cache::Entry) ? v.value : v }

  # Remove the options hash before mapping keys to values
  names.extract_options!

  result = Hash[names.zip(values)]
  result.reject!{ |k,v| v.nil? }
  result
end

#reconnectObject



224
225
226
# File 'lib/active_support/cache/redis_store.rb', line 224

def reconnect
  @data.reconnect if @data.respond_to?(:reconnect)
end

#statsObject



212
213
214
# File 'lib/active_support/cache/redis_store.rb', line 212

def stats
  with(&:info)
end

#with(&block) ⇒ Object



216
217
218
219
220
221
222
# File 'lib/active_support/cache/redis_store.rb', line 216

def with(&block)
  if defined?(@pooled) && @pooled
    @data.with(&block)
  else
    block.call(@data)
  end
end

#write(name, value, options = nil) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/active_support/cache/redis_store.rb', line 56

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)
    write_entry(normalize_key(name, options), entry, options)
  end
end