Updated README.rdoc again
[feedcatcher.git] / vendor / rails / activesupport / lib / active_support / cache / mem_cache_store.rb
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 attr_reader :addresses
27
28 # Creates a new MemCacheStore object, with the given memcached server
29 # addresses. Each address is either a host name, or a host-with-port string
30 # in the form of "host_name:port". For example:
31 #
32 # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
33 #
34 # If no addresses are specified, then MemCacheStore will connect to
35 # localhost port 11211 (the default memcached port).
36 def initialize(*addresses)
37 addresses = addresses.flatten
38 options = addresses.extract_options!
39 addresses = ["localhost"] if addresses.empty?
40 @addresses = addresses
41 @data = MemCache.new(addresses, options)
42
43 extend Strategy::LocalCache
44 end
45
46 def read(key, options = nil) # :nodoc:
47 super
48 @data.get(key, raw?(options))
49 rescue MemCache::MemCacheError => e
50 logger.error("MemCacheError (#{e}): #{e.message}")
51 nil
52 end
53
54 # Writes a value to the cache.
55 #
56 # Possible options:
57 # - +:unless_exist+ - set to true if you don't want to update the cache
58 # if the key is already set.
59 # - +:expires_in+ - the number of seconds that this value may stay in
60 # the cache. See ActiveSupport::Cache::Store#write for an example.
61 def write(key, value, options = nil)
62 super
63 method = options && options[:unless_exist] ? :add : :set
64 # memcache-client will break the connection if you send it an integer
65 # in raw mode, so we convert it to a string to be sure it continues working.
66 value = value.to_s if raw?(options)
67 response = @data.send(method, key, value, expires_in(options), raw?(options))
68 response == Response::STORED
69 rescue MemCache::MemCacheError => e
70 logger.error("MemCacheError (#{e}): #{e.message}")
71 false
72 end
73
74 def delete(key, options = nil) # :nodoc:
75 super
76 response = @data.delete(key, expires_in(options))
77 response == Response::DELETED
78 rescue MemCache::MemCacheError => e
79 logger.error("MemCacheError (#{e}): #{e.message}")
80 false
81 end
82
83 def exist?(key, options = nil) # :nodoc:
84 # Doesn't call super, cause exist? in memcache is in fact a read
85 # But who cares? Reading is very fast anyway
86 # Local cache is checked first, if it doesn't know then memcache itself is read from
87 !read(key, options).nil?
88 end
89
90 def increment(key, amount = 1) # :nodoc:
91 log("incrementing", key, amount)
92
93 response = @data.incr(key, amount)
94 response == Response::NOT_FOUND ? nil : response
95 rescue MemCache::MemCacheError
96 nil
97 end
98
99 def decrement(key, amount = 1) # :nodoc:
100 log("decrement", key, amount)
101 response = @data.decr(key, amount)
102 response == Response::NOT_FOUND ? nil : response
103 rescue MemCache::MemCacheError
104 nil
105 end
106
107 def delete_matched(matcher, options = nil) # :nodoc:
108 # don't do any local caching at present, just pass
109 # through and let the error happen
110 super
111 raise "Not supported by Memcache"
112 end
113
114 def clear
115 @data.flush_all
116 end
117
118 def stats
119 @data.stats
120 end
121
122 private
123 def expires_in(options)
124 (options && options[:expires_in]) || 0
125 end
126
127 def raw?(options)
128 options && options[:raw]
129 end
130 end
131 end
132 end