memcache-client 1.7.7 → 1.7.8

Sign up to get free protection for your applications and to get access to all the features.
data/FAQ.rdoc CHANGED
@@ -27,5 +27,5 @@ You can increase the timeout or disable them completely with the following confi
27
27
 
28
28
  The latest version of memcached-client is anywhere from 33% to 100% slower than memcached in various benchmarks. Keep in mind this means that 10,000 get requests take 1.8 sec instead of 1.2 seconds.
29
29
  In practice, memcache-client is unlikely to be a bottleneck in your system but there is always going
30
- to be an overhead to pure Ruby. memcache-client does have the advantage of built-in integration into
30
+ to be an overhead to pure Ruby. memcache-client does have the advantage of built-in integration into
31
31
  Rails and should work on non-MRI platforms: JRuby, MacRuby, etc.
data/History.rdoc CHANGED
@@ -1,6 +1,12 @@
1
+ = 1.7.8 (2010-02-03)
2
+
3
+ * Fix issue where autofix_keys logic did not account for namespace length. (menno)
4
+ * Fix issue when using memcache-client without rubygems. (anvar)
5
+ * Fix issue when using the cas method with raw=true (Takahiro Kikumoto)
6
+
1
7
  = 1.7.7 (2009-11-24)
2
8
 
3
- * Fix invalid delete request in memcached 1.4.x. The expiry parameter to MemCache#delete is
9
+ * Fix invalid delete request in memcached 1.4.x. The expiry parameter to MemCache#delete is
4
10
  now ignored as memcached 1.4.x has dropped support for this feature.
5
11
 
6
12
  = 1.7.6 (2009-11-03)
@@ -39,15 +45,15 @@
39
45
 
40
46
  = 1.7.1 (2009-03-28)
41
47
 
42
- * Performance optimizations:
43
- * Rely on higher performance operating system socket timeouts for low-level socket
48
+ * Performance optimizations:
49
+ * Rely on higher performance operating system socket timeouts for low-level socket
44
50
  read/writes where possible, instead of the (slower) SystemTimer or (slowest,
45
51
  unreliable) Timeout libraries.
46
- * the native binary search is back! The recent performance tuning made the binary search
47
- a bottleneck again so it had to return. It uses RubyInline to compile the native extension and
52
+ * the native binary search is back! The recent performance tuning made the binary search
53
+ a bottleneck again so it had to return. It uses RubyInline to compile the native extension and
48
54
  silently falls back to pure Ruby if anything fails. Make sure you run:
49
55
  `gem install RubyInline` if you want ultimate performance.
50
- * the changes make memcache-client 100% faster than 1.7.0 in my performance test on Ruby 1.8.6:
56
+ * the changes make memcache-client 100% faster than 1.7.0 in my performance test on Ruby 1.8.6:
51
57
  15 sec -> 8 sec.
52
58
  * Fix several logging issues.
53
59
 
@@ -58,7 +64,7 @@
58
64
  - append
59
65
  - prepend
60
66
  - replace
61
-
67
+
62
68
  Append and prepend only work with raw data since it makes no sense to concatenate two Marshalled
63
69
  values together. The cas functionality should be considered a prototype. Since I don't have an
64
70
  application which uses +cas+, I'm not sure what semantic sugar the API should provide. Should it
@@ -119,17 +125,17 @@ and work on JRuby and Ruby 1.8.5 when the native code fails to compile.
119
125
 
120
126
  = 1.6.1 (2009-01-28)
121
127
 
122
- * Add option to disable socket timeout support. Socket timeout has a significant performance
123
- penalty (approx 3x slower than without in Ruby 1.8.6). You can turn off the timeouts if you
128
+ * Add option to disable socket timeout support. Socket timeout has a significant performance
129
+ penalty (approx 3x slower than without in Ruby 1.8.6). You can turn off the timeouts if you
124
130
  need absolute performance, but by default timeouts are enabled. The performance
125
131
  penalty is much lower in Ruby 1.8.7, 1.9 and JRuby. (mperham)
126
132
 
127
- * Add option to disable server failover. Failover can lead to "split-brain" caches that
133
+ * Add option to disable server failover. Failover can lead to "split-brain" caches that
128
134
  return stale data. (mperham)
