memcached 0.14 → 0.15
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/BENCHMARKS +83 -64
- data/CHANGELOG +9 -1
- data/COMPATIBILITY +2 -1
- data/Manifest +2 -0
- data/README +4 -11
- data/Rakefile +1 -0
- data/ext/extconf.rb +40 -17
- data/ext/libmemcached-0.31.tar.gz +0 -0
- data/ext/rlibmemcached.i +29 -10
- data/ext/rlibmemcached_wrap.c +3167 -1659
- data/lib/memcached/behaviors.rb +2 -2
- data/lib/memcached/exceptions.rb +4 -4
- data/lib/memcached/memcached.rb +61 -37
- data/lib/memcached/rails.rb +13 -5
- data/memcached.gemspec +5 -9
- data/test/profile/benchmark.rb +198 -49
- data/test/profile/profile.rb +3 -8
- data/test/profile/valgrind.rb +5 -12
- data/test/setup.rb +21 -16
- data/test/test_helper.rb +5 -1
- data/test/unit/memcached_test.rb +98 -30
- data/test/unit/rails_test.rb +32 -2
- metadata +10 -16
- metadata.gz.sig +0 -0
data/lib/memcached/behaviors.rb
CHANGED
@@ -26,9 +26,9 @@ class Memcached
|
|
26
26
|
DIRECT_VALUE_BEHAVIORS = [:retry_timeout, :connect_timeout, :rcv_timeout, :socket_recv_size, :poll_timeout, :socket_send_size, :server_failure_limit]
|
27
27
|
|
28
28
|
CONVERSION_FACTORS = {
|
29
|
-
:connect_timeout => 1_000_000,
|
30
29
|
:rcv_timeout => 1_000_000,
|
31
|
-
:poll_timeout => 1_000
|
30
|
+
:poll_timeout => 1_000,
|
31
|
+
:connect_timeout => 1_000
|
32
32
|
}
|
33
33
|
|
34
34
|
#:startdoc:
|
data/lib/memcached/exceptions.rb
CHANGED
@@ -34,6 +34,7 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
|
|
34
34
|
* Memcached::ServerDelete
|
35
35
|
* Memcached::ServerEnd
|
36
36
|
* Memcached::ServerError
|
37
|
+
* Memcached::ServerIsMarkedDead
|
37
38
|
* Memcached::ServerValue
|
38
39
|
* Memcached::SomeErrorsWereReported
|
39
40
|
* Memcached::StatValue
|
@@ -54,13 +55,15 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
ERRNO_HASH = Hash[*Errno.constants.map{ |c| [Errno.const_get(c)::Errno, Errno.const_get(c).new.message] }.flatten]
|
59
|
+
|
57
60
|
EXCEPTIONS = []
|
58
61
|
EMPTY_STRUCT = Rlibmemcached::MemcachedSt.new
|
59
62
|
Rlibmemcached.memcached_create(EMPTY_STRUCT)
|
60
63
|
|
61
64
|
# Generate exception classes
|
62
65
|
Rlibmemcached::MEMCACHED_MAXIMUM_RETURN.times do |index|
|
63
|
-
description = Rlibmemcached.memcached_strerror(EMPTY_STRUCT, index)
|
66
|
+
description = Rlibmemcached.memcached_strerror(EMPTY_STRUCT, index).gsub("!", "")
|
64
67
|
exception_class = eval("class #{camelize(description)} < Error; self; end")
|
65
68
|
EXCEPTIONS << exception_class
|
66
69
|
end
|
@@ -77,8 +80,5 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
|
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
|
-
# Verify library version
|
81
|
-
# XXX Waiting on libmemcached 0.18
|
82
|
-
|
83
83
|
#:startdoc:
|
84
84
|
end
|
data/lib/memcached/memcached.rb
CHANGED
@@ -7,7 +7,7 @@ class Memcached
|
|
7
7
|
FLAGS = 0x0
|
8
8
|
|
9
9
|
DEFAULTS = {
|
10
|
-
:hash => :
|
10
|
+
:hash => :fnv1_32,
|
11
11
|
:no_block => false,
|
12
12
|
:distribution => :consistent_ketama,
|
13
13
|
:ketama_weighted => true,
|
@@ -26,9 +26,10 @@ class Memcached
|
|
26
26
|
:default_ttl => 604800,
|
27
27
|
:default_weight => 8,
|
28
28
|
:sort_hosts => false,
|
29
|
-
:auto_eject_hosts =>
|
29
|
+
:auto_eject_hosts => true,
|
30
30
|
:server_failure_limit => 2,
|
31
|
-
:verify_key => true
|
31
|
+
:verify_key => true,
|
32
|
+
:use_udp => false
|
32
33
|
}
|
33
34
|
|
34
35
|
#:stopdoc:
|
@@ -51,11 +52,11 @@ Weights only affect Ketama hashing. If you use Ketama hashing and don't specify
|
|
51
52
|
Valid option parameters are:
|
52
53
|
|
53
54
|
<tt>:prefix_key</tt>:: A string to prepend to every key, for namespacing. Max length is 127.
|
54
|
-
<tt>:hash</tt>:: The name of a hash function to use. Possible values are: <tt>:crc</tt>, <tt>:default</tt>, <tt>:fnv1_32</tt>, <tt>:fnv1_64</tt>, <tt>:fnv1a_32</tt>, <tt>:fnv1a_64</tt>, <tt>:hsieh</tt>, <tt>:md5</tt>, and <tt>:murmur</tt>. <tt>:
|
55
|
+
<tt>:hash</tt>:: The name of a hash function to use. Possible values are: <tt>:crc</tt>, <tt>:default</tt>, <tt>:fnv1_32</tt>, <tt>:fnv1_64</tt>, <tt>:fnv1a_32</tt>, <tt>:fnv1a_64</tt>, <tt>:hsieh</tt>, <tt>:md5</tt>, and <tt>:murmur</tt>. <tt>:fnv1_32</tt> is fast and well known, and is the default. Use <tt>:md5</tt> for compatibility with other ketama clients.
|
55
56
|
<tt>:distribution</tt>:: Either <tt>:modula</tt>, <tt>:consistent_ketama</tt>, <tt>:consistent_wheel</tt>, or <tt>:ketama</tt>. Defaults to <tt>:ketama</tt>.
|
56
57
|
<tt>:server_failure_limit</tt>:: How many consecutive failures to allow before marking a host as dead. Has no effect unless <tt>:retry_timeout</tt> is also set.
|
57
58
|
<tt>:retry_timeout</tt>:: How long to wait until retrying a dead server. Has no effect unless <tt>:server_failure_limit</tt> is non-zero. Defaults to <tt>30</tt>.
|
58
|
-
<tt>:auto_eject_hosts</tt>:: Whether to temporarily eject dead hosts from the pool. Defaults to <tt>
|
59
|
+
<tt>:auto_eject_hosts</tt>:: Whether to temporarily eject dead hosts from the pool. Defaults to <tt>true</tt>. Note that in the event of an ejection, <tt>:auto_eject_hosts</tt> will remap the entire pool unless <tt>:distribution</tt> is set to <tt>:consistent</tt>.
|
59
60
|
<tt>:cache_lookups</tt>:: Whether to cache hostname lookups for the life of the instance. Defaults to <tt>true</tt>.
|
60
61
|
<tt>:support_cas</tt>:: Flag CAS support in the client. Accepts <tt>true</tt> or <tt>false</tt>. Defaults to <tt>false</tt> because it imposes a slight performance penalty. Note that your server must also support CAS or you will trigger <b>Memcached::ProtocolError</b> exceptions.
|
61
62
|
<tt>:tcp_nodelay</tt>:: Turns on the no-delay feature for connecting sockets. Accepts <tt>true</tt> or <tt>false</tt>. Performance may or may not change, depending on your system.
|
@@ -64,10 +65,10 @@ Valid option parameters are:
|
|
64
65
|
<tt>:show_backtraces</tt>:: Whether <b>Memcached::NotFound</b> exceptions should include backtraces. Generating backtraces is slow, so this is off by default. Turn it on to ease debugging.
|
65
66
|
<tt>:connect_timeout</tt>:: How long to wait for a connection to a server. Defaults to 2 seconds. Set to <tt>0</tt> if you want to wait forever.
|
66
67
|
<tt>:timeout</tt>:: How long to wait for a response from the server. Defaults to 0.25 seconds. Set to <tt>0</tt> if you want to wait forever.
|
67
|
-
<tt>:poll_timeout</tt>:: How long to wait for a response from the server in the non-blocking select loop. Defaults to 0.25 seconds. Set to <tt>0</tt> if you want to wait forever.
|
68
68
|
<tt>:default_ttl</tt>:: The <tt>ttl</tt> to use on set if no <tt>ttl</tt> is specified, in seconds. Defaults to one week. Set to <tt>0</tt> if you want things to never expire.
|
69
69
|
<tt>:default_weight</tt>:: The weight to use if <tt>:ketama_weighted</tt> is <tt>true</tt>, but no weight is specified for a server.
|
70
70
|
<tt>:hash_with_prefix_key</tt>:: Whether to include the prefix when calculating which server a key falls on. Defaults to <tt>true</tt>.
|
71
|
+
<tt>:use_udp</tt>:: Use the UDP protocol to reduce connection overhead. Defaults to false.
|
71
72
|
<tt>:sort_hosts</tt>:: Whether to force the server list to stay sorted. This defeats consistent hashing and is rarely useful.
|
72
73
|
<tt>:verify_key</tt>:: Validate keys before accepting them. Never disable this.
|
73
74
|
|
@@ -80,9 +81,9 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
80
81
|
Lib.memcached_create(@struct)
|
81
82
|
|
82
83
|
# Merge option defaults and discard meaningless keys
|
83
|
-
@options =
|
84
|
-
|
85
|
-
|
84
|
+
@options = DEFAULTS.merge(opts)
|
85
|
+
@options.delete_if { |k,v| not DEFAULTS.keys.include? k }
|
86
|
+
@default_ttl = options[:default_ttl]
|
86
87
|
|
87
88
|
# Force :buffer_requests to use :no_block
|
88
89
|
# XXX Deleting the :no_block key should also work, but libmemcached doesn't seem to set it
|
@@ -186,19 +187,19 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
186
187
|
#
|
187
188
|
# Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be set directly.
|
188
189
|
#
|
189
|
-
def set(key, value, ttl
|
190
|
+
def set(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
|
190
191
|
value = marshal ? Marshal.dump(value) : value.to_s
|
191
192
|
check_return_code(
|
192
|
-
Lib.memcached_set(@struct, key, value, ttl
|
193
|
+
Lib.memcached_set(@struct, key, value, ttl, flags),
|
193
194
|
key
|
194
195
|
)
|
195
196
|
end
|
196
197
|
|
197
198
|
# Add a key/value pair. Raises <b>Memcached::NotStored</b> if the key already exists on the server. The parameters are the same as <tt>set</tt>.
|
198
|
-
def add(key, value, ttl
|
199
|
+
def add(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
|
199
200
|
value = marshal ? Marshal.dump(value) : value.to_s
|
200
201
|
check_return_code(
|
201
|
-
Lib.memcached_add(@struct, key, value, ttl
|
202
|
+
Lib.memcached_add(@struct, key, value, ttl, flags),
|
202
203
|
key
|
203
204
|
)
|
204
205
|
end
|
@@ -227,10 +228,10 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
227
228
|
#:startdoc:
|
228
229
|
|
229
230
|
# Replace a key/value pair. Raises <b>Memcached::NotFound</b> if the key does not exist on the server. The parameters are the same as <tt>set</tt>.
|
230
|
-
def replace(key, value, ttl
|
231
|
+
def replace(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
|
231
232
|
value = marshal ? Marshal.dump(value) : value.to_s
|
232
233
|
check_return_code(
|
233
|
-
Lib.memcached_replace(@struct, key, value, ttl
|
234
|
+
Lib.memcached_replace(@struct, key, value, ttl, flags),
|
234
235
|
key
|
235
236
|
)
|
236
237
|
end
|
@@ -261,19 +262,22 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
261
262
|
#
|
262
263
|
# CAS stands for "compare and swap", and avoids the need for manual key mutexing. CAS support must be enabled in Memcached.new or a <b>Memcached::ClientError</b> will be raised. Note that CAS may be buggy in memcached itself.
|
263
264
|
#
|
264
|
-
def cas(key, ttl
|
265
|
+
def cas(key, ttl=@default_ttl, marshal=true, flags=FLAGS)
|
265
266
|
raise ClientError, "CAS not enabled for this Memcached instance" unless options[:support_cas]
|
266
267
|
|
267
|
-
value =
|
268
|
+
value, flags, ret = Lib.memcached_get_rvalue(@struct, key)
|
269
|
+
check_return_code(ret, key)
|
270
|
+
cas = @struct.result.cas
|
271
|
+
|
272
|
+
value = Marshal.load(value) if marshal
|
268
273
|
value = yield value
|
269
|
-
value =
|
274
|
+
value = Marshal.dump(value) if marshal
|
270
275
|
|
271
|
-
check_return_code(
|
272
|
-
Lib.memcached_cas(@struct, key, value, ttl || options[:default_ttl], flags, @struct.result.cas),
|
273
|
-
key
|
274
|
-
)
|
276
|
+
check_return_code(Lib.memcached_cas(@struct, key, value, ttl, flags, cas), key)
|
275
277
|
end
|
276
278
|
|
279
|
+
alias :compare_and_swap :cas
|
280
|
+
|
277
281
|
### Deleters
|
278
282
|
|
279
283
|
# Deletes a key/value pair from the server. Accepts a String <tt>key</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist.
|
@@ -332,7 +336,7 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
332
336
|
|
333
337
|
# Return the server used by a particular key.
|
334
338
|
def server_by_key(key)
|
335
|
-
ret = Lib.memcached_server_by_key(@struct, key)
|
339
|
+
ret = Lib.memcached_server_by_key(@struct, key)
|
336
340
|
inspect_server(ret.first) if ret.is_a?(Array)
|
337
341
|
end
|
338
342
|
|
@@ -375,16 +379,21 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
375
379
|
|
376
380
|
# 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 and an optional key, for exception messages.
|
377
381
|
def check_return_code(ret, key = nil) #:doc:
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
if ret == Lib::MEMCACHED_NOTFOUND and !options[:show_backtraces]
|
382
|
+
if ret == 0 # Lib::MEMCACHED_SUCCESS
|
383
|
+
elsif ret == Lib::MEMCACHED_BUFFERED
|
384
|
+
elsif ret == Lib::MEMCACHED_NOTFOUND and !options[:show_backtraces]
|
382
385
|
raise @not_found_instance
|
383
386
|
else
|
384
387
|
message = "Key #{inspect_keys(key, (detect_failure if ret == Lib::MEMCACHED_SERVER_MARKED_DEAD)).inspect}"
|
385
|
-
if
|
386
|
-
|
387
|
-
|
388
|
+
if key.is_a?(String)
|
389
|
+
if ret == Lib::MEMCACHED_ERRNO
|
390
|
+
server = Lib.memcached_server_by_key(@struct, key)
|
391
|
+
errno = server.first.cached_errno
|
392
|
+
message = "Errno #{errno}: #{ERRNO_HASH[errno].inspect}. #{message}"
|
393
|
+
elsif ret == Lib::MEMCACHED_SERVER_ERROR
|
394
|
+
server = Lib.memcached_server_by_key(@struct, key)
|
395
|
+
message = "\"#{server.first.cached_server_error}\". #{message}."
|
396
|
+
end
|
388
397
|
end
|
389
398
|
raise EXCEPTIONS[ret], message
|
390
399
|
end
|
@@ -398,6 +407,7 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
398
407
|
end
|
399
408
|
|
400
409
|
# Find which server failed most recently.
|
410
|
+
# FIXME Is this still necessary with cached_errno?
|
401
411
|
def detect_failure
|
402
412
|
time = Time.now
|
403
413
|
server = server_structs.detect do |server|
|
@@ -408,12 +418,16 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
408
418
|
|
409
419
|
# Set the servers on the struct.
|
410
420
|
def set_servers(servers)
|
421
|
+
add_method = options[:use_udp] ? "memcached_server_add_udp_with_weight" : "memcached_server_add_with_weight"
|
411
422
|
Array(servers).each_with_index do |server, index|
|
412
|
-
|
413
|
-
|
423
|
+
if server.is_a?(String) and File.socket?(server)
|
424
|
+
Lib.memcached_server_add_unix_socket_with_weight(@struct, server, options[:default_weight].to_i)
|
425
|
+
elsif server.is_a?(String) and server =~ /^[\w\d\.-]+(:\d{1,5}){0,2}$/
|
426
|
+
host, port, weight = server.split(":")
|
427
|
+
Lib.memcached_server_add_with_weight(@struct, host, port.to_i, (weight || options[:default_weight]).to_i)
|
428
|
+
else
|
429
|
+
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)."
|
414
430
|
end
|
415
|
-
host, port, weight = server.split(":")
|
416
|
-
Lib.memcached_server_add_with_weight(@struct, host, port.to_i, (weight || options[:default_weight]).to_i)
|
417
431
|
end
|
418
432
|
# For inspect
|
419
433
|
@servers = send(:servers)
|
@@ -424,6 +438,8 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
424
438
|
BEHAVIORS.keys.each do |behavior|
|
425
439
|
set_behavior(behavior, options[behavior]) if options.key?(behavior)
|
426
440
|
end
|
441
|
+
# BUG Hash must be last due to the weird Libmemcached multi-behaviors
|
442
|
+
set_behavior(:hash, options[:hash])
|
427
443
|
end
|
428
444
|
|
429
445
|
# Set the callbacks on the struct from the current options.
|
@@ -437,9 +453,17 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
|
|
437
453
|
end
|
438
454
|
end
|
439
455
|
|
440
|
-
|
441
|
-
|
442
|
-
"#{server.hostname}:#{server.port}#{":#{server.weight}" if options[:ketama_weighted]}"
|
456
|
+
def is_unix_socket?(server)
|
457
|
+
server.type == Lib::MEMCACHED_CONNECTION_UNIX_SOCKET
|
443
458
|
end
|
444
459
|
|
460
|
+
# Stringify an opaque server struct
|
461
|
+
def inspect_server(server)
|
462
|
+
strings = [server.hostname]
|
463
|
+
if !is_unix_socket?(server)
|
464
|
+
strings << ":#{server.port}"
|
465
|
+
strings << ":#{server.weight}" if options[:ketama_weighted]
|
466
|
+
end
|
467
|
+
strings.join
|
468
|
+
end
|
445
469
|
end
|
data/lib/memcached/rails.rb
CHANGED
@@ -25,19 +25,27 @@ class Memcached
|
|
25
25
|
super(key, !raw)
|
26
26
|
rescue NotFound
|
27
27
|
end
|
28
|
+
|
29
|
+
# Wraps Memcached#cas so that it doesn't raise. Doesn't set anything if no value is present.
|
30
|
+
def cas(key, ttl=@default_ttl, raw=false, &block)
|
31
|
+
super(key, ttl, !raw, &block)
|
32
|
+
rescue NotFound
|
33
|
+
end
|
34
|
+
|
35
|
+
alias :compare_and_swap :cas
|
28
36
|
|
29
|
-
# Wraps Memcached#get
|
30
|
-
def get_multi(
|
31
|
-
super(keys)
|
37
|
+
# Wraps Memcached#get.
|
38
|
+
def get_multi(keys, raw=false)
|
39
|
+
super(keys, !raw)
|
32
40
|
end
|
33
41
|
|
34
42
|
# Wraps Memcached#set.
|
35
|
-
def set(key, value, ttl
|
43
|
+
def set(key, value, ttl=@default_ttl, raw=false)
|
36
44
|
super(key, value, ttl, !raw)
|
37
45
|
end
|
38
46
|
|
39
47
|
# Wraps Memcached#add so that it doesn't raise.
|
40
|
-
def add(key, value, ttl
|
48
|
+
def add(key, value, ttl=@default_ttl, raw=false)
|
41
49
|
super(key, value, ttl, !raw)
|
42
50
|
true
|
43
51
|
rescue NotStored
|
data/memcached.gemspec
CHANGED
@@ -2,37 +2,33 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{memcached}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.15"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Evan Weaver"]
|
9
9
|
s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
|
10
|
-
s.date = %q{2009-
|
10
|
+
s.date = %q{2009-08-03}
|
11
11
|
s.description = %q{An interface to the libmemcached C client.}
|
12
12
|
s.email = %q{}
|
13
13
|
s.extensions = ["ext/extconf.rb"]
|
14
14
|
s.extra_rdoc_files = ["BENCHMARKS", "CHANGELOG", "COMPATIBILITY", "lib/memcached/behaviors.rb", "lib/memcached/exceptions.rb", "lib/memcached/memcached.rb", "lib/memcached/rails.rb", "lib/memcached.rb", "LICENSE", "README", "TODO"]
|
15
|
-
s.files = ["BENCHMARKS", "CHANGELOG", "COMPATIBILITY", "ext/extconf.rb", "ext/rlibmemcached.i", "ext/rlibmemcached_wrap.c", "lib/memcached/behaviors.rb", "lib/memcached/exceptions.rb", "lib/memcached/integer.rb", "lib/memcached/memcached.rb", "lib/memcached/rails.rb", "lib/memcached.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/profile/benchmark.rb", "test/profile/profile.rb", "test/profile/valgrind.rb", "test/setup.rb", "test/teardown.rb", "test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "test/unit/rails_test.rb", "TODO"
|
16
|
-
s.has_rdoc = true
|
15
|
+
s.files = ["BENCHMARKS", "CHANGELOG", "COMPATIBILITY", "ext/extconf.rb", "ext/libmemcached-0.31.tar.gz", "ext/rlibmemcached.i", "ext/rlibmemcached_wrap.c", "lib/memcached/behaviors.rb", "lib/memcached/exceptions.rb", "lib/memcached/integer.rb", "lib/memcached/memcached.rb", "lib/memcached/rails.rb", "lib/memcached.rb", "LICENSE", "Manifest", "memcached.gemspec", "Rakefile", "README", "test/profile/benchmark.rb", "test/profile/profile.rb", "test/profile/valgrind.rb", "test/setup.rb", "test/teardown.rb", "test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "test/unit/rails_test.rb", "TODO"]
|
17
16
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/memcached/}
|
18
17
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Memcached", "--main", "README"]
|
19
18
|
s.require_paths = ["lib", "ext"]
|
20
19
|
s.rubyforge_project = %q{fauna}
|
21
|
-
s.rubygems_version = %q{1.3.
|
20
|
+
s.rubygems_version = %q{1.3.4}
|
22
21
|
s.signing_key = %q{/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem}
|
23
22
|
s.summary = %q{An interface to the libmemcached C client.}
|
24
23
|
s.test_files = ["test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "test/unit/rails_test.rb"]
|
25
24
|
|
26
25
|
if s.respond_to? :specification_version then
|
27
26
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
28
|
-
s.specification_version =
|
27
|
+
s.specification_version = 3
|
29
28
|
|
30
29
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
31
|
-
s.add_development_dependency(%q<echoe>, [">= 0"])
|
32
30
|
else
|
33
|
-
s.add_dependency(%q<echoe>, [">= 0"])
|
34
31
|
end
|
35
32
|
else
|
36
|
-
s.add_dependency(%q<echoe>, [">= 0"])
|
37
33
|
end
|
38
34
|
end
|
data/test/profile/benchmark.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
|
2
2
|
HERE = File.dirname(__FILE__)
|
3
3
|
$LOAD_PATH << "#{HERE}/../../lib/"
|
4
|
+
UNIX_SOCKET_NAME = File.join(ENV['TMPDIR']||'/tmp','memcached')
|
4
5
|
|
5
6
|
require 'memcached'
|
6
7
|
|
@@ -39,7 +40,7 @@ class Bench
|
|
39
40
|
@value = []
|
40
41
|
@marshalled = Marshal.dump(@value)
|
41
42
|
|
42
|
-
@
|
43
|
+
@opts_networked = [
|
43
44
|
['127.0.0.1:43042', '127.0.0.1:43043'],
|
44
45
|
{
|
45
46
|
:buffer_requests => false,
|
@@ -47,6 +48,14 @@ class Bench
|
|
47
48
|
:namespace => "namespace"
|
48
49
|
}
|
49
50
|
]
|
51
|
+
@opt_unix = [
|
52
|
+
["#{UNIX_SOCKET_NAME}0","#{UNIX_SOCKET_NAME}1"],
|
53
|
+
{
|
54
|
+
:buffer_requests => false,
|
55
|
+
:no_block => false,
|
56
|
+
:namespace => "namespace"
|
57
|
+
}
|
58
|
+
]
|
50
59
|
@key1 = "Short"
|
51
60
|
@key2 = "Sym1-2-3::45"*8
|
52
61
|
@key3 = "Long"*40
|
@@ -78,16 +87,16 @@ class Bench
|
|
78
87
|
end
|
79
88
|
|
80
89
|
def benchmark
|
81
|
-
Benchmark.bm(
|
90
|
+
Benchmark.bm(35) do |x|
|
82
91
|
|
83
|
-
n =
|
92
|
+
n = (ENV["LOOPS"] || 10000).to_i
|
84
93
|
|
85
94
|
if defined? Memcached
|
86
95
|
@m = Memcached.new(
|
87
|
-
@
|
88
|
-
@
|
96
|
+
@opts_networked[0],
|
97
|
+
@opts_networked[1].merge(:no_block => true, :buffer_requests => true)
|
89
98
|
)
|
90
|
-
x.report("set:plain:noblock:memcached") do
|
99
|
+
x.report("set:plain:noblock:memcached:net") do
|
91
100
|
n.times do
|
92
101
|
@m.set @key1, @marshalled, 0, false
|
93
102
|
@m.set @key2, @marshalled, 0, false
|
@@ -97,8 +106,22 @@ class Bench
|
|
97
106
|
@m.set @key3, @marshalled, 0, false
|
98
107
|
end
|
99
108
|
end
|
100
|
-
@m = Memcached.new(
|
101
|
-
|
109
|
+
@m = Memcached.new(
|
110
|
+
@opt_unix[0],
|
111
|
+
@opt_unix[1].merge(:no_block => true, :buffer_requests => true)
|
112
|
+
)
|
113
|
+
x.report("set:plain:noblock:memcached:uds") do
|
114
|
+
n.times do
|
115
|
+
@m.set @key1, @marshalled, 0, false
|
116
|
+
@m.set @key2, @marshalled, 0, false
|
117
|
+
@m.set @key3, @marshalled, 0, false
|
118
|
+
@m.set @key1, @marshalled, 0, false
|
119
|
+
@m.set @key2, @marshalled, 0, false
|
120
|
+
@m.set @key3, @marshalled, 0, false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
@m = Memcached.new(*@opts_networked)
|
124
|
+
x.report("set:plain:memcached:net") do
|
102
125
|
n.times do
|
103
126
|
@m.set @key1, @marshalled, 0, false
|
104
127
|
@m.set @key2, @marshalled, 0, false
|
@@ -108,10 +131,21 @@ class Bench
|
|
108
131
|
@m.set @key3, @marshalled, 0, false
|
109
132
|
end
|
110
133
|
end # if false
|
134
|
+
@m = Memcached.new(*@opt_unix)
|
135
|
+
x.report("set:plain:memcached:uds") do
|
136
|
+
n.times do
|
137
|
+
@m.set @key1, @marshalled, 0, false
|
138
|
+
@m.set @key2, @marshalled, 0, false
|
139
|
+
@m.set @key3, @marshalled, 0, false
|
140
|
+
@m.set @key1, @marshalled, 0, false
|
141
|
+
@m.set @key2, @marshalled, 0, false
|
142
|
+
@m.set @key3, @marshalled, 0, false
|
143
|
+
end
|
144
|
+
end
|
111
145
|
end
|
112
146
|
# Not supported by Caffeine
|
113
147
|
if defined? MemCache
|
114
|
-
@m = MemCache.new(*@
|
148
|
+
@m = MemCache.new(*@opts_networked)
|
115
149
|
x.report("set:plain:memcache-client") do
|
116
150
|
n.times do
|
117
151
|
@m.set @key1, @marshalled, 0, true
|
@@ -129,10 +163,10 @@ class Bench
|
|
129
163
|
|
130
164
|
if defined? Memcached
|
131
165
|
@m = Memcached.new(
|
132
|
-
@
|
133
|
-
@
|
166
|
+
@opts_networked[0],
|
167
|
+
@opts_networked[1].merge(:no_block => true, :buffer_requests => true)
|
134
168
|
)
|
135
|
-
x.report("set:ruby:noblock:memcached") do
|
169
|
+
x.report("set:ruby:noblock:memcached:net") do
|
136
170
|
n.times do
|
137
171
|
@m.set @key1, @value
|
138
172
|
@m.set @key2, @value
|
@@ -142,8 +176,22 @@ class Bench
|
|
142
176
|
@m.set @key3, @value
|
143
177
|
end
|
144
178
|
end
|
145
|
-
@m = Memcached.new(
|
146
|
-
|
179
|
+
@m = Memcached.new(
|
180
|
+
@opt_unix[0],
|
181
|
+
@opt_unix[1].merge(:no_block => true, :buffer_requests => true)
|
182
|
+
)
|
183
|
+
x.report("set:ruby:noblock:memcached:uds") do
|
184
|
+
n.times do
|
185
|
+
@m.set @key1, @value
|
186
|
+
@m.set @key2, @value
|
187
|
+
@m.set @key3, @value
|
188
|
+
@m.set @key1, @value
|
189
|
+
@m.set @key2, @value
|
190
|
+
@m.set @key3, @value
|
191
|
+
end
|
192
|
+
end
|
193
|
+
@m = Memcached.new(*@opts_networked)
|
194
|
+
x.report("set:ruby:memcached:net") do
|
147
195
|
n.times do
|
148
196
|
@m.set @key1, @value
|
149
197
|
@m.set @key2, @value
|
@@ -153,9 +201,20 @@ class Bench
|
|
153
201
|
@m.set @key3, @value
|
154
202
|
end
|
155
203
|
end # if false
|
204
|
+
@m = Memcached.new(*@opt_unix)
|
205
|
+
x.report("set:ruby:memcached:uds") do
|
206
|
+
n.times do
|
207
|
+
@m.set @key1, @value
|
208
|
+
@m.set @key2, @value
|
209
|
+
@m.set @key3, @value
|
210
|
+
@m.set @key1, @value
|
211
|
+
@m.set @key2, @value
|
212
|
+
@m.set @key3, @value
|
213
|
+
end
|
214
|
+
end
|
156
215
|
end
|
157
216
|
if defined? Caffeine
|
158
|
-
@m = Caffeine::MemCache.new(@
|
217
|
+
@m = Caffeine::MemCache.new(@opts_networked[1]); @m.servers = @opts_networked[0]
|
159
218
|
x.report("set:ruby:caffeine") do
|
160
219
|
n.times do
|
161
220
|
@m.set @key1, @value
|
@@ -168,7 +227,7 @@ class Bench
|
|
168
227
|
end
|
169
228
|
end
|
170
229
|
if defined? MemCache
|
171
|
-
@m = MemCache.new(*@
|
230
|
+
@m = MemCache.new(*@opts_networked)
|
172
231
|
x.report("set:ruby:memcache-client") do
|
173
232
|
n.times do
|
174
233
|
@m.set @key1, @value
|
@@ -182,8 +241,19 @@ class Bench
|
|
182
241
|
end
|
183
242
|
|
184
243
|
if defined? Memcached
|
185
|
-
@m = Memcached.new(*@
|
186
|
-
x.report("get:plain:memcached") do
|
244
|
+
@m = Memcached.new(*@opts_networked)
|
245
|
+
x.report("get:plain:memcached:net") do
|
246
|
+
n.times do
|
247
|
+
@m.get @key1, false
|
248
|
+
@m.get @key2, false
|
249
|
+
@m.get @key3, false
|
250
|
+
@m.get @key1, false
|
251
|
+
@m.get @key2, false
|
252
|
+
@m.get @key3, false
|
253
|
+
end
|
254
|
+
end
|
255
|
+
@m = Memcached.new(*@opt_unix)
|
256
|
+
x.report("get:plain:memcached:uds") do
|
187
257
|
n.times do
|
188
258
|
@m.get @key1, false
|
189
259
|
@m.get @key2, false
|
@@ -196,7 +266,7 @@ class Bench
|
|
196
266
|
end
|
197
267
|
# Not supported by Caffeine
|
198
268
|
if defined? MemCache
|
199
|
-
@m = MemCache.new(*@
|
269
|
+
@m = MemCache.new(*@opts_networked)
|
200
270
|
x.report("get:plain:memcache-client") do
|
201
271
|
n.times do
|
202
272
|
@m.get @key1, true
|
@@ -210,8 +280,19 @@ class Bench
|
|
210
280
|
end
|
211
281
|
|
212
282
|
if defined? Memcached
|
213
|
-
@m = Memcached.new(*@
|
214
|
-
x.report("get:ruby:memcached") do
|
283
|
+
@m = Memcached.new(*@opts_networked)
|
284
|
+
x.report("get:ruby:memcached:net") do
|
285
|
+
n.times do
|
286
|
+
@m.get @key1
|
287
|
+
@m.get @key2
|
288
|
+
@m.get @key3
|
289
|
+
@m.get @key1
|
290
|
+
@m.get @key2
|
291
|
+
@m.get @key3
|
292
|
+
end
|
293
|
+
end
|
294
|
+
@m = Memcached.new(*@opt_unix)
|
295
|
+
x.report("get:ruby:memcached:uds") do
|
215
296
|
n.times do
|
216
297
|
@m.get @key1
|
217
298
|
@m.get @key2
|
@@ -223,7 +304,7 @@ class Bench
|
|
223
304
|
end
|
224
305
|
end
|
225
306
|
if defined? Caffeine
|
226
|
-
@m = Caffeine::MemCache.new(@
|
307
|
+
@m = Caffeine::MemCache.new(@opts_networked[1]); @m.servers = @opts_networked[0]
|
227
308
|
x.report("get:ruby:caffeine") do
|
228
309
|
n.times do
|
229
310
|
@m.get @key1
|
@@ -236,7 +317,7 @@ class Bench
|
|
236
317
|
end
|
237
318
|
end
|
238
319
|
if defined? MemCache
|
239
|
-
@m = MemCache.new(*@
|
320
|
+
@m = MemCache.new(*@opts_networked)
|
240
321
|
x.report("get:ruby:memcache-client") do
|
241
322
|
n.times do
|
242
323
|
@m.get @key1
|
@@ -250,19 +331,29 @@ class Bench
|
|
250
331
|
end
|
251
332
|
|
252
333
|
if defined? Memcached
|
253
|
-
@m = Memcached.new(*@
|
334
|
+
@m = Memcached.new(*@opts_networked)
|
335
|
+
|
336
|
+
# Avoid rebuilding the array every request
|
337
|
+
keys = [@key1, @key2, @key3, @key4, @key5, @key6]
|
338
|
+
|
339
|
+
x.report("multiget:ruby:memcached:net") do
|
340
|
+
n.times do
|
341
|
+
@m.get keys
|
342
|
+
end
|
343
|
+
end
|
344
|
+
@m = Memcached.new(*@opt_unix)
|
254
345
|
|
255
346
|
# Avoid rebuilding the array every request
|
256
347
|
keys = [@key1, @key2, @key3, @key4, @key5, @key6]
|
257
348
|
|
258
|
-
x.report("multiget:ruby:memcached") do
|
349
|
+
x.report("multiget:ruby:memcached:uds") do
|
259
350
|
n.times do
|
260
351
|
@m.get keys
|
261
352
|
end
|
262
353
|
end
|
263
354
|
end
|
264
355
|
if defined? Caffeine
|
265
|
-
@m = Caffeine::MemCache.new(@
|
356
|
+
@m = Caffeine::MemCache.new(@opts_networked[1]); @m.servers = @opts_networked[0]
|
266
357
|
x.report("multiget:ruby:caffeine") do
|
267
358
|
n.times do
|
268
359
|
# We don't use the keys array because splat is slow
|
@@ -271,7 +362,7 @@ class Bench
|
|
271
362
|
end
|
272
363
|
end
|
273
364
|
if defined? MemCache
|
274
|
-
@m = MemCache.new(*@
|
365
|
+
@m = MemCache.new(*@opts_networked)
|
275
366
|
x.report("multiget:ruby:memcache-client") do
|
276
367
|
n.times do
|
277
368
|
# We don't use the keys array because splat is slow
|
@@ -283,8 +374,19 @@ class Bench
|
|
283
374
|
# restart_servers
|
284
375
|
|
285
376
|
if defined? Memcached
|
286
|
-
@m = Memcached.new(*@
|
287
|
-
x.report("missing:ruby:memcached") do
|
377
|
+
@m = Memcached.new(*@opts_networked)
|
378
|
+
x.report("missing:ruby:memcached:net") do
|
379
|
+
n.times do
|
380
|
+
begin @m.delete @key1; rescue Memcached::NotFound; end
|
381
|
+
begin @m.get @key1; rescue Memcached::NotFound; end
|
382
|
+
begin @m.delete @key2; rescue Memcached::NotFound; end
|
383
|
+
begin @m.get @key2; rescue Memcached::NotFound; end
|
384
|
+
begin @m.delete @key3; rescue Memcached::NotFound; end
|
385
|
+
begin @m.get @key3; rescue Memcached::NotFound; end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
@m = Memcached.new(*@opt_unix)
|
389
|
+
x.report("missing:ruby:memcached:uds") do
|
288
390
|
n.times do
|
289
391
|
begin @m.delete @key1; rescue Memcached::NotFound; end
|
290
392
|
begin @m.get @key1; rescue Memcached::NotFound; end
|
@@ -296,7 +398,7 @@ class Bench
|
|
296
398
|
end
|
297
399
|
end
|
298
400
|
if defined? Memcached
|
299
|
-
@m = Memcached.new(*@
|
401
|
+
@m = Memcached.new(*@opts_networked)
|
300
402
|
x.report("missing:ruby:memcached:inline") do
|
301
403
|
n.times do
|
302
404
|
@m.delete @key1 rescue nil
|
@@ -307,9 +409,20 @@ class Bench
|
|
307
409
|
@m.get @key3 rescue nil
|
308
410
|
end
|
309
411
|
end
|
412
|
+
@m = Memcached.new(*@opt_unix)
|
413
|
+
x.report("missing:ruby:memcached_UDS:inline") do
|
414
|
+
n.times do
|
415
|
+
@m.delete @key1 rescue nil
|
416
|
+
@m.get @key1 rescue nil
|
417
|
+
@m.delete @key2 rescue nil
|
418
|
+
@m.get @key2 rescue nil
|
419
|
+
@m.delete @key3 rescue nil
|
420
|
+
@m.get @key3 rescue nil
|
421
|
+
end
|
422
|
+
end
|
310
423
|
end
|
311
424
|
if defined? Caffeine
|
312
|
-
@m = Caffeine::MemCache.new(@
|
425
|
+
@m = Caffeine::MemCache.new(@opts_networked[1]); @m.servers = @opts_networked[0]
|
313
426
|
x.report("missing:ruby:caffeine") do
|
314
427
|
n.times do
|
315
428
|
begin @m.delete @key1; rescue; end
|
@@ -322,7 +435,7 @@ class Bench
|
|
322
435
|
end
|
323
436
|
end
|
324
437
|
if defined? MemCache
|
325
|
-
@m = MemCache.new(*@
|
438
|
+
@m = MemCache.new(*@opts_networked)
|
326
439
|
x.report("missing:ruby:memcache-client") do
|
327
440
|
n.times do
|
328
441
|
begin @m.delete @key1; rescue; end
|
@@ -339,10 +452,10 @@ class Bench
|
|
339
452
|
|
340
453
|
if defined? Memcached
|
341
454
|
@m = Memcached.new(
|
342
|
-
@
|
343
|
-
@
|
455
|
+
@opts_networked[0],
|
456
|
+
@opts_networked[1].merge(:no_block => true, :buffer_requests => true)
|
344
457
|
)
|
345
|
-
x.report("mixed:ruby:noblock:memcached") do
|
458
|
+
x.report("mixed:ruby:noblock:memcached:net") do
|
346
459
|
n.times do
|
347
460
|
@m.set @key1, @value
|
348
461
|
@m.set @key2, @value
|
@@ -358,8 +471,45 @@ class Bench
|
|
358
471
|
@m.get @key3
|
359
472
|
end
|
360
473
|
end
|
361
|
-
@m = Memcached.new(
|
362
|
-
|
474
|
+
@m = Memcached.new(
|
475
|
+
@opt_unix[0],
|
476
|
+
@opt_unix[1].merge(:no_block => true, :buffer_requests => true)
|
477
|
+
)
|
478
|
+
x.report("mixed:ruby:noblock:memcached:uds") do
|
479
|
+
n.times do
|
480
|
+
@m.set @key1, @value
|
481
|
+
@m.set @key2, @value
|
482
|
+
@m.set @key3, @value
|
483
|
+
@m.get @key1
|
484
|
+
@m.get @key2
|
485
|
+
@m.get @key3
|
486
|
+
@m.set @key1, @value
|
487
|
+
@m.get @key1
|
488
|
+
@m.set @key2, @value
|
489
|
+
@m.get @key2
|
490
|
+
@m.set @key3, @value
|
491
|
+
@m.get @key3
|
492
|
+
end
|
493
|
+
end
|
494
|
+
@m = Memcached.new(*@opts_networked)
|
495
|
+
x.report("mixed:ruby:memcached:net") do
|
496
|
+
n.times do
|
497
|
+
@m.set @key1, @value
|
498
|
+
@m.set @key2, @value
|
499
|
+
@m.set @key3, @value
|
500
|
+
@m.get @key1
|
501
|
+
@m.get @key2
|
502
|
+
@m.get @key3
|
503
|
+
@m.set @key1, @value
|
504
|
+
@m.get @key1
|
505
|
+
@m.set @key2, @value
|
506
|
+
@m.get @key2
|
507
|
+
@m.set @key3, @value
|
508
|
+
@m.get @key3
|
509
|
+
end
|
510
|
+
end # if false
|
511
|
+
@m = Memcached.new(*@opt_unix)
|
512
|
+
x.report("mixed:ruby:memcached:uds") do
|
363
513
|
n.times do
|
364
514
|
@m.set @key1, @value
|
365
515
|
@m.set @key2, @value
|
@@ -377,7 +527,7 @@ class Bench
|
|
377
527
|
end # if false
|
378
528
|
end
|
379
529
|
if defined? Caffeine
|
380
|
-
@m = Caffeine::MemCache.new(@
|
530
|
+
@m = Caffeine::MemCache.new(@opts_networked[1]); @m.servers = @opts_networked[0]
|
381
531
|
x.report("mixed:ruby:caffeine") do
|
382
532
|
n.times do
|
383
533
|
@m.set @key1, @value
|
@@ -396,7 +546,7 @@ class Bench
|
|
396
546
|
end
|
397
547
|
end
|
398
548
|
if defined? MemCache
|
399
|
-
@m = MemCache.new(*@
|
549
|
+
@m = MemCache.new(*@opts_networked)
|
400
550
|
x.report("mixed:ruby:memcache-client") do
|
401
551
|
n.times do
|
402
552
|
@m.set @key1, @value
|
@@ -419,17 +569,16 @@ class Bench
|
|
419
569
|
|
420
570
|
if defined? Memcached
|
421
571
|
unless ARGV.include? "--no-hash"
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
x.report("hash:#{mode}:memcached") do
|
572
|
+
Memcached::HASH_VALUES.each do |mode, int|
|
573
|
+
@m = Memcached.new(@opt_unix[0], @opt_unix[1].merge(:hash => mode))
|
574
|
+
x.report("hash:#{mode}") do
|
426
575
|
n.times do
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
576
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key1, int)
|
577
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key2, int)
|
578
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key3, int)
|
579
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key4, int)
|
580
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key5, int)
|
581
|
+
Rlibmemcached.memcached_generate_hash_rvalue(@key6, int)
|
433
582
|
end
|
434
583
|
end
|
435
584
|
end
|