Object
A Ruby client library for memcached.
The version of MemCache you are using.
Default options for the cache object.
Default memcached port.
Default memcached server weight.
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.
Whether to try to fix keys that are too long and will be truncated by using their SHA1 hash instead. The hash is only used on keys longer than 250 characters, or containing spaces, to avoid impacting performance unnecesarily.
In theory, your code should generate correct keys when calling memcache, so it’s your responsibility and you should try to fix this problem at its source.
But if that’s not possible, enable this option and memcache-client will give you a hand.
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. [: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. [:check_size] Raises a MemCacheError if the value to be set is greater than 1 MB, which is the maximum key size for the standard memcached server. Defaults to true. [:autofix_keys] If a key is longer than 250 characters or contains spaces, use an SHA1 hash instead, to prevent collisions on truncated keys.
Other options are ignored.
# File lib/memcache.rb, line 136 136: def initialize(*args) 137: servers = [] 138: opts = {} 139: 140: case args.length 141: when 0 then # NOP 142: when 1 then 143: arg = args.shift 144: case arg 145: when Hash then opts = arg 146: when Array then servers = arg 147: when String then servers = [arg] 148: else raise ArgumentError, 'first argument must be Array, Hash or String' 149: end 150: when 2 then 151: servers, opts = args 152: else 153: raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 154: end 155: 156: @evented = defined?(EM) && EM.reactor_running? 157: opts = DEFAULT_OPTIONS.merge opts 158: @namespace = opts[:namespace] 159: @readonly = opts[:readonly] 160: @multithread = opts[:multithread] && !@evented 161: @autofix_keys = opts[:autofix_keys] 162: @timeout = opts[:timeout] 163: @failover = opts[:failover] 164: @logger = opts[:logger] 165: @no_reply = opts[:no_reply] 166: @check_size = opts[:check_size] 167: @namespace_separator = opts[:namespace_separator] 168: @mutex = Mutex.new if @multithread 169: 170: logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger 171: 172: Thread.current[:memcache_client] = self.object_id if !@multithread 173: 174: 175: self.servers = servers 176: end
Shortcut to save a value in the cache. This method does not set an expiration on the entry. Use set to specify an explicit expiry.
# File lib/memcache.rb, line 659 659: def []=(key, value) 660: set key, value 661: end
Returns whether there is at least one active server for the object.
# File lib/memcache.rb, line 189 189: def active? 190: not @servers.empty? 191: 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 lib/memcache.rb, line 438 438: def add(key, value, expiry = 0, raw = false) 439: raise MemCacheError, "Update of readonly cache" if @readonly 440: value = Marshal.dump value unless raw 441: with_server(key) do |server, cache_key| 442: logger.debug { "add #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 443: command = "add #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 444: 445: with_socket_management(server) do |socket| 446: socket.write command 447: break nil if @no_reply 448: result = socket.gets 449: raise_on_error_response! result 450: result 451: end 452: end 453: 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 lib/memcache.rb, line 480 480: def append(key, value) 481: raise MemCacheError, "Update of readonly cache" if @readonly 482: with_server(key) do |server, cache_key| 483: logger.debug { "append #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 484: command = "append #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 485: 486: with_socket_management(server) do |socket| 487: socket.write command 488: break nil if @no_reply 489: result = socket.gets 490: raise_on_error_response! result 491: result 492: end 493: end 494: 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 lib/memcache.rb, line 401 401: def cas(key, expiry=0, raw=false) 402: raise MemCacheError, "Update of readonly cache" if @readonly 403: raise MemCacheError, "A block is required" unless block_given? 404: 405: (value, token) = gets(key, raw) 406: return nil unless value 407: updated = yield value 408: value = raw ? updated : Marshal.dump(updated) 409: 410: with_server(key) do |server, cache_key| 411: logger.debug { "cas #{key} to #{server.inspect}: #{value.to_s.size}" } if logger 412: command = "cas #{cache_key} 0 #{expiry} #{value.to_s.size} #{token}#{noreply}\r\n#{value}\r\n" 413: 414: with_socket_management(server) do |socket| 415: socket.write command 416: break nil if @no_reply 417: result = socket.gets 418: raise_on_error_response! result 419: 420: if result.nil? 421: server.close 422: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 423: end 424: 425: result 426: end 427: end 428: 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
key can not be decremented below 0.
# File lib/memcache.rb, line 232 232: def decr(key, amount = 1) 233: raise MemCacheError, "Update of readonly cache" if @readonly 234: with_server(key) do |server, cache_key| 235: cache_decr server, cache_key, amount 236: end 237: rescue TypeError => err 238: handle_error nil, err 239: end
Removes key from the cache. expiry is ignored as it has been removed from the latest memcached version.
# File lib/memcache.rb, line 520 520: def delete(key, expiry = 0) 521: raise MemCacheError, "Update of readonly cache" if @readonly 522: with_server(key) do |server, cache_key| 523: with_socket_management(server) do |socket| 524: logger.debug { "delete #{cache_key} on #{server}" } if logger 525: socket.write "delete #{cache_key}#{noreply}\r\n" 526: break nil if @no_reply 527: result = socket.gets 528: raise_on_error_response! result 529: result 530: end 531: end 532: 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 lib/memcache.rb, line 265 265: def fetch(key, expiry = 0, raw = false) 266: value = get(key, raw) 267: 268: if value.nil? && block_given? 269: value = yield 270: add(key, value, expiry, raw) 271: end 272: 273: value 274: 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 lib/memcache.rb, line 543 543: def flush_all(delay=0) 544: raise MemCacheError, 'No active servers' unless active? 545: raise MemCacheError, "Update of readonly cache" if @readonly 546: 547: begin 548: delay_time = 0 549: @servers.each do |server| 550: with_socket_management(server) do |socket| 551: logger.debug { "flush_all #{delay_time} on #{server}" } if logger 552: if delay == 0 # older versions of memcached will fail silently otherwise 553: socket.write "flush_all#{noreply}\r\n" 554: else 555: socket.write "flush_all #{delay_time}#{noreply}\r\n" 556: end 557: break nil if @no_reply 558: result = socket.gets 559: raise_on_error_response! result 560: result 561: end 562: delay_time += delay 563: end 564: rescue IndexError => err 565: handle_error nil, err 566: end 567: end
Retrieves key from memcache. If raw is false, the value will be unmarshalled.
# File lib/memcache.rb, line 245 245: def get(key, raw = false) 246: with_server(key) do |server, cache_key| 247: logger.debug { "get #{key} from #{server.inspect}" } if logger 248: value = cache_get server, cache_key 249: return nil if value.nil? 250: value = Marshal.load value unless raw 251: return value 252: end 253: rescue TypeError => err 254: handle_error nil, err 255: 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:
map the key to the appropriate memcached server
send a single request to each server that has one or more key values
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. You can pass in :raw => true to bypass value marshalling.
cache.get_multi('a', 'b', ..., :raw => true)
# File lib/memcache.rb, line 297 297: def get_multi(*keys) 298: raise MemCacheError, 'No active servers' unless active? 299: 300: opts = keys.last.is_a?(Hash) ? keys.pop : {} 301: 302: keys.flatten! 303: key_count = keys.length 304: cache_keys = {} 305: server_keys = Hash.new { |h,k| h[k] = [] } 306: 307: # map keys to servers 308: keys.each do |key| 309: server, cache_key = request_setup key 310: cache_keys[cache_key] = key 311: server_keys[server] << cache_key 312: end 313: 314: results = {} 315: raw = opts[:raw] || false 316: server_keys.each do |server, keys_for_server| 317: keys_for_server_str = keys_for_server.join ' ' 318: begin 319: values = cache_get_multi server, keys_for_server_str 320: values.each do |key, value| 321: results[cache_keys[key]] = raw ? value : Marshal.load(value) 322: end 323: rescue IndexError => e 324: # Ignore this server and try the others 325: logger.warn { "Unable to retrieve #{keys_for_server.size} elements from #{server.inspect}: #{e.message}"} if logger 326: end 327: end 328: 329: return results 330: rescue TypeError => err 331: handle_error nil, err 332: 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 lib/memcache.rb, line 339 339: def incr(key, amount = 1) 340: raise MemCacheError, "Update of readonly cache" if @readonly 341: with_server(key) do |server, cache_key| 342: cache_incr server, cache_key, amount 343: end 344: rescue TypeError => err 345: handle_error nil, err 346: end
Returns a string representation of the cache object.
# File lib/memcache.rb, line 181 181: def inspect 182: "<MemCache: %d servers, ns: %p, ro: %p>" % 183: [@servers.length, @namespace, @readonly] 184: 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 lib/memcache.rb, line 500 500: def prepend(key, value) 501: raise MemCacheError, "Update of readonly cache" if @readonly 502: with_server(key) do |server, cache_key| 503: logger.debug { "prepend #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 504: command = "prepend #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 505: 506: with_socket_management(server) do |socket| 507: socket.write command 508: break nil if @no_reply 509: result = socket.gets 510: raise_on_error_response! result 511: result 512: end 513: end 514: end
Returns whether or not the cache object was created read only.
# File lib/memcache.rb, line 196 196: def readonly? 197: @readonly 198: 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 lib/memcache.rb, line 459 459: def replace(key, value, expiry = 0, raw = false) 460: raise MemCacheError, "Update of readonly cache" if @readonly 461: value = Marshal.dump value unless raw 462: with_server(key) do |server, cache_key| 463: logger.debug { "replace #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger 464: command = "replace #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 465: 466: with_socket_management(server) do |socket| 467: socket.write command 468: break nil if @no_reply 469: result = socket.gets 470: raise_on_error_response! result 471: result 472: end 473: end 474: 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 lib/memcache.rb, line 574 574: def reset 575: @servers.each { |server| server.close } 576: 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 lib/memcache.rb, line 205 205: def servers=(servers) 206: # Create the server objects. 207: @servers = Array(servers).collect do |server| 208: case server 209: when String 210: host, port, weight = server.split ':', 3 211: port ||= DEFAULT_PORT 212: weight ||= DEFAULT_WEIGHT 213: Server.new self, host, port, weight 214: else 215: server 216: end 217: end 218: 219: logger.debug { "Servers now: #{@servers.inspect}" } if logger 220: 221: # There's no point in doing this if there's only one server 222: @continuum = create_continuum_for(@servers) if @servers.size > 1 223: 224: @servers 225: end
# File lib/memcache.rb, line 357 357: def set(key, value, expiry = 0, raw = false) 358: raise MemCacheError, "Update of readonly cache" if @readonly 359: 360: value = Marshal.dump value unless raw 361: with_server(key) do |server, cache_key| 362: logger.debug { "set #{key} to #{server.inspect}: #{value.to_s.size}" } if logger 363: 364: if @check_size && value.to_s.size > ONE_MB 365: raise MemCacheError, "Value too large, memcached can only store 1MB of data per key" 366: end 367: 368: command = "set #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" 369: 370: with_socket_management(server) do |socket| 371: socket.write command 372: break nil if @no_reply 373: result = socket.gets 374: raise_on_error_response! result 375: 376: if result.nil? 377: server.close 378: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 379: end 380: 381: result 382: end 383: end 384: 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 lib/memcache.rb, line 610 610: def stats 611: raise MemCacheError, "No active servers" unless active? 612: server_stats = {} 613: 614: @servers.each do |server| 615: next unless server.alive? 616: 617: with_socket_management(server) do |socket| 618: value = nil 619: socket.write "stats\r\n" 620: stats = {} 621: while line = socket.gets do 622: raise_on_error_response! line 623: break if line == "END\r\n" 624: if line =~ /\ASTAT ([\S]+) ([\w\.\:]+)/ then 625: name, value = $1, $2 626: stats[name] = case name 627: when 'version' 628: value 629: when 'rusage_user', 'rusage_system' then 630: seconds, microseconds = value.split(/:/, 2) 631: microseconds ||= 0 632: Float(seconds) + (Float(microseconds) / 1_000_000) 633: else 634: if value =~ /\A\d+\Z/ then 635: value.to_i 636: else 637: value 638: end 639: end 640: end 641: end 642: server_stats["#{server.host}:#{server.port}"] = stats 643: end 644: end 645: 646: raise MemCacheError, "No active servers" if server_stats.empty? 647: server_stats 648: end
Performs a raw decr for cache_key from server. Returns nil if not found.
# File lib/memcache.rb, line 724 724: def cache_decr(server, cache_key, amount) 725: with_socket_management(server) do |socket| 726: socket.write "decr #{cache_key} #{amount}#{noreply}\r\n" 727: break nil if @no_reply 728: text = socket.gets 729: raise_on_error_response! text 730: return nil if text == "NOT_FOUND\r\n" 731: return text.to_i 732: end 733: end
Fetches the raw data for cache_key from server. Returns nil on cache miss.
# File lib/memcache.rb, line 739 739: def cache_get(server, cache_key) 740: with_socket_management(server) do |socket| 741: socket.write "get #{cache_key}\r\n" 742: keyline = socket.gets # "VALUE <key> <flags> <bytes>\r\n" 743: 744: if keyline.nil? then 745: server.close 746: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 747: end 748: 749: raise_on_error_response! keyline 750: return nil if keyline == "END\r\n" 751: 752: unless keyline =~ /(\d+)\r/ then 753: server.close 754: raise MemCacheError, "unexpected response #{keyline.inspect}" 755: end 756: value = socket.read $1.to_i 757: socket.read 2 # "\r\n" 758: socket.gets # "END\r\n" 759: return value 760: end 761: end
Fetches cache_keys from server using a multi-get.
# File lib/memcache.rb, line 798 798: def cache_get_multi(server, cache_keys) 799: with_socket_management(server) do |socket| 800: values = {} 801: socket.write "get #{cache_keys}\r\n" 802: 803: while keyline = socket.gets do 804: return values if keyline == "END\r\n" 805: raise_on_error_response! keyline 806: 807: unless keyline =~ /\AVALUE (.+) (.+) (.+)/ then 808: server.close 809: raise MemCacheError, "unexpected response #{keyline.inspect}" 810: end 811: 812: key, data_length = $1, $3 813: values[$1] = socket.read data_length.to_i 814: socket.read(2) # "\r\n" 815: end 816: 817: server.close 818: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" # TODO: retry here too 819: end 820: end
Performs a raw incr for cache_key from server. Returns nil if not found.
# File lib/memcache.rb, line 826 826: def cache_incr(server, cache_key, amount) 827: with_socket_management(server) do |socket| 828: socket.write "incr #{cache_key} #{amount}#{noreply}\r\n" 829: break nil if @no_reply 830: text = socket.gets 831: raise_on_error_response! text 832: return nil if text == "NOT_FOUND\r\n" 833: return text.to_i 834: end 835: end
# File lib/memcache.rb, line 949 949: def check_multithread_status! 950: return if @multithread 951: return if @evented 952: 953: if Thread.current[:memcache_client] != self.object_id 954: raise MemCacheError, You are accessing this memcache-client instance from multiple threads but have not enabled multithread support. Normally: MemCache.new(['localhost:11211'], :multithread => true) In Rails: config.cache_store = [:mem_cache_store, 'localhost:11211', { :multithread => true }] 955: end 956: end
# File lib/memcache.rb, line 930 930: def create_continuum_for(servers) 931: total_weight = servers.inject(0) { |memo, srv| memo + srv.weight } 932: continuum = [] 933: 934: servers.each do |server| 935: entry_count_for(server, servers.size, total_weight).times do |idx| 936: hash = Digest::SHA1.hexdigest("#{server.host}:#{server.port}:#{idx}") 937: value = Integer("0x#{hash[0..7]}") 938: continuum << Continuum::Entry.new(value, server) 939: end 940: end 941: 942: continuum.sort { |a, b| a.value <=> b.value } 943: end
# File lib/memcache.rb, line 945 945: def entry_count_for(server, total_servers, total_weight) 946: ((total_servers * Continuum::POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor 947: end
Pick a server to handle the request based on a hash of the key.
# File lib/memcache.rb, line 699 699: def get_server_for_key(key, options = {}) 700: raise ArgumentError, "illegal character in key #{key.inspect}" if 701: key =~ /\s/ 702: raise ArgumentError, "key cannot be blank" if key.nil? || key.strip.size == 0 703: raise ArgumentError, "key too long #{key.inspect}" if key.length > 250 704: raise MemCacheError, "No servers available" if @servers.empty? 705: return @servers.first if @servers.length == 1 706: 707: hkey = hash_for(key) 708: 709: 20.times do |try| 710: entryidx = Continuum.binary_search(@continuum, hkey) 711: server = @continuum[entryidx].server 712: return server if server.alive? 713: break unless failover 714: hkey = hash_for "#{try}#{key}" 715: end 716: 717: raise MemCacheError, "No servers available" 718: end
# File lib/memcache.rb, line 763 763: def gets(key, raw = false) 764: with_server(key) do |server, cache_key| 765: logger.debug { "gets #{key} from #{server.inspect}" } if logger 766: result = with_socket_management(server) do |socket| 767: socket.write "gets #{cache_key}\r\n" 768: keyline = socket.gets # "VALUE <key> <flags> <bytes> <cas token>\r\n" 769: 770: if keyline.nil? then 771: server.close 772: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 773: end 774: 775: raise_on_error_response! keyline 776: return nil if keyline == "END\r\n" 777: 778: unless keyline =~ /(\d+) (\w+)\r/ then 779: server.close 780: raise MemCacheError, "unexpected response #{keyline.inspect}" 781: end 782: value = socket.read $1.to_i 783: socket.read 2 # "\r\n" 784: socket.gets # "END\r\n" 785: [value, $2] 786: end 787: result[0] = Marshal.load result[0] unless raw 788: result 789: end 790: rescue TypeError => err 791: handle_error nil, err 792: end
Handles error from server.
# File lib/memcache.rb, line 901 901: def handle_error(server, error) 902: raise error if error.is_a?(MemCacheError) 903: server.close if server && server.status == "CONNECTED" 904: new_error = MemCacheError.new error.message 905: new_error.set_backtrace error.backtrace 906: raise new_error 907: end
Returns an interoperable hash value for key. (I think, docs are sketchy for down servers).
# File lib/memcache.rb, line 692 692: def hash_for(key) 693: Zlib.crc32(key) 694: end
Calculate length of the key, including the namespace and namespace-separator.
# File lib/memcache.rb, line 684 684: def key_length(key) 685: key.length + (namespace.nil? ? 0 : ( namespace.length + (@namespace_separator.nil? ? 0 : @namespace_separator.length) ) ) 686: end
Create a key for the cache, incorporating the namespace qualifier if requested.
# File lib/memcache.rb, line 669 669: def make_cache_key(key) 670: if @autofix_keys && (key =~ /\s/ || key_length(key) > 250) 671: key = "#{Digest::SHA1.hexdigest(key)}-autofixed" 672: end 673: 674: if namespace.nil? 675: key 676: else 677: "#{@namespace}#{@namespace_separator}#{key}" 678: end 679: end
# File lib/memcache.rb, line 909 909: def noreply 910: @no_reply ? ' noreply' : '' 911: end
# File lib/memcache.rb, line 924 924: def raise_on_error_response!(response) 925: if response =~ /\A(?:CLIENT_|SERVER_)?ERROR(.*)/ 926: raise MemCacheError, $1.strip 927: end 928: 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 lib/memcache.rb, line 917 917: def request_setup(key) 918: raise MemCacheError, 'No active servers' unless active? 919: cache_key = make_cache_key key 920: server = get_server_for_key cache_key 921: return server, cache_key 922: end
# File lib/memcache.rb, line 882 882: def with_server(key) 883: retried = false 884: begin 885: server, cache_key = request_setup(key) 886: yield server, cache_key 887: rescue IndexError => e 888: logger.warn { "Server failed: #{e.class.name}: #{e.message}" } if logger 889: if !retried && @servers.size > 1 890: logger.info { "Connection to server #{server.inspect} DIED! Retrying operation..." } if logger 891: retried = true 892: retry 893: end 894: handle_error(nil, e) 895: end 896: 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 lib/memcache.rb, line 851 851: def with_socket_management(server, &block) 852: check_multithread_status! 853: 854: @mutex.lock if @multithread 855: retried = false 856: 857: begin 858: socket = server.socket 859: 860: # Raise an IndexError to show this server is out of whack. If were inside 861: # a with_server block, we'll catch it and attempt to restart the operation. 862: 863: raise IndexError, "No connection to server (#{server.status})" if socket.nil? 864: 865: block.call(socket) 866: 867: rescue SocketError, Errno::EAGAIN, Timeout::Error => err 868: logger.warn { "Socket failure: #{err.message}" } if logger 869: server.mark_dead(err) 870: handle_error(server, err) 871: 872: rescue MemCacheError, SystemCallError, IOError => err 873: logger.warn { "Generic failure: #{err.class.name}: #{err.message}" } if logger 874: handle_error(server, err) if retried || socket.nil? 875: retried = true 876: retry 877: end 878: ensure 879: @mutex.unlock if @multithread 880: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.