129
135
 
130
136
  * Implement continuum binary search in native code for performance reasons. Pure ruby
131
137
  is available for platforms like JRuby or Rubinius which can't use C extensions. (mperham)
132
-
138
+
133
139
  * Fix #add with raw=true (iamaleksey)
134
140
 
135
141
  = 1.6.0
data/README.rdoc CHANGED
@@ -39,7 +39,7 @@ gem installed.
39
39
 
40
40
  == Questions?
41
41
 
42
- memcache-client is maintained by Mike Perham and was originally written by Bob Cottrell,
42
+ memcache-client is maintained by Mike Perham and was originally written by Bob Cottrell,
43
43
  Eric Hodel and the seattle.rb crew.
44
44
 
45
45
  Email:: mailto:mperham@gmail.com
data/Rakefile CHANGED
@@ -14,18 +14,17 @@ begin
14
14
  s.has_rdoc = true
15
15
  s.files = FileList["[A-Z]*", "{lib,test}/**/*", 'performance.txt']
16
16
  s.test_files = FileList["test/test_*.rb"]
17
- s.rubyforge_project = 'seattlerb'
18
17
  end
19
-
18
+ Jeweler::GemcutterTasks.new
20
19
  rescue LoadError
21
20
  puts "Jeweler not available. Install it for jeweler-related tasks with: sudo gem install jeweler"
22
21
  end
23
22
 
24
23
 
25
24
  Rake::RDocTask.new do |rd|
26
- rd.main = "README.rdoc"
27
- rd.rdoc_files.include("README.rdoc", "FAQ.rdoc", "History.rdoc", "lib/memcache.rb")
28
- rd.rdoc_dir = 'doc'
25
+ rd.main = "README.rdoc"
26
+ rd.rdoc_files.include("README.rdoc", "FAQ.rdoc", "History.rdoc", "lib/memcache.rb")
27
+ rd.rdoc_dir = 'doc'
29
28
  end
30
29
 
31
30
  Rake::TestTask.new do |t|
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
- ---
2
- :patch: 7
1
+ ---
2
+ :patch: 8
3
3
  :major: 1
4
4
  :minor: 7
data/lib/memcache.rb CHANGED
@@ -3,6 +3,7 @@ $TESTING = defined?($TESTING) && $TESTING
3
3
  require 'socket'
4
4
  require 'thread'
5
5
  require 'zlib'
6
+ require 'yaml'
6
7
  require 'digest/sha1'
7
8
  require 'net/protocol'
8
9
 
@@ -82,13 +83,13 @@ class MemCache
82
83
  # The hash is only used on keys longer than 250 characters, or containing spaces,
83
84
  # to avoid impacting performance unnecesarily.
84
85
  #
85
- # In theory, your code should generate correct keys when calling memcache,
86
+ # In theory, your code should generate correct keys when calling memcache,
86
87
  # so it's your responsibility and you should try to fix this problem at its source.
87
88
  #
88
89
  # But if that's not possible, enable this option and memcache-client will give you a hand.
89
-
90
+
90
91
  attr_reader :autofix_keys
91
-
92
+
92
93
  ##
93
94
  # The servers this client talks to. Play at your own peril.
94
95
 
@@ -136,7 +137,7 @@ class MemCache
136
137
  # set/add/delete/incr/decr significantly.
137
138
  # [:check_size] Raises a MemCacheError if the value to be set is greater than 1 MB, which
138
139
  # is the maximum key size for the standard memcached server. Defaults to true.
139
- # [:autofix_keys] If a key is longer than 250 characters or contains spaces,
140
+ # [:autofix_keys] If a key is longer than 250 characters or contains spaces,
140
141
  # use an SHA1 hash instead, to prevent collisions on truncated keys.
141
142
  # Other options are ignored.
142
143
 
@@ -260,7 +261,7 @@ class MemCache
260
261
  end
261
262
 
262
263
  ##
263
- # Performs a +get+ with the given +key+. If
264
+ # Performs a +get+ with the given +key+. If
264
265
  # the value does not exist and a block was given,
265
266
  # the block will be called and the result saved via +add+.
266
267
  #
