This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
| 0bd6e933 » | jeremy | 2009-09-24 | 1 | require 'memcache' | |
| 2a9ad9cc » | dhh | 2008-01-03 | 2 | ||
| 3 | module ActiveSupport | ||||
| 4 | module Cache | ||||
| b047929c » | lifo | 2008-11-01 | 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. | ||||
| e033b5d0 » | lifo | 2009-07-25 | 15 | # - Time-based expiry support. See #write and the <tt>:expires_in</tt> option. | |
| a53ad5bb » | terrcin | 2009-01-15 | 16 | # - Per-request in memory cache for all communication with the MemCache server(s). | |
| 2a9ad9cc » | dhh | 2008-01-03 | 17 | class MemCacheStore < Store | |
| b047929c » | lifo | 2008-11-01 | 18 | module Response # :nodoc: | |
| 0d26e47b » | jeremy | 2008-02-01 | 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 | |||||
| e2ed1a1c » | brynary | 2009-05-19 | 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 | ||||
| 2a9ad9cc » | dhh | 2008-01-03 | 32 | ||
| b047929c » | lifo | 2008-11-01 | 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). | ||||
| af44b076 » | David Vrensk | 2009-11-01 | 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")) | ||||
| 2a9ad9cc » | dhh | 2008-01-03 | 46 | def initialize(*addresses) | |
| 36058f45 » | brynary | 2009-05-19 | 47 | if addresses.first.respond_to?(:get) | |
| e2ed1a1c » | brynary | 2009-05-19 | 48 | @data = addresses.first | |
| 49 | else | ||||
| 50 | @data = self.class.build_mem_cache(*addresses) | ||||
| 51 | end | ||||
| b08c9688 » | methodmissing | 2009-01-17 | 52 | ||
| 53 | extend Strategy::LocalCache | ||||
| 2a9ad9cc » | dhh | 2008-01-03 | 54 | end | |
| 55 | |||||
| 29550cc9 » | Joe Van Dyk | 2009-02-02 | 56 | # Reads multiple keys from the cache. | |
| 57 | def read_multi(*keys) | ||||
| 58 | @data.get_multi keys | ||||
| 59 | end | ||||
| 60 | |||||
| b047929c » | lifo | 2008-11-01 | 61 | def read(key, options = nil) # :nodoc: | |
| 4215e9ab » | josevalim | 2009-09-20 | 62 | super do | |
| 63 | @data.get(key, raw?(options)) | ||||
| 64 | end | ||||
| 29938ba0 » | dhh | 2008-01-21 | 65 | rescue MemCache::MemCacheError => e | |
| 66 | logger.error("MemCacheError (#{e}): #{e.message}") | ||||
| 2a9ad9cc » | dhh | 2008-01-03 | 67 | nil | |
| 68 | end | ||||
| 69 | |||||
| b047929c » | lifo | 2008-11-01 | 70 | # Writes a value to the cache. | |
| 71 | # | ||||
| 72 | # Possible options: | ||||
| e033b5d0 » | lifo | 2009-07-25 | 73 | # - <tt>:unless_exist</tt> - set to true if you don't want to update the cache | |
| b047929c » | lifo | 2008-11-01 | 74 | # if the key is already set. | |
| e033b5d0 » | lifo | 2009-07-25 | 75 | # - <tt>:expires_in</tt> - the number of seconds that this value may stay in | |
| b047929c » | lifo | 2008-11-01 | 76 | # the cache. See ActiveSupport::Cache::Store#write for an example. | |
| 40f67639 » | dhh | 2008-02-07 | 77 | def write(key, value, options = nil) | |
| 4215e9ab » | josevalim | 2009-09-20 | 78 | super do | |
| 79 | method = options && options[:unless_exist] ? :add : :set | ||||
| 80 | # memcache-client will break the connection if you send it an integer | ||||
| 81 | # in raw mode, so we convert it to a string to be sure it continues working. | ||||
| 82 | value = value.to_s if raw?(options) | ||||
| 83 | response = @data.send(method, key, value, expires_in(options), raw?(options)) | ||||
| 84 | response == Response::STORED | ||||
| 85 | end | ||||
| 29938ba0 » | dhh | 2008-01-21 | 86 | rescue MemCache::MemCacheError => e | |
| 87 | logger.error("MemCacheError (#{e}): #{e.message}") | ||||
| 0d26e47b » | jeremy | 2008-02-01 | 88 | false | |
| 2a9ad9cc » | dhh | 2008-01-03 | 89 | end | |
| 90 | |||||
| b047929c » | lifo | 2008-11-01 | 91 | def delete(key, options = nil) # :nodoc: | |
| 4215e9ab » | josevalim | 2009-09-20 | 92 | super do | |
| 93 | response = @data.delete(key, expires_in(options)) | ||||
| 94 | response == Response::DELETED | ||||
| 95 | end | ||||
| 29938ba0 » | dhh | 2008-01-21 | 96 | rescue MemCache::MemCacheError => e | |
| 97 | logger.error("MemCacheError (#{e}): #{e.message}") | ||||
| 0d26e47b » | jeremy | 2008-02-01 | 98 | false | |
| 99860b72 » | josevalim | 2008-05-16 | 99 | end | |
| 100 | |||||
| b047929c » | lifo | 2008-11-01 | 101 | def exist?(key, options = nil) # :nodoc: | |
| 99860b72 » | josevalim | 2008-05-16 | 102 | # Doesn't call super, cause exist? in memcache is in fact a read | |
| 103 | # But who cares? Reading is very fast anyway | ||||
| a53ad5bb » | terrcin | 2009-01-15 | 104 | # Local cache is checked first, if it doesn't know then memcache itself is read from | |
| 4215e9ab » | josevalim | 2009-09-20 | 105 | super do | |
| 106 | !read(key, options).nil? | ||||
| 107 | end | ||||
| 99860b72 » | josevalim | 2008-05-16 | 108 | end | |
| fef82759 » | tobi | 2008-04-29 | 109 | ||
| b047929c » | lifo | 2008-11-01 | 110 | def increment(key, amount = 1) # :nodoc: | |
| af0d1fa8 » | josevalim | 2009-10-07 | 111 | response = instrument(:increment, key, :amount => amount) do | |
| 112 | @data.incr(key, amount) | ||||
| 113 | end | ||||
| 7ae2105d » | josh | 2008-07-16 | 114 | ||
| b08c9688 » | methodmissing | 2009-01-17 | 115 | response == Response::NOT_FOUND ? nil : response | |
| 7ae2105d » | josh | 2008-07-16 | 116 | rescue MemCache::MemCacheError | |
| fef82759 » | tobi | 2008-04-29 | 117 | nil | |
| 2a9ad9cc » | dhh | 2008-01-03 | 118 | end | |
| 119 | |||||
| b047929c » | lifo | 2008-11-01 | 120 | def decrement(key, amount = 1) # :nodoc: | |
| af0d1fa8 » | josevalim | 2009-10-07 | 121 | response = instrument(:decrement, key, :amount => amount) do | |
| 122 | @data.decr(key, amount) | ||||
| 123 | end | ||||
| 124 | |||||
| b08c9688 » | methodmissing | 2009-01-17 | 125 | response == Response::NOT_FOUND ? nil : response | |
| 7ae2105d » | josh | 2008-07-16 | 126 | rescue MemCache::MemCacheError | |
| fef82759 » | tobi | 2008-04-29 | 127 | nil | |
| 7ae2105d » | josh | 2008-07-16 | 128 | end | |
| 129 | |||||
| b047929c » | lifo | 2008-11-01 | 130 | def delete_matched(matcher, options = nil) # :nodoc: | |
| a53ad5bb » | terrcin | 2009-01-15 | 131 | # don't do any local caching at present, just pass | |
| 132 | # through and let the error happen | ||||
| 2a9ad9cc » | dhh | 2008-01-03 | 133 | super | |
| 134 | raise "Not supported by Memcache" | ||||
| 7ae2105d » | josh | 2008-07-16 | 135 | end | |
| 136 | |||||
| 4c307718 » | jeremy | 2008-02-20 | 137 | def clear | |
| 138 | @data.flush_all | ||||
| 7ae2105d » | josh | 2008-07-16 | 139 | end | |
| 140 | |||||
| 09517e3a » | tobi | 2008-04-29 | 141 | def stats | |
| 142 | @data.stats | ||||
| 4c307718 » | jeremy | 2008-02-20 | 143 | end | |
| 144 | |||||
| 2a9ad9cc » | dhh | 2008-01-03 | 145 | private | |
| 146 | def raw?(options) | ||||
| 147 | options && options[:raw] | ||||
| 148 | end | ||||
| 149 | end | ||||
| 150 | end | ||||
| 151 | end | ||||








