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/test/profile/profile.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
$LOAD_PATH << "#{HERE}/../../lib/"
|
2
|
+
require "#{File.dirname(__FILE__)}/../setup"
|
4
3
|
|
4
|
+
$LOAD_PATH << "#{File.dirname(__FILE__)}/../../lib/"
|
5
5
|
require 'rubygems'
|
6
6
|
require 'memcached'
|
7
7
|
require 'ruby-prof'
|
8
8
|
|
9
|
-
@cache = Memcached.new(
|
10
|
-
'127.0.0.1:43042', '127.0.0.1:43043'],
|
11
|
-
:namespace => "namespace"
|
12
|
-
)
|
13
|
-
|
14
9
|
result = RubyProf.profile do
|
15
|
-
load "#{HERE}/valgrind.rb"
|
10
|
+
load "#{HERE}/profile/valgrind.rb"
|
16
11
|
end
|
17
12
|
|
18
13
|
printer = RubyProf::GraphPrinter.new(result)
|
data/test/profile/valgrind.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
$LOAD_PATH << "#{HERE}/../../lib/"
|
2
|
+
require "#{File.dirname(__FILE__)}/../setup"
|
4
3
|
|
4
|
+
$LOAD_PATH << "#{File.dirname(__FILE__)}/../../lib/"
|
5
5
|
require 'memcached'
|
6
6
|
require 'rubygems'
|
7
7
|
|
8
8
|
class Worker
|
9
9
|
def initialize(method_name, iterations)
|
10
10
|
@method = method_name || 'mixed'
|
11
|
-
@i = (iterations ||
|
11
|
+
@i = (iterations || 10000).to_i
|
12
12
|
|
13
13
|
@key1 = "key1-"*8
|
14
14
|
@key2 = "key2-"*8
|
@@ -17,15 +17,13 @@ class Worker
|
|
17
17
|
@marshalled = Marshal.dump(@value)
|
18
18
|
|
19
19
|
@opts = [
|
20
|
-
[
|
20
|
+
["#{UNIX_SOCKET_NAME}0", "#{UNIX_SOCKET_NAME}1"],
|
21
21
|
{
|
22
22
|
:buffer_requests => false,
|
23
23
|
:no_block => false,
|
24
24
|
:namespace => "namespace"
|
25
25
|
}
|
26
26
|
]
|
27
|
-
system("ruby #{HERE}/../setup.rb")
|
28
|
-
sleep(1)
|
29
27
|
@cache = Memcached.new(*@opts)
|
30
28
|
|
31
29
|
@cache.set @key1, @value
|
@@ -103,11 +101,6 @@ class Worker
|
|
103
101
|
when "clone"
|
104
102
|
@i.times do
|
105
103
|
cache = @cache.clone
|
106
|
-
cache.destroy(false)
|
107
|
-
end
|
108
|
-
when "clone-nodestroy"
|
109
|
-
@i.times do
|
110
|
-
@cache.clone
|
111
104
|
end
|
112
105
|
when "servers"
|
113
106
|
@i.times do
|
@@ -117,7 +110,7 @@ class Worker
|
|
117
110
|
raise "No such method"
|
118
111
|
end
|
119
112
|
|
120
|
-
|
113
|
+
GC.start
|
121
114
|
end
|
122
115
|
|
123
116
|
end
|
data/test/setup.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
system("
|
1
|
+
|
2
|
+
unless defined? UNIX_SOCKET_NAME
|
3
|
+
HERE = File.dirname(__FILE__)
|
4
|
+
UNIX_SOCKET_NAME = File.join(ENV['TMPDIR']||'/tmp','memcached')
|
5
|
+
|
6
|
+
# Kill memcached
|
7
|
+
system("killall -9 memcached")
|
8
|
+
|
9
|
+
# Start memcached
|
10
|
+
verbosity = (ENV['DEBUG'] ? "-vv" : "")
|
11
|
+
log = "/tmp/memcached.log"
|
12
|
+
system ">#{log}"
|
13
|
+
|
14
|
+
# Network memcached
|
15
|
+
(43042..43046).each do |port|
|
16
|
+
system "memcached #{verbosity} -U #{port} -p #{port} >> #{log} 2>&1 &"
|
17
|
+
end
|
18
|
+
# Domain socket memcached
|
19
|
+
(0..1).each do |i|
|
20
|
+
system "memcached -M -s #{UNIX_SOCKET_NAME}#{i} #{verbosity} >> #{log} 2>&1 &"
|
21
|
+
end
|
8
22
|
end
|
9
|
-
|
10
|
-
log = "/tmp/memcached.log"
|
11
|
-
system ">#{log}"
|
12
|
-
|
13
|
-
verbosity = (ENV['DEBUG'] ? "-vv" : "")
|
14
|
-
|
15
|
-
(43042..43046).each do |port|
|
16
|
-
system "memcached #{verbosity} -p #{port} >> #{log} 2>&1 &"
|
17
|
-
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
|
2
2
|
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
|
3
3
|
|
4
|
+
require 'rubygems'
|
5
|
+
require 'mocha'
|
6
|
+
|
4
7
|
if ENV['DEBUG']
|
5
|
-
require 'rubygems'
|
6
8
|
require 'ruby-debug'
|
7
9
|
end
|
8
10
|
|
@@ -10,5 +12,7 @@ require 'memcached'
|
|
10
12
|
require 'test/unit'
|
11
13
|
require 'ostruct'
|
12
14
|
|
15
|
+
UNIX_SOCKET_NAME = File.join(ENV['TMPDIR']||'/tmp','memcached') unless defined? UNIX_SOCKET_NAME
|
16
|
+
|
13
17
|
class GenericClass
|
14
18
|
end
|
data/test/unit/memcached_test.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
require "#{File.dirname(__FILE__)}/../test_helper"
|
3
3
|
require 'socket'
|
4
|
+
require 'mocha'
|
4
5
|
require 'benchmark'
|
5
6
|
|
6
7
|
class MemcachedTest < Test::Unit::TestCase
|
7
8
|
|
8
9
|
def setup
|
9
|
-
@servers = ['localhost:43042', 'localhost:43043']
|
10
|
+
@servers = ['localhost:43042', 'localhost:43043', "#{UNIX_SOCKET_NAME}0"]
|
10
11
|
|
11
12
|
# Maximum allowed prefix key size for :hash_with_prefix_key_key => false
|
12
13
|
@prefix_key = 'prefix_key_'
|
@@ -18,6 +19,14 @@ class MemcachedTest < Test::Unit::TestCase
|
|
18
19
|
}
|
19
20
|
@cache = Memcached.new(@servers, @options)
|
20
21
|
|
22
|
+
@udp_options = {
|
23
|
+
:prefix_key => @prefix_key,
|
24
|
+
:hash => :default,
|
25
|
+
:udp => true,
|
26
|
+
:distribution => :modula
|
27
|
+
}
|
28
|
+
@udp_cache = Memcached.new(@servers, @udp_options)
|
29
|
+
|
21
30
|
@nb_options = {
|
22
31
|
:prefix_key => @prefix_key,
|
23
32
|
:no_block => true,
|
@@ -35,10 +44,9 @@ class MemcachedTest < Test::Unit::TestCase
|
|
35
44
|
def test_initialize
|
36
45
|
cache = Memcached.new @servers, :prefix_key => 'test'
|
37
46
|
assert_equal 'test', cache.options[:prefix_key]
|
38
|
-
assert_equal
|
47
|
+
assert_equal 3, cache.send(:server_structs).size
|
39
48
|
assert_equal 'localhost', cache.send(:server_structs).first.hostname
|
40
|
-
assert_equal
|
41
|
-
assert_equal 43043, cache.send(:server_structs).last.port
|
49
|
+
assert_equal 43042, cache.send(:server_structs).first.port
|
42
50
|
end
|
43
51
|
|
44
52
|
def test_initialize_with_ip_addresses
|
@@ -69,6 +77,12 @@ class MemcachedTest < Test::Unit::TestCase
|
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
80
|
+
def test_initialize_with_ip_address_and_options
|
81
|
+
cache = Memcached.new '127.0.0.1:43042', :ketama_weighted => false
|
82
|
+
assert_equal '127.0.0.1', cache.send(:server_structs).first.hostname
|
83
|
+
assert_equal false, cache.options[:ketama_weighted]
|
84
|
+
end
|
85
|
+
|
72
86
|
def test_options_are_set
|
73
87
|
Memcached::DEFAULTS.merge(@nb_options).each do |key, expected|
|
74
88
|
value = @nb_cache.options[key]
|
@@ -120,7 +134,7 @@ class MemcachedTest < Test::Unit::TestCase
|
|
120
134
|
def test_initialize_without_prefix_key
|
121
135
|
cache = Memcached.new @servers
|
122
136
|
assert_equal nil, cache.options[:prefix_key]
|
123
|
-
assert_equal
|
137
|
+
assert_equal 3, cache.send(:server_structs).size
|
124
138
|
end
|
125
139
|
|
126
140
|
def test_initialize_negative_behavior
|
@@ -204,6 +218,12 @@ class MemcachedTest < Test::Unit::TestCase
|
|
204
218
|
result = @cache.get key
|
205
219
|
assert_equal @value, result
|
206
220
|
end
|
221
|
+
|
222
|
+
def test_udp_get
|
223
|
+
@udp_cache.set key, @value
|
224
|
+
result = @udp_cache.get key
|
225
|
+
assert_equal @value, result
|
226
|
+
end
|
207
227
|
|
208
228
|
def test_get_nil
|
209
229
|
@cache.set key, nil, 0
|
@@ -222,21 +242,21 @@ class MemcachedTest < Test::Unit::TestCase
|
|
222
242
|
socket = stub_server 43047
|
223
243
|
cache = Memcached.new("localhost:43047:1", :timeout => 0.5)
|
224
244
|
assert 0.49 < (Benchmark.measure do
|
225
|
-
assert_raise(Memcached::
|
245
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
226
246
|
result = cache.get key
|
227
247
|
end
|
228
248
|
end).real
|
229
249
|
|
230
250
|
cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.001, :rcv_timeout => 0.5)
|
231
251
|
assert 0.49 < (Benchmark.measure do
|
232
|
-
assert_raise(Memcached::
|
252
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
233
253
|
result = cache.get key
|
234
254
|
end
|
235
255
|
end).real
|
236
256
|
|
237
257
|
cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.25, :rcv_timeout => 0.25)
|
238
|
-
assert 0.
|
239
|
-
assert_raise(Memcached::
|
258
|
+
assert 0.51 > (Benchmark.measure do
|
259
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
240
260
|
result = cache.get key
|
241
261
|
end
|
242
262
|
end).real
|
@@ -246,14 +266,14 @@ class MemcachedTest < Test::Unit::TestCase
|
|
246
266
|
socket = stub_server 43048
|
247
267
|
cache = Memcached.new("localhost:43048:1", :no_block => true, :timeout => 0.25)
|
248
268
|
assert 0.24 < (Benchmark.measure do
|
249
|
-
assert_raise(Memcached::
|
269
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
250
270
|
result = cache.get key
|
251
271
|
end
|
252
272
|
end).real
|
253
273
|
|
254
274
|
cache = Memcached.new("localhost:43048:1", :no_block => true, :poll_timeout => 0.25, :rcv_timeout => 0.001)
|
255
275
|
assert 0.24 < (Benchmark.measure do
|
256
|
-
assert_raise(Memcached::
|
276
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
257
277
|
result = cache.get key
|
258
278
|
end
|
259
279
|
end).real
|
@@ -263,7 +283,7 @@ class MemcachedTest < Test::Unit::TestCase
|
|
263
283
|
:rcv_timeout => 0.25 # No affect in no-block mode
|
264
284
|
)
|
265
285
|
assert 0.24 > (Benchmark.measure do
|
266
|
-
assert_raise(Memcached::
|
286
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
267
287
|
result = cache.get key
|
268
288
|
end
|
269
289
|
end).real
|
@@ -379,6 +399,12 @@ class MemcachedTest < Test::Unit::TestCase
|
|
379
399
|
end
|
380
400
|
end
|
381
401
|
|
402
|
+
def test_udp_set
|
403
|
+
assert_nothing_raised do
|
404
|
+
@udp_cache.set(key, @value)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
382
408
|
def test_set_expiry
|
383
409
|
@cache.set key, @value, 1
|
384
410
|
assert_nothing_raised do
|
@@ -655,17 +681,25 @@ class MemcachedTest < Test::Unit::TestCase
|
|
655
681
|
end
|
656
682
|
end
|
657
683
|
|
658
|
-
def
|
659
|
-
|
660
|
-
|
661
|
-
|
684
|
+
def test_server_error_message
|
685
|
+
@cache.set key, "I'm big" * 1000000
|
686
|
+
assert false # Never reached
|
687
|
+
rescue Memcached::ServerError => e
|
688
|
+
assert_match /^"object too large for cache". Key/, e.message
|
689
|
+
end
|
690
|
+
|
691
|
+
def test_errno_message
|
692
|
+
Rlibmemcached::MemcachedServerSt.any_instance.expects("cached_errno").returns(1)
|
693
|
+
@cache.send(:check_return_code, Rlibmemcached::MEMCACHED_ERRNO, key)
|
694
|
+
rescue Memcached::SystemError => e
|
695
|
+
assert_match /^Errno 1: "Operation not permitted". Key/, e.message
|
662
696
|
end
|
663
697
|
|
664
698
|
# Stats
|
665
699
|
|
666
700
|
def test_stats
|
667
701
|
stats = @cache.stats
|
668
|
-
assert_equal
|
702
|
+
assert_equal 3, stats[:pid].size
|
669
703
|
assert_instance_of Fixnum, stats[:pid].first
|
670
704
|
assert_instance_of String, stats[:version].first
|
671
705
|
end
|
@@ -753,30 +787,64 @@ class MemcachedTest < Test::Unit::TestCase
|
|
753
787
|
|
754
788
|
# Server removal and consistent hashing
|
755
789
|
|
756
|
-
def
|
790
|
+
def test_unresponsive_server
|
757
791
|
socket = stub_server 43041
|
758
792
|
cache = Memcached.new(
|
759
793
|
[@servers.last, 'localhost:43041'],
|
760
794
|
:prefix_key => @prefix_key,
|
761
795
|
:auto_eject_hosts => true,
|
762
|
-
:server_failure_limit =>
|
796
|
+
:server_failure_limit => 2,
|
763
797
|
:retry_timeout => 1,
|
764
798
|
:hash_with_prefix_key => false,
|
765
799
|
:hash => :md5
|
766
800
|
)
|
767
801
|
|
768
|
-
# Hit
|
769
|
-
|
770
|
-
cache.set(
|
771
|
-
cache.get(
|
802
|
+
# Hit second server up to the server_failure_limit
|
803
|
+
key2 = 'test_missing_server'
|
804
|
+
assert_raise(Memcached::ATimeoutOccurred) { cache.set(key2, @value) }
|
805
|
+
assert_raise(Memcached::ATimeoutOccurred) { cache.get(key2, @value) }
|
772
806
|
|
773
|
-
# Hit second server
|
807
|
+
# Hit second server and pass the limit
|
774
808
|
key2 = 'test_missing_server'
|
775
|
-
|
809
|
+
begin
|
810
|
+
cache.get(key2)
|
811
|
+
rescue => e
|
812
|
+
assert_equal Memcached::ServerIsMarkedDead, e.class
|
813
|
+
assert_match /localhost:43041/, e.message
|
814
|
+
end
|
815
|
+
|
816
|
+
# Hit first server on retry
|
817
|
+
assert_nothing_raised do
|
776
818
|
cache.set(key2, @value)
|
819
|
+
assert_equal cache.get(key2), @value
|
777
820
|
end
|
821
|
+
|
822
|
+
sleep(2)
|
823
|
+
|
824
|
+
# Hit second server again after restore, expect same failure
|
825
|
+
key2 = 'test_missing_server'
|
826
|
+
assert_raise(Memcached::ATimeoutOccurred) do
|
827
|
+
cache.set(key2, @value)
|
828
|
+
end
|
829
|
+
end
|
778
830
|
|
779
|
-
|
831
|
+
def test_missing_server
|
832
|
+
cache = Memcached.new(
|
833
|
+
[@servers.last, 'localhost:43041'],
|
834
|
+
:prefix_key => @prefix_key,
|
835
|
+
:auto_eject_hosts => true,
|
836
|
+
:server_failure_limit => 2,
|
837
|
+
:retry_timeout => 1,
|
838
|
+
:hash_with_prefix_key => false,
|
839
|
+
:hash => :md5
|
840
|
+
)
|
841
|
+
|
842
|
+
# Hit second server up to the server_failure_limit
|
843
|
+
key2 = 'test_missing_server'
|
844
|
+
assert_raise(Memcached::SystemError) { cache.set(key2, @value) }
|
845
|
+
assert_raise(Memcached::SystemError) { cache.get(key2, @value) }
|
846
|
+
|
847
|
+
# Hit second server and pass the limit
|
780
848
|
key2 = 'test_missing_server'
|
781
849
|
begin
|
782
850
|
cache.get(key2)
|
@@ -788,14 +856,14 @@ class MemcachedTest < Test::Unit::TestCase
|
|
788
856
|
# Hit first server on retry
|
789
857
|
assert_nothing_raised do
|
790
858
|
cache.set(key2, @value)
|
791
|
-
cache.get(key2)
|
859
|
+
assert_equal cache.get(key2), @value
|
792
860
|
end
|
793
861
|
|
794
862
|
sleep(2)
|
795
863
|
|
796
864
|
# Hit second server again after restore, expect same failure
|
797
865
|
key2 = 'test_missing_server'
|
798
|
-
assert_raise(Memcached::
|
866
|
+
assert_raise(Memcached::SystemError) do
|
799
867
|
cache.set(key2, @value)
|
800
868
|
end
|
801
869
|
end
|
@@ -849,7 +917,7 @@ class MemcachedTest < Test::Unit::TestCase
|
|
849
917
|
threads.each {|thread| thread.join}
|
850
918
|
end
|
851
919
|
|
852
|
-
# Hash
|
920
|
+
# Hash
|
853
921
|
|
854
922
|
def test_hash
|
855
923
|
assert_equal 3157003241,
|
data/test/unit/rails_test.rb
CHANGED
@@ -4,7 +4,7 @@ require "#{File.dirname(__FILE__)}/../test_helper"
|
|
4
4
|
class RailsTest < Test::Unit::TestCase
|
5
5
|
|
6
6
|
def setup
|
7
|
-
@servers = ['127.0.0.1:43042', '127.0.0.1:43043']
|
7
|
+
@servers = ['127.0.0.1:43042', '127.0.0.1:43043', "#{UNIX_SOCKET_NAME}0"]
|
8
8
|
@namespace = 'rails_test'
|
9
9
|
@cache = Memcached::Rails.new(:servers => @servers, :namespace => @namespace)
|
10
10
|
@value = OpenStruct.new(:a => 1, :b => 2, :c => GenericClass)
|
@@ -19,7 +19,7 @@ class RailsTest < Test::Unit::TestCase
|
|
19
19
|
|
20
20
|
def test_get_multi
|
21
21
|
@cache.set key, @value
|
22
|
-
result = @cache.get_multi
|
22
|
+
result = @cache.get_multi([key])
|
23
23
|
assert_equal(
|
24
24
|
{key => @value},
|
25
25
|
result
|
@@ -47,6 +47,36 @@ class RailsTest < Test::Unit::TestCase
|
|
47
47
|
assert_equal @value, result
|
48
48
|
end
|
49
49
|
|
50
|
+
def test_cas
|
51
|
+
cache = Memcached::Rails.new(:servers => @servers, :namespace => @namespace, :support_cas => true)
|
52
|
+
value2 = OpenStruct.new(:d => 3, :e => 4, :f => GenericClass)
|
53
|
+
|
54
|
+
# Existing set
|
55
|
+
cache.set key, @value
|
56
|
+
cache.cas(key) do |current|
|
57
|
+
assert_equal @value, current
|
58
|
+
value2
|
59
|
+
end
|
60
|
+
assert_equal value2, cache.get(key)
|
61
|
+
|
62
|
+
# Missing set
|
63
|
+
cache.delete key
|
64
|
+
assert_nothing_raised do
|
65
|
+
cache.cas(key) { @called = true }
|
66
|
+
end
|
67
|
+
assert_nil cache.get(key)
|
68
|
+
assert_nil @called
|
69
|
+
|
70
|
+
# Conflicting set
|
71
|
+
cache.set key, @value
|
72
|
+
assert_raises(Memcached::ConnectionDataExists) do
|
73
|
+
cache.cas(key) do |current|
|
74
|
+
cache.set key, value2
|
75
|
+
current
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
50
80
|
def test_get_missing
|
51
81
|
@cache.delete key rescue nil
|
52
82
|
result = @cache.get key
|