beginrequire'dalli'rescueLoadError=>e$stderr.puts"You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"raiseeendrequire'digest/md5'require'active_support/core_ext/marshal'require'active_support/core_ext/array/extract_options'moduleActiveSupportmoduleCache# A cache store implementation which stores data in Memcached:# http://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, then MemCacheStore will ignore it until it comes back up.## MemCacheStore implements the Strategy::LocalCache strategy which implements# an in-memory cache inside of a block.classMemCacheStore<Store# Provide support for raw values in the local cache strategy.moduleLocalCacheWithRaw# :nodoc:protecteddefread_entry(key,options)entry=superifoptions[:raw]&&local_cache&&entryentry=deserialize_entry(entry.value)endentryenddefwrite_entry(key,entry,options)# :nodoc:ifoptions[:raw]&&local_cacheraw_entry=Entry.new(entry.value.to_s)raw_entry.expires_at=entry.expires_atsuper(key,raw_entry,options)elsesuperendendendprependStrategy::LocalCacheprependLocalCacheWithRawESCAPE_KEY_CHARS=/[\x00-\x20%\x7F-\xFF]/n# Creates a new Dalli::Client instance with specified addresses and options.# By default address is equal localhost:11211.## ActiveSupport::Cache::MemCacheStore.build_mem_cache# # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil># ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>defself.build_mem_cache(*addresses)# :nodoc:addresses=addresses.flattenoptions=addresses.extract_options!addresses=["localhost:11211"]ifaddresses.empty?Dalli::Client.new(addresses,options)end# 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 specified, then MemCacheStore will connect to# localhost port 11211 (the default memcached port).definitialize(*addresses)addresses=addresses.flattenoptions=addresses.extract_options!super(options)unless[String,Dalli::Client,NilClass].include?(addresses.first.class)raiseArgumentError,"First argument must be an empty array, an array of hosts or a Dalli::Client instance."endifaddresses.first.is_a?(Dalli::Client)@data=addresses.firstelsemem_cache_options=options.dupUNIVERSAL_OPTIONS.each{|name|mem_cache_options.delete(name)}@data=self.class.build_mem_cache(*(addresses+[mem_cache_options]))endend# Reads multiple values from the cache using a single call to the# servers for all keys. Options can be passed in the last argument.defread_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)values={}raw_values.eachdo|key,value|entry=deserialize_entry(value)values[keys_to_names[key]]=entry.valueunlessentry.expired?endvaluesend# 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.defincrement(name,amount=1,options=nil)# :nodoc:options=merged_options(options)instrument(:increment,name,:amount=>amount)dorescue_error_withnildo@data.incr(normalize_key(name,options),amount)endendend# Decrement a cached value. This method uses the memcached decr 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.defdecrement(name,amount=1,options=nil)# :nodoc:options=merged_options(options)instrument(:decrement,name,:amount=>amount)dorescue_error_withnildo@data.decr(normalize_key(name,options),amount)endendend# Clear the entire cache on all memcached servers. This method should# be used with care when shared cache is being used.defclear(options=nil)rescue_error_with(nil){@data.flush_all}end# Get the statistics from the memcached servers.defstats@data.statsendprotected# Read an entry from the cache.defread_entry(key,options)# :nodoc:rescue_error_with(nil){deserialize_entry(@data.get(key,options))}end# Write an entry to the cache.defwrite_entry(key,entry,options)# :nodoc:method=options&&options[:unless_exist]?:add::setvalue=options[:raw]?entry.value.to_s:entryexpires_in=options[:expires_in].to_iifexpires_in>0&&!options[:raw]# Set the memcache expire a few minutes in the future to support race condition ttls on readexpires_in+=5.minutesendrescue_error_withfalsedo@data.send(method,key,value,expires_in,options)endend# Delete an entry from the cache.defdelete_entry(key,options)# :nodoc:rescue_error_with(false){@data.delete(key)}endprivate# 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.defnormalize_key(key,options)key=super.dupkey=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)}"ifkey.size>250keyenddefescape_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.
MESSAGEkeyenddefdeserialize_entry(raw_value)ifraw_valueentry=Marshal.load(raw_value)rescueraw_valueentry.is_a?(Entry)?entry:Entry.new(entry)endenddefrescue_error_with(fallback)yieldrescueDalli::DalliError=>elogger.error("DalliError (#{e}): #{e.message}")ifloggerfallbackendendendend