Class: Memcached

The Memcached client class.

Child modules and classes

Class Memcached::Error
Class Memcached::Rails

Constants

NameValue
FLAGS 0x0
DEFAULTS { :hash => :default, :no_block => false, :distribution => :consistent, :buffer_requests => false, :cache_lookups => true, :support_cas => false, :tcp_nodelay => false, :show_not_found_backtraces => false, :retry_timeout => 60, # :poll_timeout => 5, :connect_timeout => 5, :prefix_key => nil, :sort_hosts => false, :failover => false, :verify_key => true
Lib Rlibmemcached
REQUIRED_VERSION File.read("#{File.dirname(__FILE__)}/../COMPATIBILITY")[/:: ([\d\.]+)/, 1]
RECEIVED_VERSION Lib.memcached_lib_version

Attributes

NameRead/write?
options R

Public Class Methods


new (servers, opts = {})

Create a new Memcached instance. Accepts a single server string such as ‘localhost:11211’, or an array of such strings, as well an an optional configuration hash.

Valid option parameters are:

:prefix_key:A string to prepend to every key, for namespacing. Max length is 11.
:hash:The name of a hash function to use. Possible values are: :crc, :default, :fnv1_32, :fnv1_64, :fnv1a_32, :fnv1a_64, :hsieh, :md5, and :murmur. :default is the fastest. Use :md5 for compatibility with other ketama clients.
:distribution:Either :modula, :consistent, or :consistent_wheel. Defaults to :consistent, which is ketama-compatible.
:failover:Whether to permanently eject failed hosts from the pool. Defaults to false. Note that in the event of a server failure, :failover will remap the entire pool unless :distribution is set to :consistent.
:cache_lookups:Whether to cache hostname lookups for the life of the instance. Defaults to true.
:support_cas:Flag CAS support in the client. Accepts true or false. Defaults to false because it imposes a slight performance penalty. Note that your server must also support CAS or you will trigger Memcached::ProtocolError exceptions.
:tcp_nodelay:Turns on the no-delay feature for connecting sockets. Accepts true or false. Performance may or may not change, depending on your system.
:no_block:Whether to use non-blocking, asynchronous IO for writes. Accepts true or false.
:buffer_requests:Whether to use an internal write buffer. Accepts true or false. Calling get or closing the connection will force the buffer to flush. Note that :buffer_requests might not work well without :no_block also enabled.
:show_not_found_backtraces:Whether Memcached::NotFound exceptions should include backtraces. Generating backtraces is slow, so this is off by default. Turn it on to ease debugging.
:sort_hosts:Whether to force the server list to stay sorted. This defeats consistent hashing and is rarely useful.
:verify_key:Validate keys before accepting them. Never disable this.

Please note that when non-blocking IO is enabled, setter and deleter methods do not raise on errors. For example, if you try to set an invalid key with :no_block => true, it will appear to succeed. The actual setting of the key occurs after libmemcached has returned control to your program, so there is no way to backtrack and raise the exception.

    # File lib/memcached/memcached.rb, line 59
59:   def initialize(servers, opts = {})
60:     @struct = Lib::MemcachedSt.new    
61:     Lib.memcached_create(@struct)
62: 
63:     # Merge option defaults
64:     @options = DEFAULTS.merge(opts)
65:     
66:     # Force :buffer_requests to use :no_block
67:     # XXX Deleting the :no_block key should also work, but libmemcached doesn't seem to set it
68:     # consistently
69:     options[:no_block] = true if options[:buffer_requests] 
70:     
71:     # Legacy accessor
72:     options[:prefix_key] = options.delete(:namespace) if options[:namespace]
73:     
74:     # Disallow :sort_hosts with consistent hashing
75:     if options[:sort_hosts] and options[:distribution] == :consistent
76:       raise ArgumentError, ":sort_hosts defeats :consistent hashing"
77:     end
78:     
79:     # Set the behaviors on the struct
80:     set_behaviors
81:     set_callbacks
82: 
83:     # Freeze the hash
84:     options.freeze
85: 
86:     # Set the servers on the struct
87:     set_servers(servers)         
88:         
89:     # Not found exceptions
90:     # Note that these have global effects since the NotFound class itself is modified. You should only 
91:     # be enabling the backtrace for debugging purposes, so it's not really a big deal.
92:     if options[:show_not_found_backtraces]
93:       NotFound.restore_backtraces
94:     else
95:       NotFound.remove_backtraces
96:     end    
97:   end

Public Instance Methods


add (key, value, timeout=0, marshal=true)

Add a key/value pair. Raises Memcached::NotStored if the key already exists on the server. The parameters are the same as set.

     # File lib/memcached/memcached.rb, line 164
164:   def add(key, value, timeout=0, marshal=true)
165:     value = marshal ? Marshal.dump(value) : value.to_s
166:     check_return_code(
167:       Lib.memcached_add(@struct, key, value, timeout, FLAGS)
168:     )
169:   end

append (key, value)

Appends a string to a key‘s value. Accepts a String key and a String value. Raises Memcached::NotFound if the key does not exist on the server.

Note that the key must be initialized to an unmarshalled string first, via set, add, or replace with marshal set to false.

     # File lib/memcached/memcached.rb, line 205
205:   def append(key, value)
206:     # Requires memcached 1.2.4
207:     check_return_code(
208:       Lib.memcached_append(@struct, key, value.to_s, IGNORED, FLAGS)
209:     )
210:   end

cas (key, timeout = 0, marshal = true) {|value| ...}

Reads a key‘s value from the server and yields it to a block. Replaces the key‘s value with the result of the block as long as the key hasn‘t been updated in the meantime, otherwise raises Memcached::NotStored. Accepts a String key and a block.

Also accepts an optional timeout value.

CAS stands for "compare and swap", and avoids the need for manual key mutexing. CAS support must be enabled in Memcached.new or a Memcached::ClientError will be raised. Note that CAS may be buggy in memcached itself.

     # File lib/memcached/memcached.rb, line 226
226:   def cas(key, timeout = 0, marshal = true)
227:     raise ClientError, "CAS not enabled for this Memcached instance" unless options[:support_cas]
228:       
229:     value = get(key, marshal)
230:     value = yield value
231:     value = marshal ? Marshal.dump(value) : value.to_s
232:     
233:     check_return_code(
234:       Lib.memcached_cas(@struct, key, value, timeout, FLAGS, @struct.result.cas)
235:     )
236:   end

clone ()

Safely copy this instance. Returns a Memcached instance.

clone is useful for threading, since each thread must have its own unshared Memcached object.

     # File lib/memcached/memcached.rb, line 111
111:   def clone
112:     memcached = super
113:     memcached.instance_variable_set('@struct', Lib.memcached_clone(nil, @struct))
114:     memcached
115:   end

decrement (key, offset=1)

Decrement a key‘s value. The parameters and exception behavior are the same as increment.

     # File lib/memcached/memcached.rb, line 183
183:   def decrement(key, offset=1)
184:     ret, value = Lib.memcached_decrement(@struct, key, offset)
185:     check_return_code(ret)
186:     value
187:   end

delete (key)

Deletes a key/value pair from the server. Accepts a String key. Raises Memcached::NotFound if the key does not exist.

     # File lib/memcached/memcached.rb, line 241
241:   def delete(key)
242:     check_return_code(
243:       Lib.memcached_delete(@struct, key, IGNORED)
244:     )  
245:   end

flush ()

Flushes all key/value pairs from all the servers.

     # File lib/memcached/memcached.rb, line 248
248:   def flush
249:     check_return_code(
250:       Lib.memcached_flush(@struct, IGNORED)
251:     )
252:   end

get (keys, marshal=true)

Gets a key‘s value from the server. Accepts a String key or array of String keys.

Also accepts a marshal value, which defaults to true. Set marshal to false if you want the value to be returned directly as a String. Otherwise it will be assumed to be a marshalled Ruby object and unmarshalled.

If you pass a String key, and the key does not exist on the server, Memcached::NotFound will be raised. If you pass an array of keys, memcached‘s multiget mode will be used, and a hash of key/value pairs will be returned. The hash will contain only the keys that were found.

The multiget behavior is subject to change in the future; however, for multiple lookups, it is much faster than normal mode.

Note that when you rescue Memcached::NotFound exceptions, you should use a the block rescue syntax instead of the inline syntax. Block rescues are very fast, but inline rescues are very slow.

     # File lib/memcached/memcached.rb, line 266
266:   def get(keys, marshal=true)
267:     if keys.is_a? Array
268:       # Multi get
269:       keys.map! { |key| key }
270:       hash = {}
271:       
272:       ret = Lib.memcached_mget(@struct, keys);
273:       check_return_code(ret)
274:       
275:       keys.size.times do 
276:         value, key, flags, ret = Lib.memcached_fetch_rvalue(@struct)
277:         break if ret == Lib::MEMCACHED_END
278:         check_return_code(ret)
279:         value = Marshal.load(value) if marshal
280:         # Assign the value
281:         hash[key] = value
282:       end
283:       hash
284:     else
285:       # Single get
286:       value, flags, ret = Lib.memcached_get_rvalue(@struct, keys)
287:       check_return_code(ret)
288:       value = Marshal.load(value) if marshal
289:       value
290:     end    
291:   end


increment (key, offset=1)

Increment a key‘s value. Accepts a String key. Raises Memcached::NotFound if the key does not exist.

Also accepts an optional offset paramater, which defaults to 1. offset must be an integer.

Note that the key must be initialized to an unmarshalled integer first, via set, add, or replace with marshal set to false.

     # File lib/memcached/memcached.rb, line 176
176:   def increment(key, offset=1)
177:     ret, value = Lib.memcached_increment(@struct, key, offset)
178:     check_return_code(ret)
179:     value
180:   end

prepend (key, value)

Prepends a string to a key‘s value. The parameters and exception behavior are the same as append.

     # File lib/memcached/memcached.rb, line 213
213:   def prepend(key, value)
214:     # Requires memcached 1.2.4
215:     check_return_code(
216:       Lib.memcached_prepend(@struct, key, value.to_s, IGNORED, FLAGS)
217:     )
218:   end

replace (key, value, timeout=0, marshal=true)

Replace a key/value pair. Raises Memcached::NotFound if the key does not exist on the server. The parameters are the same as set.

     # File lib/memcached/memcached.rb, line 195
195:   def replace(key, value, timeout=0, marshal=true)
196:     value = marshal ? Marshal.dump(value) : value.to_s
197:     check_return_code(
198:       Lib.memcached_replace(@struct, key, value, timeout, FLAGS)
199:     )
200:   end

reset (current_servers = nil)

Reset the state of the libmemcached struct. This is useful for changing the server list at runtime.

     # File lib/memcached/memcached.rb, line 118
118:   def reset(current_servers = nil)
119:     current_servers ||= servers
120:     @struct = Lib::MemcachedSt.new    
121:     Lib.memcached_create(@struct)
122:     set_behaviors
123:     set_callbacks
124:     set_servers(current_servers)
125:   end

servers ()

Return the array of server strings used to configure this instance.

     # File lib/memcached/memcached.rb, line 100
100:   def servers
101:     server_structs.map do |server|
102:       "#{server.hostname}:#{server.port}"
103:     end
104:   end

set (key, value, timeout=0, marshal=true)

Set a key/value pair. Accepts a String key and an arbitrary Ruby object. Overwrites any existing value on the server.

Accepts an optional timeout value to specify the maximum lifetime of the key on the server. timeout can be either an integer number of seconds, or a Time elapsed time object. 0 means no timeout. Note that there is no guarantee that the key will persist as long as the timeout, but it will not persist longer.

Also accepts a marshal value, which defaults to true. Set marshal to false if you want the value to be set directly.

     # File lib/memcached/memcached.rb, line 156
156:   def set(key, value, timeout=0, marshal=true)
157:     value = marshal ? Marshal.dump(value) : value.to_s
158:     check_return_code(
159:       Lib.memcached_set(@struct, key, value, timeout, FLAGS)
160:     )
161:   end

stats ()

Return a Hash of statistics responses from the set of servers. Each value is an array with one entry for each server, in the same order the servers were defined.

     # File lib/memcached/memcached.rb, line 296
296:   def stats
297:     stats = Hash.new([])
298:     
299:     stat_struct, ret = Lib.memcached_stat(@struct, "")
300:     check_return_code(ret)
301:     
302:     keys, ret = Lib.memcached_stat_get_keys(@struct, stat_struct)
303:     check_return_code(ret)
304:     
305:     keys.each do |key|
306:        server_structs.size.times do |index|
307: 
308:          value, ret = Lib.memcached_stat_get_rvalue(
309:            @struct, 
310:            Lib.memcached_select_stat_at(@struct, stat_struct, index),
311:            key)
312:          check_return_code(ret)
313: 
314:          value = case value
315:            when /^\d+\.\d+$/: value.to_f 
316:            when /^\d+$/: value.to_i
317:            else value
318:          end           
319:          
320:          stats[key.to_sym] += [value]
321:        end
322:     end
323:     
324:     Lib.memcached_stat_free(@struct, stat_struct)
325:     stats
326:   end

Private Instance Methods


check_return_code (ret)

Checks the return code from Rlibmemcached against the exception list. Raises the corresponding exception if the return code is not Memcached::Success or Memcached::ActionQueued. Accepts an integer return code.

     # File lib/memcached/memcached.rb, line 333
333:   def check_return_code(ret) #:doc:
334:     # 0.16 --enable-debug returns 0 for an ActionQueued result but --disable-debug does not
335:     return if ret == 0 or ret == 31
336: 
337:     # SystemError; eject from the pool
338:     if ret == 25 and options[:failover]
339:       failed = sweep_servers
340:       raise EXCEPTIONS[ret], "Server #{failed} failed permanently"
341:     else
342:       raise EXCEPTIONS[ret], ""      
343:     end
344:   end

set_behavior (behavior, value)

Set a behavior option for this Memcached instance. Accepts a Symbol behavior and either true, false, or a Symbol for value. Arguments are validated and converted into integers for the struct setter method.

    # File lib/memcached/behaviors.rb, line 33
33:   def set_behavior(behavior, value) #:doc:
34:     raise ArgumentError, "No behavior #{behavior.inspect}" unless b_id = BEHAVIORS[behavior]    
35:     
36:     # Scoped validations; annoying
37:     msg =  "Invalid behavior value #{value.inspect} for #{behavior.inspect}" 
38:     case behavior 
39:       when :hash then raise(ArgumentError, msg) unless HASH_VALUES[value]
40:       when :distribution then raise(ArgumentError, msg) unless DISTRIBUTION_VALUES[value]
41:       when *DIRECT_VALUE_BEHAVIORS then raise(ArgumentError, msg) unless value.is_a? Fixnum and value > 0
42:       else
43:         raise(ArgumentError, msg) unless BEHAVIOR_VALUES[value]
44:     end
45:     
46:     lib_value = BEHAVIOR_VALUES[value] || value    
47:     #STDERR.puts "Setting #{behavior}:#{b_id} => #{value} (#{lib_value})"
48:     Lib.memcached_behavior_set(@struct, b_id, lib_value)    
49:     #STDERR.puts " -> set to #{get_behavior(behavior).inspect}"
50:   end