Class | MemCache |
In: |
vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb
|
Parent: | Object |
A Ruby client library for memcached.
VERSION | = | '1.7.4' | The version of MemCache you are using. | |
DEFAULT_OPTIONS | = | { :namespace => nil, :readonly => false, :multithread => true, :failover => true, :timeout => 0.5, :logger => nil, :no_reply => false, } | Default options for the cache object. | |
DEFAULT_PORT | = | 11211 | Default memcached port. | |
DEFAULT_WEIGHT | = | 1 | Default memcached server weight. | |
ONE_MB | = | 1024 * 1024 |
Add key to the cache with value value that expires in
expiry seconds. If raw is true, value will not
be Marshalled.
Warning: Readers should not call this method in the event of a cache miss; see MemCache#add. |
failover | [R] | Should the client try to failover to another server if the first server is down? Defaults to true. |
logger | [R] | Log debug/info/warn/error to the given Logger, defaults to nil. |
multithread | [R] | The multithread setting for this instance |
namespace | [R] | The namespace for this instance |
no_reply | [R] | Don‘t send or look for a reply from the memcached server for write operations. Please note this feature only works in memcached 1.2.5 and later. Earlier versions will reply with "ERROR". |
servers | [R] | The servers this client talks to. Play at your own peril. |
timeout | [R] | Socket timeout limit with this client, defaults to 0.5 sec. Set to nil to disable timeouts. |
Accepts a list of servers and a list of opts. servers may be omitted. See +servers=+ for acceptable server list arguments.
Valid options for opts are:
[:namespace] Prepends this value to all keys added or retrieved. [:readonly] Raises an exception on cache writes when true. [:multithread] Wraps cache access in a Mutex for thread safety. Defaults to true. [:failover] Should the client try to failover to another server if the first server is down? Defaults to true. [:timeout] Time to use as the socket read timeout. Defaults to 0.5 sec, set to nil to disable timeouts (this is a major performance penalty in Ruby 1.8, "gem install SystemTimer' to remove most of the penalty). [:logger] Logger to use for info/debug output, defaults to nil [:no_reply] Don't bother looking for a reply for write operations (i.e. they become 'fire and forget'), memcached 1.2.5 and later only, speeds up set/add/delete/incr/decr significantly.
Other options are ignored.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 102 102: def initialize(*args) 103: servers = [] 104: opts = {} 105: 106: case args.length 107: when 0 then # NOP 108: when 1 then 109: arg = args.shift 110: case arg 111: when Hash then opts = arg 112: when Array then servers = arg 113: when String then servers = [arg] 114: else raise ArgumentError, 'first argument must be Array, Hash or String' 115: end 116: when 2 then 117: servers, opts = args 118: else 119: raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 120: end 121: 122: opts = DEFAULT_OPTIONS.merge opts 123: @namespace = opts[:namespace] 124: @readonly = opts[:readonly] 125: @multithread = opts[:multithread] 126: @timeout = opts[:timeout] 127: @failover = opts[:failover] 128: @logger = opts[:logger] 129: @no_reply = opts[:no_reply] 130: @mutex = Mutex.new if @multithread 131: 132: logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger 133: 134: Thread.current[:memcache_client] = self.object_id if !@multithread 135: 136: self.servers = servers 137: end
Returns whether there is at least one active server for the object.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 150 150: def active? 151: not @servers.empty? 152: end
Add key to the cache with value value that expires in expiry seconds, but only if key does not already exist in the cache. If raw is true, value will not be Marshalled.
Readers should call this method in the event of a cache miss, not MemCache#set.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 393 393: def add(key, value, expiry = 0, raw = false) 394: raise MemCacheError, "Update of readonly cache" if @readonly 395: with_server(key) do |server, cache_key| 396: value = Marshal.dump value unless raw 397: logger.debug { "add #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 398: command = "add #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 399: 400: with_socket_management(server) do |socket| 401: socket.write command 402: break nil if @no_reply 403: result = socket.gets 404: raise_on_error_response! result 405: result 406: end 407: end 408: end
Append - ‘add this data to an existing key after existing data’ Please note the value is always passed to memcached as raw since it doesn‘t make a lot of sense to concatenate marshalled data together.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 435 435: def append(key, value) 436: raise MemCacheError, "Update of readonly cache" if @readonly 437: with_server(key) do |server, cache_key| 438: logger.debug { "append #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 439: command = "append #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 440: 441: with_socket_management(server) do |socket| 442: socket.write command 443: break nil if @no_reply 444: result = socket.gets 445: raise_on_error_response! result 446: result 447: end 448: end 449: end
"cas" is a check and set operation which means "store this data but only if no one else has updated since I last fetched it." This can be used as a form of optimistic locking.
Works in block form like so:
cache.cas('some-key') do |value| value + 1 end
Returns: nil if the value was not found on the memcached server. STORED if the value was updated successfully EXISTS if the value was updated by someone else since last fetch
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 355 355: def cas(key, expiry=0, raw=false) 356: raise MemCacheError, "Update of readonly cache" if @readonly 357: raise MemCacheError, "A block is required" unless block_given? 358: 359: (value, token) = gets(key, raw) 360: return nil unless value 361: updated = yield value 362: 363: with_server(key) do |server, cache_key| 364: 365: value = Marshal.dump updated unless raw 366: logger.debug { "cas #{key} to #{server.inspect}: #{value.to_s.size}" } if logger 367: command = "cas #{cache_key} 0 #{expiry} #{value.to_s.size} #{token}#{noreply}\r\n#{value}\r\n" 368: 369: with_socket_management(server) do |socket| 370: socket.write command 371: break nil if @no_reply 372: result = socket.gets 373: raise_on_error_response! result 374: 375: if result.nil? 376: server.close 377: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 378: end 379: 380: result 381: end 382: end 383: end
Decrements the value for key by amount and returns the new value. key must already exist. If key is not an integer, it is assumed to be
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 193 193: def decr(key, amount = 1) 194: raise MemCacheError, "Update of readonly cache" if @readonly 195: with_server(key) do |server, cache_key| 196: cache_decr server, cache_key, amount 197: end 198: rescue TypeError => err 199: handle_error nil, err 200: end
Removes key from the cache in expiry seconds.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 474 474: def delete(key, expiry = 0) 475: raise MemCacheError, "Update of readonly cache" if @readonly 476: with_server(key) do |server, cache_key| 477: with_socket_management(server) do |socket| 478: logger.debug { "delete #{cache_key} on #{server}" } if logger 479: socket.write "delete #{cache_key} #{expiry}#{noreply}\r\n" 480: break nil if @no_reply 481: result = socket.gets 482: raise_on_error_response! result 483: result 484: end 485: end 486: end
Performs a get with the given key. If the value does not exist and a block was given, the block will be called and the result saved via add.
If you do not provide a block, using this method is the same as using get.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 226 226: def fetch(key, expiry = 0, raw = false) 227: value = get(key, raw) 228: 229: if value.nil? && block_given? 230: value = yield 231: add(key, value, expiry, raw) 232: end 233: 234: value 235: end
Flush the cache from all memcache servers. A non-zero value for delay will ensure that the flush is propogated slowly through your memcached server farm. The Nth server will be flushed N*delay seconds from now, asynchronously so this method returns quickly. This prevents a huge database spike due to a total flush all at once.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 497 497: def flush_all(delay=0) 498: raise MemCacheError, 'No active servers' unless active? 499: raise MemCacheError, "Update of readonly cache" if @readonly 500: 501: begin 502: delay_time = 0 503: @servers.each do |server| 504: with_socket_management(server) do |socket| 505: logger.debug { "flush_all #{delay_time} on #{server}" } if logger 506: if delay == 0 # older versions of memcached will fail silently otherwise 507: socket.write "flush_all#{noreply}\r\n" 508: else 509: socket.write "flush_all #{delay_time}#{noreply}\r\n" 510: end 511: break nil if @no_reply 512: result = socket.gets 513: raise_on_error_response! result 514: result 515: end 516: delay_time += delay 517: end 518: rescue IndexError => err 519: handle_error nil, err 520: end 521: end
Retrieves key from memcache. If raw is false, the value will be unmarshalled.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 206 206: def get(key, raw = false) 207: with_server(key) do |server, cache_key| 208: logger.debug { "get #{key} from #{server.inspect}" } if logger 209: value = cache_get server, cache_key 210: return nil if value.nil? 211: value = Marshal.load value unless raw 212: return value 213: end 214: rescue TypeError => err 215: handle_error nil, err 216: end
Retrieves multiple values from memcached in parallel, if possible.
The memcached protocol supports the ability to retrieve multiple keys in a single request. Pass in an array of keys to this method and it will:
Returns a hash of values.
cache["a"] = 1 cache["b"] = 2 cache.get_multi "a", "b" # => { "a" => 1, "b" => 2 }
Note that get_multi assumes the values are marshalled.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 255 255: def get_multi(*keys) 256: raise MemCacheError, 'No active servers' unless active? 257: 258: keys.flatten! 259: key_count = keys.length 260: cache_keys = {} 261: server_keys = Hash.new { |h,k| h[k] = [] } 262: 263: # map keys to servers 264: keys.each do |key| 265: server, cache_key = request_setup key 266: cache_keys[cache_key] = key 267: server_keys[server] << cache_key 268: end 269: 270: results = {} 271: 272: server_keys.each do |server, keys_for_server| 273: keys_for_server_str = keys_for_server.join ' ' 274: begin 275: values = cache_get_multi server, keys_for_server_str 276: values.each do |key, value| 277: results[cache_keys[key]] = Marshal.load value 278: end 279: rescue IndexError => e 280: # Ignore this server and try the others 281: logger.warn { "Unable to retrieve #{keys_for_server.size} elements from #{server.inspect}: #{e.message}"} if logger 282: end 283: end 284: 285: return results 286: rescue TypeError => err 287: handle_error nil, err 288: end
Increments the value for key by amount and returns the new value. key must already exist. If key is not an integer, it is assumed to be 0.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 295 295: def incr(key, amount = 1) 296: raise MemCacheError, "Update of readonly cache" if @readonly 297: with_server(key) do |server, cache_key| 298: cache_incr server, cache_key, amount 299: end 300: rescue TypeError => err 301: handle_error nil, err 302: end
Returns a string representation of the cache object.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 142 142: def inspect 143: "<MemCache: %d servers, ns: %p, ro: %p>" % 144: [@servers.length, @namespace, @readonly] 145: end
Prepend - ‘add this data to an existing key before existing data’ Please note the value is always passed to memcached as raw since it doesn‘t make a lot of sense to concatenate marshalled data together.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 455 455: def prepend(key, value) 456: raise MemCacheError, "Update of readonly cache" if @readonly 457: with_server(key) do |server, cache_key| 458: logger.debug { "prepend #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 459: command = "prepend #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 460: 461: with_socket_management(server) do |socket| 462: socket.write command 463: break nil if @no_reply 464: result = socket.gets 465: raise_on_error_response! result 466: result 467: end 468: end 469: end
Returns whether or not the cache object was created read only.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 157 157: def readonly? 158: @readonly 159: end
Add key to the cache with value value that expires in expiry seconds, but only if key already exists in the cache. If raw is true, value will not be Marshalled.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 414 414: def replace(key, value, expiry = 0, raw = false) 415: raise MemCacheError, "Update of readonly cache" if @readonly 416: with_server(key) do |server, cache_key| 417: value = Marshal.dump value unless raw 418: logger.debug { "replace #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 419: command = "replace #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 420: 421: with_socket_management(server) do |socket| 422: socket.write command 423: break nil if @no_reply 424: result = socket.gets 425: raise_on_error_response! result 426: result 427: end 428: end 429: end
Reset the connection to all memcache servers. This should be called if there is a problem with a cache lookup that might have left the connection in a corrupted state.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 528 528: def reset 529: @servers.each { |server| server.close } 530: end
Set the servers that the requests will be distributed between. Entries can be either strings of the form "hostname:port" or "hostname:port:weight" or MemCache::Server objects.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 166 166: def servers=(servers) 167: # Create the server objects. 168: @servers = Array(servers).collect do |server| 169: case server 170: when String 171: host, port, weight = server.split ':', 3 172: port ||= DEFAULT_PORT 173: weight ||= DEFAULT_WEIGHT 174: Server.new self, host, port, weight 175: else 176: server 177: end 178: end 179: 180: logger.debug { "Servers now: #{@servers.inspect}" } if logger 181: 182: # There's no point in doing this if there's only one server 183: @continuum = create_continuum_for(@servers) if @servers.size > 1 184: 185: @servers 186: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 313 313: def set(key, value, expiry = 0, raw = false) 314: raise MemCacheError, "Update of readonly cache" if @readonly 315: with_server(key) do |server, cache_key| 316: 317: value = Marshal.dump value unless raw 318: logger.debug { "set #{key} to #{server.inspect}: #{value.to_s.size}" } if logger 319: 320: raise MemCacheError, "Value too large, memcached can only store 1MB of data per key" if value.to_s.size > ONE_MB 321: 322: command = "set #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 323: 324: with_socket_management(server) do |socket| 325: socket.write command 326: break nil if @no_reply 327: result = socket.gets 328: raise_on_error_response! result 329: 330: if result.nil? 331: server.close 332: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 333: end 334: 335: result 336: end 337: end 338: end
Returns statistics for each memcached server. An explanation of the statistics can be found in the memcached docs:
code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
Example:
>> pp CACHE.stats {"localhost:11211"=> {"bytes"=>4718, "pid"=>20188, "connection_structures"=>4, "time"=>1162278121, "pointer_size"=>32, "limit_maxbytes"=>67108864, "cmd_get"=>14532, "version"=>"1.2.0", "bytes_written"=>432583, "cmd_set"=>32, "get_misses"=>0, "total_connections"=>19, "curr_connections"=>3, "curr_items"=>4, "uptime"=>1557, "get_hits"=>14532, "total_items"=>32, "rusage_system"=>0.313952, "rusage_user"=>0.119981, "bytes_read"=>190619}} => nil
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 564 564: def stats 565: raise MemCacheError, "No active servers" unless active? 566: server_stats = {} 567: 568: @servers.each do |server| 569: next unless server.alive? 570: 571: with_socket_management(server) do |socket| 572: value = nil 573: socket.write "stats\r\n" 574: stats = {} 575: while line = socket.gets do 576: raise_on_error_response! line 577: break if line == "END\r\n" 578: if line =~ /\ASTAT ([\S]+) ([\w\.\:]+)/ then 579: name, value = $1, $2 580: stats[name] = case name 581: when 'version' 582: value 583: when 'rusage_user', 'rusage_system' then 584: seconds, microseconds = value.split(/:/, 2) 585: microseconds ||= 0 586: Float(seconds) + (Float(microseconds) / 1_000_000) 587: else 588: if value =~ /\A\d+\Z/ then 589: value.to_i 590: else 591: value 592: end 593: end 594: end 595: end 596: server_stats["#{server.host}:#{server.port}"] = stats 597: end 598: end 599: 600: raise MemCacheError, "No active servers" if server_stats.empty? 601: server_stats 602: end
Performs a raw decr for cache_key from server. Returns nil if not found.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 666 666: def cache_decr(server, cache_key, amount) 667: with_socket_management(server) do |socket| 668: socket.write "decr #{cache_key} #{amount}#{noreply}\r\n" 669: break nil if @no_reply 670: text = socket.gets 671: raise_on_error_response! text 672: return nil if text == "NOT_FOUND\r\n" 673: return text.to_i 674: end 675: end
Fetches the raw data for cache_key from server. Returns nil on cache miss.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 681 681: def cache_get(server, cache_key) 682: with_socket_management(server) do |socket| 683: socket.write "get #{cache_key}\r\n" 684: keyline = socket.gets # "VALUE <key> <flags> <bytes>\r\n" 685: 686: if keyline.nil? then 687: server.close 688: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 689: end 690: 691: raise_on_error_response! keyline 692: return nil if keyline == "END\r\n" 693: 694: unless keyline =~ /(\d+)\r/ then 695: server.close 696: raise MemCacheError, "unexpected response #{keyline.inspect}" 697: end 698: value = socket.read $1.to_i 699: socket.read 2 # "\r\n" 700: socket.gets # "END\r\n" 701: return value 702: end 703: end
Fetches cache_keys from server using a multi-get.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 740 740: def cache_get_multi(server, cache_keys) 741: with_socket_management(server) do |socket| 742: values = {} 743: socket.write "get #{cache_keys}\r\n" 744: 745: while keyline = socket.gets do 746: return values if keyline == "END\r\n" 747: raise_on_error_response! keyline 748: 749: unless keyline =~ /\AVALUE (.+) (.+) (.+)/ then 750: server.close 751: raise MemCacheError, "unexpected response #{keyline.inspect}" 752: end 753: 754: key, data_length = $1, $3 755: values[$1] = socket.read data_length.to_i 756: socket.read(2) # "\r\n" 757: end 758: 759: server.close 760: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" # TODO: retry here too 761: end 762: end
Performs a raw incr for cache_key from server. Returns nil if not found.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 768 768: def cache_incr(server, cache_key, amount) 769: with_socket_management(server) do |socket| 770: socket.write "incr #{cache_key} #{amount}#{noreply}\r\n" 771: break nil if @no_reply 772: text = socket.gets 773: raise_on_error_response! text 774: return nil if text == "NOT_FOUND\r\n" 775: return text.to_i 776: end 777: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 891 891: def check_multithread_status! 892: return if @multithread 893: 894: if Thread.current[:memcache_client] != self.object_id 895: raise MemCacheError, "You are accessing this memcache-client instance from multiple threads but have not enabled multithread support.\nNormally: MemCache.new(['localhost:11211'], :multithread => true)\nIn Rails: config.cache_store = [:mem_cache_store, 'localhost:11211', { :multithread => true }]\n" 896: end 897: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 872 872: def create_continuum_for(servers) 873: total_weight = servers.inject(0) { |memo, srv| memo + srv.weight } 874: continuum = [] 875: 876: servers.each do |server| 877: entry_count_for(server, servers.size, total_weight).times do |idx| 878: hash = Digest::SHA1.hexdigest("#{server.host}:#{server.port}:#{idx}") 879: value = Integer("0x#{hash[0..7]}") 880: continuum << Continuum::Entry.new(value, server) 881: end 882: end 883: 884: continuum.sort { |a, b| a.value <=> b.value } 885: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 887 887: def entry_count_for(server, total_servers, total_weight) 888: ((total_servers * Continuum::POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor 889: end
Pick a server to handle the request based on a hash of the key.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 642 642: def get_server_for_key(key, options = {}) 643: raise ArgumentError, "illegal character in key #{key.inspect}" if 644: key =~ /\s/ 645: raise ArgumentError, "key too long #{key.inspect}" if key.length > 250 646: raise MemCacheError, "No servers available" if @servers.empty? 647: return @servers.first if @servers.length == 1 648: 649: hkey = hash_for(key) 650: 651: 20.times do |try| 652: entryidx = Continuum.binary_search(@continuum, hkey) 653: server = @continuum[entryidx].server 654: return server if server.alive? 655: break unless failover 656: hkey = hash_for "#{try}#{key}" 657: end 658: 659: raise MemCacheError, "No servers available" 660: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 705 705: def gets(key, raw = false) 706: with_server(key) do |server, cache_key| 707: logger.debug { "gets #{key} from #{server.inspect}" } if logger 708: result = with_socket_management(server) do |socket| 709: socket.write "gets #{cache_key}\r\n" 710: keyline = socket.gets # "VALUE <key> <flags> <bytes> <cas token>\r\n" 711: 712: if keyline.nil? then 713: server.close 714: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 715: end 716: 717: raise_on_error_response! keyline 718: return nil if keyline == "END\r\n" 719: 720: unless keyline =~ /(\d+) (\w+)\r/ then 721: server.close 722: raise MemCacheError, "unexpected response #{keyline.inspect}" 723: end 724: value = socket.read $1.to_i 725: socket.read 2 # "\r\n" 726: socket.gets # "END\r\n" 727: [value, $2] 728: end 729: result[0] = Marshal.load result[0] unless raw 730: result 731: end 732: rescue TypeError => err 733: handle_error nil, err 734: end
Handles error from server.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 843 843: def handle_error(server, error) 844: raise error if error.is_a?(MemCacheError) 845: server.close if server 846: new_error = MemCacheError.new error.message 847: new_error.set_backtrace error.backtrace 848: raise new_error 849: end
Returns an interoperable hash value for key. (I think, docs are sketchy for down servers).
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 635 635: def hash_for(key) 636: Zlib.crc32(key) 637: end
Create a key for the cache, incorporating the namespace qualifier if requested.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 623 623: def make_cache_key(key) 624: if namespace.nil? then 625: key 626: else 627: "#{@namespace}:#{key}" 628: end 629: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 851 851: def noreply 852: @no_reply ? ' noreply' : '' 853: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 866 866: def raise_on_error_response!(response) 867: if response =~ /\A(?:CLIENT_|SERVER_)?ERROR(.*)/ 868: raise MemCacheError, $1.strip 869: end 870: end
Performs setup for making a request with key from memcached. Returns the server to fetch the key from and the complete key to use.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 859 859: def request_setup(key) 860: raise MemCacheError, 'No active servers' unless active? 861: cache_key = make_cache_key key 862: server = get_server_for_key cache_key 863: return server, cache_key 864: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 824 824: def with_server(key) 825: retried = false 826: begin 827: server, cache_key = request_setup(key) 828: yield server, cache_key 829: rescue IndexError => e 830: logger.warn { "Server failed: #{e.class.name}: #{e.message}" } if logger 831: if !retried && @servers.size > 1 832: logger.info { "Connection to server #{server.inspect} DIED! Retrying operation..." } if logger 833: retried = true 834: retry 835: end 836: handle_error(nil, e) 837: end 838: end
Gets or creates a socket connected to the given server, and yields it to the block, wrapped in a mutex synchronization if @multithread is true.
If a socket error (SocketError, SystemCallError, IOError) or protocol error (MemCacheError) is raised by the block, closes the socket, attempts to connect again, and retries the block (once). If an error is again raised, reraises it as MemCacheError.
If unable to connect to the server (or if in the reconnect wait period), raises MemCacheError. Note that the socket connect code marks a server dead for a timeout period, so retrying does not apply to connection attempt failures (but does still apply to unexpectedly lost connections etc.).
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb, line 793 793: def with_socket_management(server, &block) 794: check_multithread_status! 795: 796: @mutex.lock if @multithread 797: retried = false 798: 799: begin 800: socket = server.socket 801: 802: # Raise an IndexError to show this server is out of whack. If were inside 803: # a with_server block, we'll catch it and attempt to restart the operation. 804: 805: raise IndexError, "No connection to server (#{server.status})" if socket.nil? 806: 807: block.call(socket) 808: 809: rescue SocketError, Errno::EAGAIN, Timeout::Error => err 810: logger.warn { "Socket failure: #{err.message}" } if logger 811: server.mark_dead(err) 812: handle_error(server, err) 813: 814: rescue MemCacheError, SystemCallError, IOError => err 815: logger.warn { "Generic failure: #{err.class.name}: #{err.message}" } if logger 816: handle_error(server, err) if retried || socket.nil? 817: retried = true 818: retry 819: end 820: ensure 821: @mutex.unlock if @multithread 822: end