@@ -405,7 +406,7 @@ class MemCache
405
406
  (value, token) = gets(key, raw)
406
407
  return nil unless value
407
408
  updated = yield value
408
- value = Marshal.dump updated unless raw
409
+ value = raw ? updated : Marshal.dump(updated)
409
410
 
410
411
  with_server(key) do |server, cache_key|
411
412
  logger.debug { "cas #{key} to #{server.inspect}: #{value.to_s.size}" } if logger
@@ -451,7 +452,7 @@ class MemCache
451
452
  end
452
453
  end
453
454
  end
454
-
455
+
455
456
  ##
456
457
  # Add +key+ to the cache with value +value+ that expires in +expiry+
457
458
  # seconds, but only if +key+ already exists in the cache.
@@ -667,17 +668,24 @@ class MemCache
667
668
  # requested.
668
669
 
669
670
  def make_cache_key(key)
670
- if @autofix_keys and (key =~ /\s/ or (key.length + (namespace.nil? ? 0 : namespace.length)) > 250)
671
+ if @autofix_keys && (key =~ /\s/ || key_length(key) > 250)
671
672
  key = "#{Digest::SHA1.hexdigest(key)}-autofixed"
672
673
  end
673
674
 
674
- if namespace.nil? then
675
+ if namespace.nil?
675
676
  key
676
677
  else
677
678
  "#{@namespace}#{@namespace_separator}#{key}"
678
679
  end
679
680
  end
680
681
 
682
+ ##
683
+ # Calculate length of the key, including the namespace and namespace-separator.
684
+
685
+ def key_length(key)
686
+ key.length + (namespace.nil? ? 0 : ( namespace.length + (@namespace_separator.nil? ? 0 : @namespace_separator.length) ) )
687
+ end
688
+
681
689
  ##
682
690
  # Returns an interoperable hash value for +key+. (I think, docs are
683
691
  # sketchy for down servers).
@@ -705,7 +713,7 @@ class MemCache
705
713
  break unless failover
706
714
  hkey = hash_for "#{try}#{key}"
707
715
  end
708
-
716
+
709
717
  raise MemCacheError, "No servers available"
710
718
  end
711
719
 
data/lib/memcache_util.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  ##
2
2
  # A utility wrapper around the MemCache client to simplify cache access. All
3
3
  # methods silently ignore MemCache errors.
4
- #
4
+ #
5
5
  # This API is deprecated, please use the Rails.cache API or your own wrapper API
6
6
  # around MemCache.
7
7
 
8
8
  module Cache
9
-
9
+
10
10
  ##
11
11
  # Try to return a logger object that does not rely
12
12
  # on ActiveRecord for logging.
@@ -17,7 +17,7 @@ class TestBenchmark < Test::Unit::TestCase
17
17
  # which is a constant penalty that both clients have to pay
18
18
  @value = []
19
19
  @marshalled = Marshal.dump(@value)
