Class: Memcached
- Inherits:
-
Object
- Object
- Memcached
- Defined in:
- lib/memcached/memcached.rb,
lib/memcached.rb,
lib/memcached/auth.rb,
lib/memcached/rails.rb,
lib/memcached/behaviors.rb,
lib/memcached/exceptions.rb
Overview
The Memcached client class.
Direct Known Subclasses
Defined Under Namespace
Constant Summary collapse
- Lib =
Rlibmemcached
- VERSION =
File.read("#{File.dirname(__FILE__)}/../CHANGELOG")[/v([\d\.]+)\./, 1]
- BEHAVIORS =
load_constants("MEMCACHED_BEHAVIOR_")
- BEHAVIOR_VALUES =
{ false => 0, true => 1 }
- HASH_VALUES =
{}
- DISTRIBUTION_VALUES =
{}
- DIRECT_VALUE_BEHAVIORS =
[:retry_timeout, :connect_timeout, :rcv_timeout, :socket_recv_size, :poll_timeout, :socket_send_size, :server_failure_limit]
- CONVERSION_FACTORS =
{ :rcv_timeout => 1_000_000, :poll_timeout => 1_000, :connect_timeout => 1_000 }
- FLAGS =
0x0
- DEFAULTS =
{ :hash => :fnv1_32, :no_block => false, :distribution => :consistent_ketama, :ketama_weighted => true, :buffer_requests => false, :cache_lookups => true, :support_cas => false, :tcp_nodelay => false, :show_backtraces => false, :retry_timeout => 30, :timeout => 0.25, :rcv_timeout => nil, :poll_timeout => nil, :connect_timeout => 2, :prefix_key => nil, :hash_with_prefix_key => true, :default_ttl => 604800, :default_weight => 8, :sort_hosts => false, :auto_eject_hosts => true, :server_failure_limit => 2, :verify_key => true, :use_udp => false, :binary_protocol => false, :credentials => nil }
- IGNORED =
:stopdoc:
0
- ERRNO_HASH =
- EXCEPTIONS =
[]
- EMPTY_STRUCT =
Rlibmemcached::MemcachedSt.new
- @@structs =
Track structs so we can free them
{}
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
:startdoc:.
Class Method Summary collapse
Instance Method Summary collapse
-
#add(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Add a key/value pair.
-
#append(key, value) ⇒ Object
Appends a string to a key’s value.
-
#cas(key, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
(also: #compare_and_swap)
Reads a key’s value from the server and yields it to a block.
-
#clone ⇒ Object
(also: #dup)
Safely copy this instance.
-
#decrement(key, offset = 1) ⇒ Object
(also: #decr)
Decrement a key’s value.
-
#delete(key) ⇒ Object
Deletes a key/value pair from the server.
- #destroy_credentials ⇒ Object
-
#flush ⇒ Object
Flushes all key/value pairs from all the servers.
-
#get(keys, marshal = true) ⇒ Object
Gets a key’s value from the server.
-
#increment(key, offset = 1) ⇒ Object
(also: #incr)
Increment a key’s value.
-
#initialize(servers = nil, opts = {}) ⇒ Memcached
constructor
A new instance of Memcached.
-
#prepend(key, value) ⇒ Object
Prepends a string to a key’s value.
-
#quit ⇒ Object
Disconnect from all currently connected servers.
-
#replace(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Replace a key/value pair.
-
#reset(current_servers = nil) ⇒ Object
Reset the state of the libmemcached struct.
-
#server_by_key(key) ⇒ Object
Return the server used by a particular key.
-
#servers ⇒ Object
Return the array of server strings used to configure this instance.
-
#set(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Set a key/value pair.
- #set_credentials ⇒ Object
-
#set_servers(servers) ⇒ Object
Set the server list.
-
#stats(subcommand = nil) ⇒ Object
Return a Hash of statistics responses from the set of servers.
Constructor Details
#initialize(servers = nil, opts = {}) ⇒ Memcached
Returns a new instance of Memcached.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/memcached/memcached.rb', line 85 def initialize(servers = nil, opts = {}) @struct = Lib::MemcachedSt.new Lib.memcached_create(@struct) @@structs[object_id] = @struct # Merge option defaults and discard meaningless keys @options = DEFAULTS.merge(opts) @options.delete_if { |k,v| not DEFAULTS.keys.include? k } @default_ttl = [:default_ttl] if servers == nil || servers == [] if ENV.key?("MEMCACHE_SERVERS") servers = ENV["MEMCACHE_SERVERS"].split(",").map do | s | s.strip end else servers = "127.0.0.1:11211" end end if [:credentials] == nil && ENV.key?("MEMCACHE_USERNAME") && ENV.key?("MEMCACHE_PASSWORD") [:credentials] = [ENV["MEMCACHE_USERNAME"], ENV["MEMCACHE_PASSWORD"]] end [:binary_protocol] = true if [:credentials] != nil # Force :buffer_requests to use :no_block # XXX Deleting the :no_block key should also work, but libmemcached doesn't seem to set it # consistently [:no_block] = true if [:buffer_requests] # Disallow weights without ketama .delete(:ketama_weighted) if [:distribution] != :consistent_ketama # Legacy accessor [:prefix_key] = .delete(:namespace) if [:namespace] # Disallow :sort_hosts with consistent hashing if [:sort_hosts] and [:distribution] == :consistent raise ArgumentError, ":sort_hosts defeats :consistent hashing" end # Read timeouts [:rcv_timeout] ||= [:timeout] || 0 [:poll_timeout] ||= [:timeout] || 0 # Set the behaviors on the struct set_behaviors set_callbacks set_credentials # Freeze the hash .freeze # Set the servers on the struct set_servers(servers) # Not found exceptions unless [:show_backtraces] @not_found = NotFound.new @not_found.no_backtrace = true @not_stored = NotStored.new @not_stored.no_backtrace = true end ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc) end |
Instance Attribute Details
#options ⇒ Object (readonly)
:startdoc:
41 42 43 |
# File 'lib/memcached/memcached.rb', line 41 def @options end |
Class Method Details
.finalize(id) ⇒ Object
152 153 154 155 156 157 158 159 |
# File 'lib/memcached/memcached.rb', line 152 def Memcached.finalize(id) # Don't leak clients! struct = @@structs[id] @@structs.delete(id) # Don't leak authentication data either. This will silently fail if it's not set. Lib.memcached_destroy_sasl_auth_data(struct) Lib.memcached_free(struct) end |
.load_constants(prefix, hash = {}) ⇒ Object
:stopdoc:
6 7 8 9 10 11 |
# File 'lib/memcached/behaviors.rb', line 6 def self.load_constants(prefix, hash = {}) Lib.constants.grep(/^#{prefix}/).each do |const_name| hash[const_name[prefix.length..-1].downcase.to_sym] = Lib.const_get(const_name) end hash end |
Instance Method Details
#add(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Add a key/value pair. Raises Memcached::NotStored if the key already exists on the server. The parameters are the same as set
.
270 271 272 273 274 275 276 |
# File 'lib/memcached/memcached.rb', line 270 def add(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS) value = marshal ? Marshal.dump(value) : value.to_s check_return_code( Lib.memcached_add(@struct, key, value, ttl, flags), key ) end |
#append(key, value) ⇒ Object
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
.
313 314 315 316 317 318 319 |
# File 'lib/memcached/memcached.rb', line 313 def append(key, value) # Requires memcached 1.2.4 check_return_code( Lib.memcached_append(@struct, key, value.to_s, IGNORED, IGNORED), key ) end |
#cas(key, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object Also known as: compare_and_swap
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 ttl
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.
336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/memcached/memcached.rb', line 336 def cas(key, ttl=@default_ttl, marshal=true, flags=FLAGS) raise ClientError, "CAS not enabled for this Memcached instance" unless [:support_cas] value, flags, ret = Lib.memcached_get_rvalue(@struct, key) check_return_code(ret, key) cas = @struct.result.cas value = Marshal.load(value) if marshal value = yield value value = Marshal.dump(value) if marshal check_return_code(Lib.memcached_cas(@struct, key, value, ttl, flags, cas), key) end |
#clone ⇒ Object Also known as: dup
Safely copy this instance. Returns a Memcached instance.
clone
is useful for threading, since each thread must have its own unshared Memcached object.
198 199 200 201 202 203 204 205 |
# File 'lib/memcached/memcached.rb', line 198 def clone # FIXME Memory leak # memcached = super # struct = Lib.memcached_clone(nil, @struct) # memcached.instance_variable_set('@struct', struct) # memcached self.class.new(servers, ) end |
#decrement(key, offset = 1) ⇒ Object Also known as: decr
Decrement a key’s value. The parameters and exception behavior are the same as increment
.
290 291 292 293 294 |
# File 'lib/memcached/memcached.rb', line 290 def decrement(key, offset=1) ret, value = Lib.memcached_decrement(@struct, key, offset) check_return_code(ret, key) value end |
#delete(key) ⇒ Object
Deletes a key/value pair from the server. Accepts a String key
. Raises Memcached::NotFound if the key does not exist.
355 356 357 358 359 360 |
# File 'lib/memcached/memcached.rb', line 355 def delete(key) check_return_code( Lib.memcached_delete(@struct, key, IGNORED), key ) end |
#destroy_credentials ⇒ Object
2 3 4 5 6 |
# File 'lib/memcached/auth.rb', line 2 def destroy_credentials if [:credentials] != nil check_return_code(Lib.memcached_destroy_sasl_auth_data(@struct)) end end |
#flush ⇒ Object
Flushes all key/value pairs from all the servers.
363 364 365 366 367 |
# File 'lib/memcached/memcached.rb', line 363 def flush check_return_code( Lib.memcached_flush(@struct, IGNORED) ) end |
#get(keys, marshal = true) ⇒ Object
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.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/memcached/memcached.rb', line 381 def get(keys, marshal=true) if keys.is_a? Array # Multi get ret = Lib.memcached_mget(@struct, keys); check_return_code(ret, keys) hash = {} keys.each do value, key, flags, ret = Lib.memcached_fetch_rvalue(@struct) break if ret == Lib::MEMCACHED_END check_return_code(ret, key) # Assign the value hash[key] = (marshal ? Marshal.load(value) : value) end hash else # Single get value, flags, ret = Lib.memcached_get_rvalue(@struct, keys) check_return_code(ret, keys) marshal ? Marshal.load(value) : value end end |
#increment(key, offset = 1) ⇒ Object Also known as: incr
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
.
283 284 285 286 287 |
# File 'lib/memcached/memcached.rb', line 283 def increment(key, offset=1) ret, value = Lib.memcached_increment(@struct, key, offset) check_return_code(ret, key) value end |
#prepend(key, value) ⇒ Object
Prepends a string to a key’s value. The parameters and exception behavior are the same as append
.
322 323 324 325 326 327 328 |
# File 'lib/memcached/memcached.rb', line 322 def prepend(key, value) # Requires memcached 1.2.4 check_return_code( Lib.memcached_prepend(@struct, key, value.to_s, IGNORED, IGNORED), key ) end |
#quit ⇒ Object
Disconnect from all currently connected servers
221 222 223 224 |
# File 'lib/memcached/memcached.rb', line 221 def quit Lib.memcached_quit(@struct) self end |
#replace(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Replace a key/value pair. Raises Memcached::NotFound if the key does not exist on the server. The parameters are the same as set
.
302 303 304 305 306 307 308 |
# File 'lib/memcached/memcached.rb', line 302 def replace(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS) value = marshal ? Marshal.dump(value) : value.to_s check_return_code( Lib.memcached_replace(@struct, key, value, ttl, flags), key ) end |
#reset(current_servers = nil) ⇒ Object
Reset the state of the libmemcached struct. This is useful for changing the server list at runtime.
208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/memcached/memcached.rb', line 208 def reset(current_servers = nil) current_servers ||= servers destroy_credentials Lib.memcached_free(@struct) @struct = Lib::MemcachedSt.new Lib.memcached_create(@struct) set_behaviors set_callbacks set_credentials set_servers(current_servers) end |
#server_by_key(key) ⇒ Object
Return the server used by a particular key.
407 408 409 410 411 412 413 414 |
# File 'lib/memcached/memcached.rb', line 407 def server_by_key(key) ret = Lib.memcached_server_by_key(@struct, key) if ret.is_a?(Array) string = inspect_server(ret.first) Rlibmemcached.memcached_server_free(ret.first) string end end |
#servers ⇒ Object
Return the array of server strings used to configure this instance.
187 188 189 190 191 |
# File 'lib/memcached/memcached.rb', line 187 def servers server_structs.map do |server| inspect_server(server) end end |
#set(key, value, ttl = @default_ttl, marshal = true, flags = FLAGS) ⇒ Object
Set a key/value pair. Accepts a String key
and an arbitrary Ruby object. Overwrites any existing value on the server.
Accepts an optional ttl
value to specify the maximum lifetime of the key on the server. ttl
can be either an integer number of seconds, or a Time elapsed time object. 0
means no ttl. Note that there is no guarantee that the key will persist as long as the ttl
, 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.
257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/memcached/memcached.rb', line 257 def set(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS) value = marshal ? Marshal.dump(value) : value.to_s check_return_code( Lib.memcached_set(@struct, key, value, ttl, flags), key ) rescue ClientError # FIXME Memcached 1.2.8 occasionally rejects valid sets tried = 1 and retry unless defined?(tried) raise end |
#set_credentials ⇒ Object
8 9 10 11 12 13 14 |
# File 'lib/memcached/auth.rb', line 8 def set_credentials # If credentials aren't provided, try to get them from the environment if [:credentials] != nil username, password = [:credentials] check_return_code(Lib.memcached_set_sasl_auth_data(@struct, username, password)) end end |
#set_servers(servers) ⇒ Object
Set the server list. FIXME Does not necessarily free any existing server structs.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/memcached/memcached.rb', line 163 def set_servers(servers) Array(servers).each_with_index do |server, index| # Socket if server.is_a?(String) and File.socket?(server) args = [@struct, server, [:default_weight].to_i] check_return_code(Lib.memcached_server_add_unix_socket_with_weight(*args)) # Network elsif server.is_a?(String) and server =~ /^[\w\d\.-]+(:\d{1,5}){0,2}$/ host, port, weight = server.split(":") args = [@struct, host, port.to_i, (weight || [:default_weight]).to_i] if [:use_udp] # check_return_code(Lib.memcached_server_add_udp_with_weight(*args)) else check_return_code(Lib.memcached_server_add_with_weight(*args)) end else raise ArgumentError, "Servers must be either in the format 'host:port[:weight]' (e.g., 'localhost:11211' or 'localhost:11211:10') for a network server, or a valid path to a Unix domain socket (e.g., /var/run/memcached)." end end # For inspect @servers = send(:servers) end |
#stats(subcommand = nil) ⇒ Object
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.
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/memcached/memcached.rb', line 417 def stats(subcommand=nil) stats = Hash.new([]) stat_struct, ret = Lib.memcached_stat(@struct, subcommand) check_return_code(ret) keys, ret = Lib.memcached_stat_get_keys(@struct, stat_struct) check_return_code(ret) keys.each do |key| server_structs.size.times do |index| value, ret = Lib.memcached_stat_get_rvalue( @struct, Lib.memcached_select_stat_at(@struct, stat_struct, index), key) check_return_code(ret, key) value = case value when /^\d+\.\d+$/ then value.to_f when /^\d+$/ then value.to_i else value end stats[key.to_sym] += [value] end end Lib.memcached_stat_free(@struct, stat_struct) stats rescue Memcached::SomeErrorsWereReported => _ e = _.class.new("Error getting stats") e.set_backtrace(_.backtrace) raise e end |