Class | MemCache |
In: |
vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb
|
Parent: | Object |
A Ruby client library for memcached.
This is intended to provide access to basic memcached functionality. It does not attempt to be complete implementation of the entire API, but it is approaching a complete implementation.
VERSION | = | '1.5.0' | The version of MemCache you are using. | |
DEFAULT_OPTIONS | = | { :namespace => nil, :readonly => false, :multithread => false, } | Default options for the cache object. | |
DEFAULT_PORT | = | 11211 | Default memcached port. | |
DEFAULT_WEIGHT | = | 1 | Default memcached server weight. |
multithread | [R] | The multithread setting for this instance |
namespace | [R] | The namespace for this instance |
request_timeout | [RW] | The amount of time to wait for a response from a memcached server. If a response is not completed within this time, the connection to the server will be closed and an error will be raised. |
servers | [R] | The servers this client talks to. Play at your own peril. |
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 exeception on cache writes when true. [:multithread] Wraps cache access in a Mutex for thread safety.
Other options are ignored.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 127 127: def initialize(*args) 128: servers = [] 129: opts = {} 130: 131: case args.length 132: when 0 then # NOP 133: when 1 then 134: arg = args.shift 135: case arg 136: when Hash then opts = arg 137: when Array then servers = arg 138: when String then servers = [arg] 139: else raise ArgumentError, 'first argument must be Array, Hash or String' 140: end 141: when 2 then 142: servers, opts = args 143: else 144: raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 145: end 146: 147: opts = DEFAULT_OPTIONS.merge opts 148: @namespace = opts[:namespace] 149: @readonly = opts[:readonly] 150: @multithread = opts[:multithread] 151: @mutex = Mutex.new if @multithread 152: @buckets = [] 153: self.servers = servers 154: end
Returns whether there is at least one active server for the object.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 167 167: def active? 168: not @servers.empty? 169: 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 or MemCache#[]=.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 352 352: def add(key, value, expiry = 0, raw = false) 353: raise MemCacheError, "Update of readonly cache" if @readonly 354: server, cache_key = request_setup key 355: socket = server.socket 356: 357: value = Marshal.dump value unless raw 358: command = "add #{cache_key} 0 #{expiry} #{value.size}\r\n#{value}\r\n" 359: 360: begin 361: @mutex.lock if @multithread 362: socket.write command 363: result = socket.gets 364: raise_on_error_response! result 365: result 366: rescue SocketError, SystemCallError, IOError => err 367: server.close 368: raise MemCacheError, err.message 369: ensure 370: @mutex.unlock if @multithread 371: end 372: end
Deceremets 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.5.0/memcache.rb, line 214 214: def decr(key, amount = 1) 215: server, cache_key = request_setup key 216: 217: if @multithread then 218: threadsafe_cache_decr server, cache_key, amount 219: else 220: cache_decr server, cache_key, amount 221: end 222: rescue TypeError, SocketError, SystemCallError, IOError => err 223: handle_error server, err 224: end
Removes key from the cache in expiry seconds.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 377 377: def delete(key, expiry = 0) 378: @mutex.lock if @multithread 379: 380: raise MemCacheError, "No active servers" unless active? 381: cache_key = make_cache_key key 382: server = get_server_for_key cache_key 383: 384: sock = server.socket 385: raise MemCacheError, "No connection to server" if sock.nil? 386: 387: begin 388: sock.write "delete #{cache_key} #{expiry}\r\n" 389: result = sock.gets 390: raise_on_error_response! result 391: result 392: rescue SocketError, SystemCallError, IOError => err 393: server.close 394: raise MemCacheError, err.message 395: end 396: ensure 397: @mutex.unlock if @multithread 398: end
Flush the cache from all memcache servers.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 403 403: def flush_all 404: raise MemCacheError, 'No active servers' unless active? 405: raise MemCacheError, "Update of readonly cache" if @readonly 406: begin 407: @mutex.lock if @multithread 408: @servers.each do |server| 409: begin 410: sock = server.socket 411: raise MemCacheError, "No connection to server" if sock.nil? 412: sock.write "flush_all\r\n" 413: result = sock.gets 414: raise_on_error_response! result 415: result 416: rescue SocketError, SystemCallError, IOError => err 417: server.close 418: raise MemCacheError, err.message 419: end 420: end 421: ensure 422: @mutex.unlock if @multithread 423: end 424: 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.5.0/memcache.rb, line 230 230: def get(key, raw = false) 231: server, cache_key = request_setup key 232: 233: value = if @multithread then 234: threadsafe_cache_get server, cache_key 235: else 236: cache_get server, cache_key 237: end 238: 239: return nil if value.nil? 240: 241: value = Marshal.load value unless raw 242: 243: return value 244: rescue TypeError, SocketError, SystemCallError, IOError => err 245: handle_error server, err 246: 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 }
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 264 264: def get_multi(*keys) 265: raise MemCacheError, 'No active servers' unless active? 266: 267: keys.flatten! 268: key_count = keys.length 269: cache_keys = {} 270: server_keys = Hash.new { |h,k| h[k] = [] } 271: 272: # map keys to servers 273: keys.each do |key| 274: server, cache_key = request_setup key 275: cache_keys[cache_key] = key 276: server_keys[server] << cache_key 277: end 278: 279: results = {} 280: 281: server_keys.each do |server, keys_for_server| 282: keys_for_server = keys_for_server.join ' ' 283: values = if @multithread then 284: threadsafe_cache_get_multi server, keys_for_server 285: else 286: cache_get_multi server, keys_for_server 287: end 288: values.each do |key, value| 289: results[cache_keys[key]] = Marshal.load value 290: end 291: end 292: 293: return results 294: rescue TypeError, SocketError, SystemCallError, IOError => err 295: handle_error server, err 296: end
Increments the value for key by amount and retruns 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.5.0/memcache.rb, line 303 303: def incr(key, amount = 1) 304: server, cache_key = request_setup key 305: 306: if @multithread then 307: threadsafe_cache_incr server, cache_key, amount 308: else 309: cache_incr server, cache_key, amount 310: end 311: rescue TypeError, SocketError, SystemCallError, IOError => err 312: handle_error server, err 313: end
Returns a string representation of the cache object.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 159 159: def inspect 160: "<MemCache: %d servers, %d buckets, ns: %p, ro: %p>" % 161: [@servers.length, @buckets.length, @namespace, @readonly] 162: end
Returns whether or not the cache object was created read only.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 174 174: def readonly? 175: @readonly 176: 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.5.0/memcache.rb, line 431 431: def reset 432: @servers.each { |server| server.close } 433: 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.5.0/memcache.rb, line 183 183: def servers=(servers) 184: # Create the server objects. 185: @servers = servers.collect do |server| 186: case server 187: when String 188: host, port, weight = server.split ':', 3 189: port ||= DEFAULT_PORT 190: weight ||= DEFAULT_WEIGHT 191: Server.new self, host, port, weight 192: when Server 193: if server.memcache.multithread != @multithread then 194: raise ArgumentError, "can't mix threaded and non-threaded servers" 195: end 196: server 197: else 198: raise TypeError, "cannot convert #{server.class} into MemCache::Server" 199: end 200: end 201: 202: # Create an array of server buckets for weight selection of servers. 203: @buckets = [] 204: @servers.each do |server| 205: server.weight.times { @buckets.push(server) } 206: end 207: end
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.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 322 322: def set(key, value, expiry = 0, raw = false) 323: raise MemCacheError, "Update of readonly cache" if @readonly 324: server, cache_key = request_setup key 325: socket = server.socket 326: 327: value = Marshal.dump value unless raw 328: command = "set #{cache_key} 0 #{expiry} #{value.size}\r\n#{value}\r\n" 329: 330: begin 331: @mutex.lock if @multithread 332: socket.write command 333: result = socket.gets 334: raise_on_error_response! result 335: result 336: rescue SocketError, SystemCallError, IOError => err 337: server.close 338: raise MemCacheError, err.message 339: ensure 340: @mutex.unlock if @multithread 341: end 342: 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.5.0/memcache.rb, line 467 467: def stats 468: raise MemCacheError, "No active servers" unless active? 469: server_stats = {} 470: 471: @servers.each do |server| 472: sock = server.socket 473: raise MemCacheError, "No connection to server" if sock.nil? 474: 475: value = nil 476: begin 477: sock.write "stats\r\n" 478: stats = {} 479: while line = sock.gets do 480: raise_on_error_response! line 481: break if line == "END\r\n" 482: if line =~ /\ASTAT ([\w]+) ([\w\.\:]+)/ then 483: name, value = $1, $2 484: stats[name] = case name 485: when 'version' 486: value 487: when 'rusage_user', 'rusage_system' then 488: seconds, microseconds = value.split(/:/, 2) 489: microseconds ||= 0 490: Float(seconds) + (Float(microseconds) / 1_000_000) 491: else 492: if value =~ /\A\d+\Z/ then 493: value.to_i 494: else 495: value 496: end 497: end 498: end 499: end 500: server_stats["#{server.host}:#{server.port}"] = stats 501: rescue SocketError, SystemCallError, IOError => err 502: server.close 503: raise MemCacheError, err.message 504: end 505: end 506: 507: server_stats 508: 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.5.0/memcache.rb, line 570 570: def cache_decr(server, cache_key, amount) 571: socket = server.socket 572: socket.write "decr #{cache_key} #{amount}\r\n" 573: text = socket.gets 574: raise_on_error_response! text 575: return nil if text == "NOT_FOUND\r\n" 576: return text.to_i 577: 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.5.0/memcache.rb, line 583 583: def cache_get(server, cache_key) 584: socket = server.socket 585: socket.write "get #{cache_key}\r\n" 586: keyline = socket.gets # "VALUE <key> <flags> <bytes>\r\n" 587: 588: if keyline.nil? then 589: server.close 590: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 591: end 592: 593: raise_on_error_response! keyline 594: return nil if keyline == "END\r\n" 595: 596: unless keyline =~ /(\d+)\r/ then 597: server.close 598: raise MemCacheError, "unexpected response #{keyline.inspect}" 599: end 600: value = socket.read $1.to_i 601: socket.read 2 # "\r\n" 602: socket.gets # "END\r\n" 603: return value 604: end
Fetches cache_keys from server using a multi-get.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 609 609: def cache_get_multi(server, cache_keys) 610: values = {} 611: socket = server.socket 612: socket.write "get #{cache_keys}\r\n" 613: 614: while keyline = socket.gets do 615: return values if keyline == "END\r\n" 616: raise_on_error_response! keyline 617: 618: unless keyline =~ /\AVALUE (.+) (.+) (.+)/ then 619: server.close 620: raise MemCacheError, "unexpected response #{keyline.inspect}" 621: end 622: 623: key, data_length = $1, $3 624: values[$1] = socket.read data_length.to_i 625: socket.read(2) # "\r\n" 626: end 627: 628: server.close 629: raise MemCacheError, "lost connection to #{server.host}:#{server.port}" 630: 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.5.0/memcache.rb, line 636 636: def cache_incr(server, cache_key, amount) 637: socket = server.socket 638: socket.write "incr #{cache_key} #{amount}\r\n" 639: text = socket.gets 640: raise_on_error_response! text 641: return nil if text == "NOT_FOUND\r\n" 642: return text.to_i 643: 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.5.0/memcache.rb, line 540 540: def get_server_for_key(key) 541: raise ArgumentError, "illegal character in key #{key.inspect}" if 542: key =~ /\s/ 543: raise ArgumentError, "key too long #{key.inspect}" if key.length > 250 544: raise MemCacheError, "No servers available" if @servers.empty? 545: return @servers.first if @servers.length == 1 546: 547: hkey = hash_for key 548: 549: 20.times do |try| 550: server = @buckets[hkey % @buckets.nitems] 551: return server if server.alive? 552: hkey += hash_for "#{try}#{key}" 553: end 554: 555: raise MemCacheError, "No servers available" 556: end
Handles error from server.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 648 648: def handle_error(server, error) 649: server.close if server 650: new_error = MemCacheError.new error.message 651: new_error.set_backtrace error.backtrace 652: raise new_error 653: 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.5.0/memcache.rb, line 562 562: def hash_for(key) 563: (key.crc32_ITU_T >> 16) & 0x7fff 564: end
Create a key for the cache, incorporating the namespace qualifier if requested.
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 529 529: def make_cache_key(key) 530: if namespace.nil? then 531: key 532: else 533: "#{@namespace}:#{key}" 534: end 535: end
# File vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb, line 695 695: def raise_on_error_response!(response) 696: if response =~ /\A(?:CLIENT_|SERVER_)?ERROR (.*)/ 697: raise MemCacheError, $1.strip 698: end 699: 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.5.0/memcache.rb, line 659 659: def request_setup(key) 660: raise MemCacheError, 'No active servers' unless active? 661: cache_key = make_cache_key key 662: server = get_server_for_key cache_key 663: raise MemCacheError, 'No connection to server' if server.socket.nil? 664: return server, cache_key 665: end