20
-
20
+
21
21
  @opts = [
22
22
  ['127.0.0.1:11211', 'localhost:11211'],
23
23
  {
@@ -31,16 +31,16 @@ class TestBenchmark < Test::Unit::TestCase
31
31
  @key3 = "Long"*40
32
32
  @key4 = "Medium"*8
33
33
  # 5 and 6 are only used for multiget miss test
34
- @key5 = "Medium2"*8
35
- @key6 = "Long3"*40
34
+ @key5 = "Medium2"*8
35
+ @key6 = "Long3"*40
36
36
  end
37
37
 
38
38
  def test_benchmark
39
39
  Benchmark.bm(31) do |x|
40
-
40
+
41
41
  n = 2500
42
42
  # n = 1000
43
-
43
+
44
44
  @m = MemCache.new(*@opts)
45
45
  x.report("set:plain:memcache-client") do
46
46
  n.times do
@@ -52,7 +52,7 @@ class TestBenchmark < Test::Unit::TestCase
52
52
  @m.set @key3, @marshalled, 0, true
53
53
  end
54
54
  end
55
-
55
+
56
56
  @m = MemCache.new(*@opts)
57
57
  x.report("set:ruby:memcache-client") do
58
58
  n.times do
@@ -64,7 +64,7 @@ class TestBenchmark < Test::Unit::TestCase
64
64
  @m.set @key3, @value
65
65
  end
66
66
  end
67
-
67
+
68
68
  @m = MemCache.new(*@opts)
69
69
  x.report("get:plain:memcache-client") do
70
70
  n.times do
@@ -76,7 +76,7 @@ class TestBenchmark < Test::Unit::TestCase
76
76
  @m.get @key3, true
77
77
  end
78
78
  end
79
-
79
+
80
80
  @m = MemCache.new(*@opts)
81
81
  x.report("get:ruby:memcache-client") do
82
82
  n.times do
@@ -96,7 +96,7 @@ class TestBenchmark < Test::Unit::TestCase
96
96
  @m.get_multi @key1, @key2, @key3, @key4, @key5, @key6
97
97
  end
98
98
  end
99
-
99
+
100
100
  @m = MemCache.new(*@opts)
101
101
  x.report("missing:ruby:memcache-client") do
102
102
  n.times do
@@ -108,7 +108,7 @@ class TestBenchmark < Test::Unit::TestCase
108
108
  begin @m.get @key3; rescue; end
109
109
  end
110
110
  end
111
-
111
+
112
112
  @m = MemCache.new(*@opts)
113
113
  x.report("mixed:ruby:memcache-client") do
114
114
  n.times do
@@ -19,7 +19,7 @@ class MemCache
19
19
 
20
20
  attr_writer :namespace
21
21
  attr_writer :autofix_keys
22
-
22
+
23
23
  end
24
24
 
25
25
  class FakeSocket
@@ -54,11 +54,11 @@ class Test::Unit::TestCase
54
54
  assert true
55
55
  end
56
56
  end
57
-
57
+
58
58
  def memcached_running?
59
59
  TCPSocket.new('localhost', 11211) rescue false
60
60
  end
61
-
61
+
62
62
  def xprofile(name, &block)
63
63
  a = Time.now
64
64
  block.call
@@ -76,7 +76,7 @@ class Test::Unit::TestCase
76
76
  end
77
77
  time
78
78
  end
79
-
79
+
80
80
  end
81
81
 
82
82
  class FakeServer
@@ -168,7 +168,7 @@ class TestMemCache < Test::Unit::TestCase
168
168
  assert same_count > 700
169
169
  end
170
170
  end
171
-
171
+
172
172
  def test_get_multi_with_server_failure
173
173
  @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace', :logger => nil #Logger.new(STDOUT)
174
174
  s1 = FakeServer.new
@@ -211,11 +211,11 @@ class TestMemCache < Test::Unit::TestCase
211
211
  assert s1.alive?
212
212
  assert !s2.alive?
213
213
  end
214
-
214
+
215
215
  def test_cache_get_without_failover
216
216
  s1 = FakeServer.new
217
217
  s2 = FakeServer.new
218
-
218
+
219
219
  s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
220
220
  s1.socket.data.rewind
221
221
  s2.socket.data.write "bogus response\r\nbogus response\r\n"
@@ -336,7 +336,7 @@ class TestMemCache < Test::Unit::TestCase
336
336
  def test_multithread_error
337
337
  server = FakeServer.new
338
338
  server.multithread = false
339
-
339
+
340
340
  @cache = MemCache.new(['localhost:1'], :multithread => false)
341
341
 
342
342
  server.socket.data.write "bogus response\r\nbogus response\r\n"
@@ -489,7 +489,7 @@ class TestMemCache < Test::Unit::TestCase
489
489
  value = @cache.fetch('key', 1)
490
490
  assert_equal nil, value
491
491
  end
492
-
492
+
493
493
  def test_fetch_miss
494
494
  server = FakeServer.new
495
495
  server.socket.data.write "END\r\n"
@@ -725,29 +725,37 @@ class TestMemCache < Test::Unit::TestCase
725
725
  hash = Digest::SHA1.hexdigest(key)
726
726
  @cache.namespace = nil
727
727
  assert_equal key, @cache.make_cache_key(key)
728
+ end
728
729
 
730
+ def test_make_cache_key_with_autofix
729
731
  @cache.autofix_keys = true
730
732
 
731
733
  @cache.namespace = "my_namespace"
732
734
  assert_equal 'my_namespace:key', @cache.make_cache_key('key')
733
735
  @cache.namespace = nil
734
736
  assert_equal 'key', @cache.make_cache_key('key')
735
-
737
+
736
738
  key = "keys with more than two hundred and fifty characters can cause problems, because they get truncated and start colliding with each other. It's not a common occurrence, but when it happens is very hard to debug. the autofix option takes care of that for you"
737
739
  hash = Digest::SHA1.hexdigest(key)
738
740
  @cache.namespace = "my_namespace"
739
741
  assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
740
742
  @cache.namespace = nil
741
743
  assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
742
-
744
+
743
745
  key = "a short key with spaces"
744
746
  hash = Digest::SHA1.hexdigest(key)
745
747
  @cache.namespace = "my_namespace"
746
748
  assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
747
749
  @cache.namespace = nil
748
750
  assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
751
+
752
+ # namespace + separator + key > 250
753
+ key = 'k' * 240
754
+ hash = Digest::SHA1.hexdigest(key)
755
+ @cache.namespace = 'n' * 10
756
+ assert_equal "#{@cache.namespace}:#{hash}-autofixed", @cache.make_cache_key(key)
749
757
  end
750
-
758
+
751
759
  def test_servers
752
760
  server = FakeServer.new
753
761
  @cache.servers = []
@@ -864,7 +872,7 @@ class TestMemCache < Test::Unit::TestCase
864
872
  @cache.servers << server
865
873
 
866
874
  @cache.prepend 'key', 'value'
867
-
875
+
868
876
  dumped = Marshal.dump('value')
869
877
 
870
878
  expected = "prepend my_namespace:key 0 0 5\r\nvalue\r\n"
@@ -879,7 +887,7 @@ class TestMemCache < Test::Unit::TestCase
879
887
  @cache.servers << server
880
888
 
881
889
  @cache.append 'key', 'value'
882
-
890
+
883
891
  expected = "append my_namespace:key 0 0 5\r\nvalue\r\n"
884
892
  assert_equal expected, server.socket.written.string
885
893
  end
@@ -892,7 +900,7 @@ class TestMemCache < Test::Unit::TestCase
892
900
  @cache.servers << server
893
901
 
894
902
  @cache.replace 'key', 'value', 150
895
-
903
+
896
904
  dumped = Marshal.dump('value')
897
905
 
898
906
  expected = "replace my_namespace:key 0 150 #{dumped.length}\r\n#{dumped}\r\n"
@@ -907,7 +915,7 @@ class TestMemCache < Test::Unit::TestCase
907
915
  @cache.servers << server
908
916
 
909
917
  @cache.add 'key', 'value'
910
-
918
+
911
919
  dumped = Marshal.dump('value')
912
920
 
913
921
  expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
@@ -982,9 +990,9 @@ class TestMemCache < Test::Unit::TestCase
982
990
  server = FakeServer.new
983
991
  @cache.servers = []
984
992
  @cache.servers << server
985
-
993
+
986
994
  @cache.delete 'key'
987
-
995
+
988
996
  expected = "delete my_namespace:key\r\n"
989
997
  assert_equal expected, server.socket.written.string
990
998
  end
@@ -993,9 +1001,9 @@ class TestMemCache < Test::Unit::TestCase
993
1001
  server = FakeServer.new
994
1002
  @cache.servers = []
995
1003
  @cache.servers << server
996
-
1004
+
997
1005
  @cache.delete 'key', 300
998
-
1006
+
999
1007
  expected = "delete my_namespace:key\r\n"
1000
1008
  assert_equal expected, server.socket.written.string
1001
1009
  end
@@ -1042,7 +1050,7 @@ class TestMemCache < Test::Unit::TestCase
1042
1050
 
1043
1051
  assert_match(/flush_all\r\n/, socket.written.string)
1044
1052
  end
1045
-
1053
+
1046
1054
  def test_flush_all_for_real
1047
1055
  requirement(memcached_running?, 'A real memcached server must be running for testing flush_all') do
1048
1056
  cache = MemCache.new "localhost:11211", :namespace => "test_flush_all"