diff options
Diffstat (limited to 'activesupport/lib/active_support/cache/mem_cache_store.rb')
-rw-r--r-- | activesupport/lib/active_support/cache/mem_cache_store.rb | 139 |
1 files changed, 74 insertions, 65 deletions
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 2ca4b51efa..cae0d44e7d 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -1,18 +1,19 @@ +# frozen_string_literal: true + begin - require 'dalli' + require "dalli" rescue LoadError => e $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'digest/md5' -require 'active_support/core_ext/marshal' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/marshal" +require "active_support/core_ext/array/extract_options" module ActiveSupport module Cache # A cache store implementation which stores data in Memcached: - # http://memcached.org/ + # https://memcached.org # # This is currently the most popular cache store for production websites. # @@ -26,24 +27,24 @@ module ActiveSupport class MemCacheStore < Store # Provide support for raw values in the local cache strategy. module LocalCacheWithRaw # :nodoc: - protected - def read_entry(key, options) - entry = super - if options[:raw] && local_cache && entry - entry = deserialize_entry(entry.value) + private + def read_entry(key, options) + entry = super + if options[:raw] && local_cache && entry + entry = deserialize_entry(entry.value) + end + entry end - entry - end - def write_entry(key, entry, options) # :nodoc: - if options[:raw] && local_cache - raw_entry = Entry.new(entry.value.to_s) - raw_entry.expires_at = entry.expires_at - super(key, raw_entry, options) - else - super + def write_entry(key, entry, options) + if options[:raw] && local_cache + raw_entry = Entry.new(entry.value.to_s) + raw_entry.expires_at = entry.expires_at + super(key, raw_entry, options) + else + super + end end - end end prepend Strategy::LocalCache @@ -62,7 +63,23 @@ module ActiveSupport addresses = addresses.flatten options = addresses.extract_options! addresses = ["localhost:11211"] if addresses.empty? - Dalli::Client.new(addresses, options) + + pool_options = {} + pool_options[:size] = options[:pool_size] if options[:pool_size] + pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout] + + if pool_options.empty? + Dalli::Client.new(addresses, options) + else + begin + require "connection_pool" + rescue LoadError => e + $stderr.puts "You don't have connection_pool installed in your application. Please add it to your Gemfile and run bundle install" + raise e + end + + ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) } + end end # Creates a new MemCacheStore object, with the given memcached server @@ -85,36 +102,20 @@ module ActiveSupport @data = addresses.first else mem_cache_options = options.dup - UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)} + UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) } @data = self.class.build_mem_cache(*(addresses + [mem_cache_options])) end end - # Reads multiple values from the cache using a single call to the - # servers for all keys. Options can be passed in the last argument. - def read_multi(*names) - options = names.extract_options! - options = merged_options(options) - - keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}] - raw_values = @data.get_multi(keys_to_names.keys, :raw => true) - values = {} - raw_values.each do |key, value| - entry = deserialize_entry(value) - values[keys_to_names[key]] = entry.value unless entry.expired? - end - values - end - # Increment a cached value. This method uses the memcached incr atomic # operator and can only be used on values written with the :raw option. # Calling it on a value not stored with :raw will initialize that value # to zero. - def increment(name, amount = 1, options = nil) # :nodoc: + def increment(name, amount = 1, options = nil) options = merged_options(options) - instrument(:increment, name, :amount => amount) do + instrument(:increment, name, amount: amount) do rescue_error_with nil do - @data.incr(normalize_key(name, options), amount) + @data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) } end end end @@ -123,11 +124,11 @@ module ActiveSupport # operator and can only be used on values written with the :raw option. # Calling it on a value not stored with :raw will initialize that value # to zero. - def decrement(name, amount = 1, options = nil) # :nodoc: + def decrement(name, amount = 1, options = nil) options = merged_options(options) - instrument(:decrement, name, :amount => amount) do + instrument(:decrement, name, amount: amount) do rescue_error_with nil do - @data.decr(normalize_key(name, options), amount) + @data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) } end end end @@ -135,22 +136,22 @@ module ActiveSupport # Clear the entire cache on all memcached servers. This method should # be used with care when shared cache is being used. def clear(options = nil) - rescue_error_with(nil) { @data.flush_all } + rescue_error_with(nil) { @data.with { |c| c.flush_all } } end # Get the statistics from the memcached servers. def stats - @data.stats + @data.with { |c| c.stats } end - protected + private # Read an entry from the cache. - def read_entry(key, options) # :nodoc: - rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) } + def read_entry(key, options) + rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) } end # Write an entry to the cache. - def write_entry(key, entry, options) # :nodoc: + def write_entry(key, entry, options) method = options && options[:unless_exist] ? :add : :set value = options[:raw] ? entry.value.to_s : entry expires_in = options[:expires_in].to_i @@ -159,16 +160,32 @@ module ActiveSupport expires_in += 5.minutes end rescue_error_with false do - @data.send(method, key, value, expires_in, options) + @data.with { |c| c.send(method, key, value, expires_in, options) } end end - # Delete an entry from the cache. - def delete_entry(key, options) # :nodoc: - rescue_error_with(false) { @data.delete(key) } + # Reads multiple entries from the cache implementation. + def read_multi_entries(names, options) + keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }] + + raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) } + values = {} + + raw_values.each do |key, value| + entry = deserialize_entry(value) + + unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options)) + values[keys_to_names[key]] = entry.value + end + end + + values end - private + # Delete an entry from the cache. + def delete_entry(key, options) + rescue_error_with(false) { @data.with { |c| c.delete(key) } } + end # Memcache keys are binaries. So we need to force their encoding to binary # before applying the regular expression to ensure we are escaping all @@ -176,16 +193,8 @@ module ActiveSupport def normalize_key(key, options) key = super.dup key = key.force_encoding(Encoding::ASCII_8BIT) - key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" } - key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250 - key - end - - def escape_key(key) - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - `escape_key` is deprecated and will be removed from Rails 5.1. - Please use `normalize_key` which will return a fully resolved key or nothing. - MESSAGE + key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } + key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250 key end |