Class: ActiveSupport::Cache::MemCacheStore
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Store
|
|
Instance Chain:
|
|
Inherits: |
ActiveSupport::Cache::Store
|
Defined in: | activesupport/lib/active_support/cache/mem_cache_store.rb |
Overview
Memcached Cache Store
A cache store implementation which stores data in Memcached: memcached.org
This is currently the most popular cache store for production websites.
Special features:
-
Clustering and load balancing. One can specify multiple memcached servers, and
MemCacheStore
will load balance between all available servers. If a server goes down, thenMemCacheStore
will ignore it until it comes back up.
MemCacheStore
implements the Strategy::LocalCache
strategy which implements an in-memory cache inside of a block.
Constant Summary
-
ESCAPE_KEY_CHARS =
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 85/[\x00-\x20%\x7F-\xFF]/n
-
KEY_MAX_SIZE =
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 84250
-
OVERRIDDEN_OPTIONS =
These options represent behavior overridden by this implementation and should not be allowed to get down to the Dalli client
UNIVERSAL_OPTIONS
Store
- Inherited
Class Attribute Summary
-
.supports_cache_versioning? ⇒ Boolean
readonly
Advertise cache versioning support.
Store
- Inherited
Class Method Summary
-
.new(*addresses) ⇒ MemCacheStore
constructor
Creates a new
MemCacheStore
object, with the given memcached server addresses. -
.build_mem_cache(*addresses)
Internal use only
Creates a new
Dalli::Client
instance with specified addresses and options.
Store
- Inherited
.new | Creates a new cache. |
.retrieve_pool_options |
Instance Attribute Summary
Store
- Inherited
Instance Method Summary
-
#clear(options = nil)
Clear the entire cache on all memcached servers.
-
#decrement(name, amount = 1, options = nil)
Decrement a cached integer value using the memcached decr atomic operator.
-
#increment(name, amount = 1, options = nil)
Increment a cached integer value using the memcached incr atomic operator.
- #inspect
-
#stats
Get the statistics from the memcached servers.
-
#write(name, value, options = nil)
Behaves the same as Store#write, but supports additional options specific to memcached.
- #default_serializer private
-
#delete_entry(key, **options)
private
Delete an entry from the cache.
- #deserialize_entry(payload, raw: false) private
-
#normalize_key(key, options)
private
Memcache keys are binaries.
-
#read_entry(key, **options)
private
Read an entry from the cache.
-
#read_multi_entries(names, **options)
private
Reads multiple entries from the cache implementation.
- #read_serialized_entry(key, **options) private
- #rescue_error_with(fallback) private
- #serialize_entry(entry, raw: false, **options) private
-
#write_entry(key, entry, **options)
private
Write an entry to the cache.
- #write_serialized_entry(key, payload, **options) private
DupLocalCache
- Included
Strategy::LocalCache
- Included
#middleware | Middleware class can be inserted as a |
#with_local_cache | Use a local cache for the duration of block. |
#bypass_local_cache, #delete_entry, #local_cache, #local_cache_key, #read_multi_entries, #read_serialized_entry, #use_temporary_local_cache, #write_cache_value, #write_serialized_entry, #cleanup, #clear, #decrement, #delete_matched, #increment |
Store
- Inherited
#cleanup | Cleans up the cache by removing expired entries. |
#clear | Clears the entire cache. |
#decrement | Decrements an integer value in the cache. |
#delete | Deletes an entry in the cache. |
#delete_matched | Deletes all entries with keys matching the pattern. |
#delete_multi | Deletes multiple entries in the cache. |
#exist? | Returns |
#fetch | Fetches data from the cache, using the given key. |
#fetch_multi | Fetches data from the cache, using the given keys. |
#increment | Increments an integer value in the cache. |
#mute | Silences the logger within a block. |
#read | Reads data from the cache, using the given key. |
#read_multi | Reads multiple values at once from the cache. |
#silence, | |
#silence! | Silences the logger. |
#write | Writes the value to the cache with the key. |
#write_multi |
|
#_instrument, #default_serializer, | |
#delete_entry | Deletes an entry from the cache implementation. |
#delete_multi_entries | Deletes multiples entries in the cache implementation. |
#deserialize_entry, | |
#expanded_key | Expands key to be a consistent string value. |
#expanded_version, #get_entry_value, #handle_expired_entry, #handle_invalid_expires_in, #instrument, #instrument_multi, | |
#key_matcher | Adds the namespace defined in the options to a pattern designed to match keys. |
#merged_options | Merges the default options with ones specific to a method call. |
#namespace_key | Prefix the key with a namespace string: |
#normalize_key | Expands and namespaces the cache key. |
#normalize_options | Normalize aliased options to their canonical form. |
#normalize_version, | |
#read_entry | Reads an entry from the cache implementation. |
#read_multi_entries | Reads multiple entries from the cache implementation. |
#save_block_result_to_cache, #serialize_entry, #validate_options, | |
#write_entry | Writes an entry to the cache implementation. |
#write_multi_entries | Writes multiple entries to the cache implementation. |
#new_entry |
Constructor Details
.new(*addresses) ⇒ MemCacheStore
Creates a new MemCacheStore
object, with the given memcached server addresses. Each address is either a host name, or a host-with-port string in the form of “host_name:port”. For example:
ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
If no addresses are provided, but ENV['MEMCACHE_SERVERS']
is defined, it will be used instead. Otherwise, MemCacheStore
will connect to localhost:11211 (the default memcached port). Passing a Dalli::Client
instance is deprecated and will be removed. Please pass an address instead.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 118
def initialize(*addresses) addresses = addresses.flatten = addresses. if .key?(:cache_nils) [:skip_nil] = ! .delete(:cache_nils) end super( ) unless [String, Dalli::Client, NilClass].include?(addresses.first.class) raise ArgumentError, "First argument must be an empty array, address, or array of addresses." end if addresses.first.is_a?(Dalli::Client) ActiveSupport.deprecator.warn(<<~MSG) Initializing MemCacheStore with a Dalli::Client is deprecated and will be removed in Rails 7.2. Use memcached server addresses instead. MSG @data = addresses.first else @mem_cache_options = .dup # The value "compress: false" prevents duplicate compression within Dalli. @mem_cache_options[:compress] = false (OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) } @data = self.class.build_mem_cache(*(addresses + [@mem_cache_options])) end end
Class Attribute Details
.supports_cache_versioning? ⇒ Boolean
(readonly)
Advertise cache versioning support.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 38
def self.supports_cache_versioning? true end
Class Method Details
.build_mem_cache(*addresses)
Creates a new Dalli::Client
instance with specified addresses and options. If no addresses are provided, we give nil to Dalli::Client
, so it uses its fallbacks:
-
ENV (if defined)
-
“127.0.0.1:11211” (otherwise)
ActiveSupport::Cache::MemCacheStore.build_mem_cache
# => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
ActiveSupport::Cache::MemCacheStore.build_mem_cache(‘localhost:10290’)
# => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 96
def self.build_mem_cache(*addresses) # :nodoc: addresses = addresses.flatten = addresses. addresses = nil if addresses.compact.empty? = ( ) if ConnectionPool.new( ) { Dalli::Client.new(addresses, .merge(threadsafe: false)) } else Dalli::Client.new(addresses, ) end end
Instance Method Details
#clear(options = nil)
Clear the entire cache on all memcached servers. This method should be used with care when shared cache is being used.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 215
def clear( = nil) rescue_error_with(nil) { @data.with { |c| c.flush_all } } end
#decrement(name, amount = 1, options = nil)
Decrement a cached integer value using the memcached decr atomic operator. Returns the updated value.
If the key is unset or has expired, it will be set to 0. Memcached does not support negative counters.
cache.decrement("foo") # => 0
To set a specific value, call #write passing raw: true
:
cache.write("baz", 5, raw: true)
cache.decrement("baz") # => 4
Decrementing a non-numeric value, or a value written without raw: true
, will fail and return nil
.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 204
def decrement(name, amount = 1, = nil) = ( ) instrument(:decrement, name, amount: amount) do rescue_error_with nil do @data.with { |c| c.decr(normalize_key(name, ), amount, [:expires_in], 0) } end end end
#default_serializer (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 225
def default_serializer if Cache.format_version == 6.1 ActiveSupport.deprecator.warn <<~EOM Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2. Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format for more information on how to upgrade. EOM Cache::SerializerWithFallback[:passthrough] else super end end
#delete_entry(key, **options) (private)
Delete an entry from the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 296
def delete_entry(key, ** ) rescue_error_with(false) { @data.with { |c| c.delete(key) } } end
#deserialize_entry(payload, raw: false) (private)
[ GitHub ]#increment(name, amount = 1, options = nil)
Increment a cached integer value using the memcached incr atomic operator. Returns the updated value.
If the key is unset or has expired, it will be set to amount
:
cache.increment("foo") # => 1
cache.increment("bar", 100) # => 100
To set a specific value, call #write passing raw: true
:
cache.write("baz", 5, raw: true)
cache.increment("baz") # => 6
Incrementing a non-numeric value, or a value written without raw: true
, will fail and return nil
.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 180
def increment(name, amount = 1, = nil) = ( ) instrument(:increment, name, amount: amount) do rescue_error_with nil do @data.with { |c| c.incr(normalize_key(name, ), amount, [:expires_in], amount) } end end end
#inspect
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 144
def inspect instance = @data || @mem_cache_options "#<#{self.class} options=#{ .inspect} mem_cache=#{instance.inspect}>" end
#normalize_key(key, options) (private)
Memcache keys are binaries. So we need to force their encoding to binary before applying the regular expression to ensure we are escaping all characters properly.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 311
def normalize_key(key, ) key = super if key key = key.dup.force_encoding(Encoding::ASCII_8BIT) key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } if key.size > KEY_MAX_SIZE key_separator = ":hash:" key_hash = ActiveSupport::Digest.hexdigest(key) key_trim_size = KEY_MAX_SIZE - key_separator.size - key_hash.size key = "#{key[0, key_trim_size]}#{key_separator}#{key_hash}" end end key end
#read_entry(key, **options) (private)
Read an entry from the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 240
def read_entry(key, ** ) deserialize_entry(read_serialized_entry(key, ** ), ** ) end
#read_multi_entries(names, **options) (private)
Reads multiple entries from the cache implementation.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 270
def read_multi_entries(names, ** ) keys_to_names = names.index_by { |name| normalize_key(name, ) } raw_values = begin @data.with { |c| c.get_multi(keys_to_names.keys) } rescue Dalli::UnmarshalError {} end values = {} raw_values.each do |key, value| entry = deserialize_entry(value, raw: [:raw]) unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], )) begin values[keys_to_names[key]] = entry.value rescue DeserializationError end end end values end
#read_serialized_entry(key, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 244
def read_serialized_entry(key, ** ) rescue_error_with(nil) do @data.with { |c| c.get(key, ) } end end
#rescue_error_with(fallback) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 335
def rescue_error_with(fallback) yield rescue Dalli::DalliError => error logger.error("DalliError (#{error}): #{error.}") if logger ActiveSupport.error_reporter&.report( error, severity: :warning, source: "mem_cache_store.active_support", ) fallback end
#serialize_entry(entry, raw: false, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 300
def serialize_entry(entry, raw: false, ** ) if raw entry.value.to_s else super(entry, raw: raw, ** ) end end
#stats
Get the statistics from the memcached servers.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 220
def stats @data.with { |c| c.stats } end
#write(name, value, options = nil)
Behaves the same as Store#write, but supports additional options specific to memcached.
Additional Options
-
raw: true
- Sends the value directly to the server as raw bytes. The value must be a string or number. You can use memcached direct operations likeincrement
anddecrement
only on raw values. -
unless_exist: true
- Prevents overwriting an existing cache entry.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 150
rdoc_method :method: write
#write_entry(key, entry, **options) (private)
Write an entry to the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 251
def write_entry(key, entry, ** ) write_serialized_entry(key, serialize_entry(entry, ** ), ** ) end
#write_serialized_entry(key, payload, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 255
def write_serialized_entry(key, payload, ** ) method = [:unless_exist] ? :add : :set expires_in = [:expires_in].to_i if [:race_condition_ttl] && expires_in > 0 && ! [:raw] # Set the memcache expire a few minutes in the future to support race condition ttls on read expires_in += 5.minutes end rescue_error_with false do # Don't pass compress option to Dalli since we are already dealing with compression. .delete(:compress) @data.with { |c| c.send(method, key, payload, expires_in, ** ) } end end