File: active_support/cache/mem_cache_store.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#3
  module: Cache#4
  class: MemCacheStore#17
extends
  LocalCache ( ActiveSupport::Cache::Strategy )
inherits from
  Store ( ActiveSupport::Cache )
has properties
class method: build_mem_cache / 1 #26
method: initialize / 1 #46
method: read_multi / 1 #57
method: read / 2 #61
method: write / 3 #76
method: delete / 2 #89
method: exist? / 2 #98
method: increment / 2 #105
method: decrement / 2 #114
method: delete_matched / 2 #122
method: clear #129
method: stats #133
method: raw? / 1 #138
  module: Response#18
has properties
constant: STORED #19
constant: NOT_STORED #20
constant: EXISTS #21
constant: NOT_FOUND #22
constant: DELETED #23

Class Hierarchy

Code

   1  require 'memcache'
   2 
   3  module ActiveSupport
   4    module Cache
   5      # A cache store implementation which stores data in Memcached:
   6      # http://www.danga.com/memcached/
   7      #
   8      # This is currently the most popular cache store for production websites.
   9      #
  10      # Special features:
  11      # - Clustering and load balancing. One can specify multiple memcached servers,
  12      #   and MemCacheStore will load balance between all available servers. If a
  13      #   server goes down, then MemCacheStore will ignore it until it goes back
  14      #   online.
  15      # - Time-based expiry support. See #write and the +:expires_in+ option.
  16      # - Per-request in memory cache for all communication with the MemCache server(s).
  17      class MemCacheStore < Store
  18        module Response # :nodoc:
  19          STORED      = "STORED\r\n"
  20          NOT_STORED  = "NOT_STORED\r\n"
  21          EXISTS      = "EXISTS\r\n"
  22          NOT_FOUND   = "NOT_FOUND\r\n"
  23          DELETED     = "DELETED\r\n"
  24        end
  25 
  26        def self.build_mem_cache(*addresses)
  27          addresses = addresses.flatten
  28          options = addresses.extract_options!
  29          addresses = ["localhost"] if addresses.empty?
  30          MemCache.new(addresses, options)
  31        end
  32 
  33        # Creates a new MemCacheStore object, with the given memcached server
  34        # addresses. Each address is either a host name, or a host-with-port string
  35        # in the form of "host_name:port". For example:
  36        #
  37        #   ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
  38        #
  39        # If no addresses are specified, then MemCacheStore will connect to
  40        # localhost port 11211 (the default memcached port).
  41        #
  42        # Instead of addresses one can pass in a MemCache-like object. For example:
  43        #
  44        #   require 'memcached' # gem install memcached; uses C bindings to libmemcached
  45        #   ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
  46        def initialize(*addresses)
  47          if addresses.first.respond_to?(:get)
  48            @data = addresses.first
  49          else
  50            @data = self.class.build_mem_cache(*addresses)
  51          end
  52 
  53          extend Strategy::LocalCache
  54        end
  55 
  56        # Reads multiple keys from the cache.
  57        def read_multi(*keys)
  58          @data.get_multi keys
  59        end
  60 
  61        def read(key, options = nil) # :nodoc:
  62          super
  63          @data.get(key, raw?(options))
  64        rescue MemCache::MemCacheError => e
  65          logger.error("MemCacheError (#{e}): #{e.message}")
  66          nil
  67        end
  68 
  69        # Writes a value to the cache.
  70        #
  71        # Possible options:
  72        # - +:unless_exist+ - set to true if you don't want to update the cache
  73        #   if the key is already set.
  74        # - +:expires_in+ - the number of seconds that this value may stay in
  75        #   the cache. See ActiveSupport::Cache::Store#write for an example.
  76        def write(key, value, options = nil)
  77          super
  78          method = options && options[:unless_exist] ? :add : :set
  79          # memcache-client will break the connection if you send it an integer
  80          # in raw mode, so we convert it to a string to be sure it continues working.
  81          value = value.to_s if raw?(options)
  82          response = @data.send(method, key, value, expires_in(options), raw?(options))
  83          response == Response::STORED
  84        rescue MemCache::MemCacheError => e
  85          logger.error("MemCacheError (#{e}): #{e.message}")
  86          false
  87        end
  88 
  89        def delete(key, options = nil) # :nodoc:
  90          super
  91          response = @data.delete(key, expires_in(options))
  92          response == Response::DELETED
  93        rescue MemCache::MemCacheError => e
  94          logger.error("MemCacheError (#{e}): #{e.message}")
  95          false
  96        end
  97 
  98        def exist?(key, options = nil) # :nodoc:
  99          # Doesn't call super, cause exist? in memcache is in fact a read
 100          # But who cares? Reading is very fast anyway
 101          # Local cache is checked first, if it doesn't know then memcache itself is read from
 102          !read(key, options).nil?
 103        end
 104 
 105        def increment(key, amount = 1) # :nodoc:
 106          log("incrementing", key, amount)
 107 
 108          response = @data.incr(key, amount)
 109          response == Response::NOT_FOUND ? nil : response
 110        rescue MemCache::MemCacheError
 111          nil
 112        end
 113 
 114        def decrement(key, amount = 1) # :nodoc:
 115          log("decrement", key, amount)
 116          response = @data.decr(key, amount)
 117          response == Response::NOT_FOUND ? nil : response
 118        rescue MemCache::MemCacheError
 119          nil
 120        end
 121 
 122        def delete_matched(matcher, options = nil) # :nodoc:
 123          # don't do any local caching at present, just pass
 124          # through and let the error happen
 125          super
 126          raise "Not supported by Memcache"
 127        end
 128 
 129        def clear
 130          @data.flush_all
 131        end
 132 
 133        def stats
 134          @data.stats
 135        end
 136 
 137        private
 138          def raw?(options)
 139            options && options[:raw]
 140          end
 141      end
 142    end
 143  end