memcached 0.19.2 → 0.19.3

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,3 +1,4 @@
1
+ v0.19.3. Add exception_retry_limit and exceptions_to_retry.
1
2
 
2
3
  v0.19.2. Regenerate SWIG with better configuration options for Linux.
3
4
 
@@ -34,11 +34,11 @@ if !ENV["EXTERNAL_LIB"]
34
34
  raise "'#{cmd}' failed" unless system(cmd)
35
35
 
36
36
  puts "Patching libmemcached source."
37
- puts(cmd = "patch -p1 < libmemcached.patch")
37
+ puts(cmd = "patch -p1 -Z < libmemcached.patch")
38
38
  raise "'#{cmd}' failed" unless system(cmd)
39
39
 
40
40
  puts "Patching libmemcached with SASL support."
41
- puts(cmd = "patch -p1 < sasl.patch")
41
+ puts(cmd = "patch -p1 -Z < sasl.patch")
42
42
  raise "'#{cmd}' failed" unless system(cmd)
43
43
 
44
44
  Dir.chdir(BUNDLE_PATH) do
@@ -31,7 +31,21 @@ class Memcached
31
31
  :verify_key => true,
32
32
  :use_udp => false,
33
33
  :binary_protocol => false,
34
- :credentials => nil
34
+ :credentials => nil,
35
+ :exception_retry_limit => 5,
36
+ :exceptions_to_retry => [
37
+ Memcached::ServerIsMarkedDead,
38
+ Memcached::ATimeoutOccurred,
39
+ Memcached::ConnectionBindFailure,
40
+ Memcached::ConnectionFailure,
41
+ Memcached::ConnectionSocketCreateFailure,
42
+ Memcached::Failure,
43
+ Memcached::MemoryAllocationFailure,
44
+ Memcached::ReadFailure,
45
+ Memcached::ServerError,
46
+ Memcached::SystemError,
47
+ Memcached::UnknownReadFailure,
48
+ Memcached::WriteFailure]
35
49
  }
36
50
 
37
51
  #:stopdoc:
@@ -75,6 +89,8 @@ Valid option parameters are:
75
89
  <tt>:binary_protocol</tt>:: Use the binary protocol to reduce query processing overhead. Defaults to false.
76
90
  <tt>:sort_hosts</tt>:: Whether to force the server list to stay sorted. This defeats consistent hashing and is rarely useful.
77
91
  <tt>:verify_key</tt>:: Validate keys before accepting them. Never disable this.
92
+ <tt>:exception_retry_limit</tt>:: Retry this many times before raising the exception if the exception is in <tt>:exceptions_to_retry</tt>.
93
+ <tt>:exceptions_to_retry</tt>:: Exceptions listed here will be retried <tt>:exception_retry_limit</tt> times before getting raised.
78
94
 
79
95
  Please note that when pipelining is enabled, setter and deleter methods do not raise on errors. For example, if you try to set an invalid key with <tt>:no_block => true</tt>, 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.
80
96
 
@@ -231,6 +247,12 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
231
247
  self
232
248
  end
233
249
 
250
+ # Should retry the exception
251
+ def should_retry(e)
252
+ options[:exceptions_to_retry].each {|ex_class| return true if e.instance_of?(ex_class)}
253
+ false
254
+ end
255
+
234
256
  #:stopdoc:
235
257
  alias :dup :clone #:nodoc:
236
258
  #:startdoc:
@@ -282,23 +304,34 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
282
304
  #
283
305
  def set(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
284
306
  value = marshal ? Marshal.dump(value) : value.to_s
285
- check_return_code(
286
- Lib.memcached_set(@struct, key, value, ttl, flags),
287
- key
288
- )
289
- rescue ClientError
290
- # FIXME Memcached 1.2.8 occasionally rejects valid sets
291
- tried = 1 and retry unless defined?(tried)
292
- raise
307
+ begin
308
+ check_return_code(
309
+ Lib.memcached_set(@struct, key, value, ttl, flags),
310
+ key
311
+ )
312
+ rescue => e
313
+ tries ||= 0
314
+ retry if e.instance_of?(ClientError) && !tries
315
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
316
+ tries += 1
317
+ retry
318
+ end
293
319
  end
294
320
 
295
321
  # 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>.
296
322
  def add(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
297
323
  value = marshal ? Marshal.dump(value) : value.to_s
298
- check_return_code(
299
- Lib.memcached_add(@struct, key, value, ttl, flags),
300
- key
301
- )
324
+ begin
325
+ check_return_code(
326
+ Lib.memcached_add(@struct, key, value, ttl, flags),
327
+ key
328
+ )
329
+ rescue => e
330
+ tries ||= 0
331
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
332
+ tries += 1
333
+ retry
334
+ end
302
335
  end
303
336
 
304
337
  # Increment a key's value. Accepts a String <tt>key</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist.
@@ -310,6 +343,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
310
343
  ret, value = Lib.memcached_increment(@struct, key, offset)
311
344
  check_return_code(ret, key)
312
345
  value
346
+ rescue => e
347
+ tries ||= 0
348
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
349
+ tries += 1
350
+ retry
313
351
  end
314
352
 
315
353
  # Decrement a key's value. The parameters and exception behavior are the same as <tt>increment</tt>.
@@ -317,6 +355,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
317
355
  ret, value = Lib.memcached_decrement(@struct, key, offset)
318
356
  check_return_code(ret, key)
319
357
  value
358
+ rescue => e
359
+ tries ||= 0
360
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
361
+ tries += 1
362
+ retry
320
363
  end
321
364
 
322
365
  #:stopdoc:
@@ -327,10 +370,17 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
327
370
  # 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>.
328
371
  def replace(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
329
372
  value = marshal ? Marshal.dump(value) : value.to_s
330
- check_return_code(
331
- Lib.memcached_replace(@struct, key, value, ttl, flags),
332
- key
333
- )
373
+ begin
374
+ check_return_code(
375
+ Lib.memcached_replace(@struct, key, value, ttl, flags),
376
+ key
377
+ )
378
+ rescue => e
379
+ tries ||= 0
380
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
381
+ tries += 1
382
+ retry
383
+ end
334
384
  end
335
385
 
336
386
  # Appends a string to a key's value. Accepts a String <tt>key</tt> and a String <tt>value</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist on the server.
@@ -342,6 +392,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
342
392
  Lib.memcached_append(@struct, key, value.to_s, IGNORED, IGNORED),
343
393
  key
344
394
  )
395
+ rescue => e
396
+ tries ||= 0
397
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
398
+ tries += 1
399
+ retry
345
400
  end
346
401
 
347
402
  # Prepends a string to a key's value. The parameters and exception behavior are the same as <tt>append</tt>.
@@ -351,6 +406,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
351
406
  Lib.memcached_prepend(@struct, key, value.to_s, IGNORED, IGNORED),
352
407
  key
353
408
  )
409
+ rescue => e
410
+ tries ||= 0
411
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
412
+ tries += 1
413
+ retry
354
414
  end
355
415
 
356
416
  # 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 <b>Memcached::NotStored</b>. Accepts a String <tt>key</tt> and a block.
@@ -358,22 +418,37 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
358
418
  # Also accepts an optional <tt>ttl</tt> value.
359
419
  #
360
420
  # 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.
361
- #
421
+ # :retry_on_exceptions does not apply to this method
362
422
  def cas(key, ttl=@default_ttl, marshal=true, flags=FLAGS)
363
423
  raise ClientError, "CAS not enabled for this Memcached instance" unless options[:support_cas]
364
424
 
365
- value, flags, ret = Lib.memcached_get_rvalue(@struct, key)
366
- check_return_code(ret, key)
425
+ begin
426
+ value, flags, ret = Lib.memcached_get_rvalue(@struct, key)
427
+ check_return_code(ret, key)
428
+ rescue => e
429
+ tries_for_get ||= 0
430
+ raise unless tries_for_get < options[:exception_retry_limit] && should_retry(e)
431
+ tries_for_get += 1
432
+ retry
433
+ end
434
+
367
435
  cas = @struct.result.cas
368
436
 
369
437
  value = Marshal.load(value) if marshal
370
438
  value = yield value
371
439
  value = Marshal.dump(value) if marshal
372
440
 
373
- check_return_code(
374
- Lib.memcached_cas(@struct, key, value, ttl, flags, cas),
375
- key
376
- )
441
+ begin
442
+ check_return_code(
443
+ Lib.memcached_cas(@struct, key, value, ttl, flags, cas),
444
+ key
445
+ )
446
+ rescue => e
447
+ tries_for_cas ||= 0
448
+ raise unless tries_for_cas < options[:exception_retry_limit] && should_retry(e)
449
+ tries_for_cas += 1
450
+ retry
451
+ end
377
452
  end
378
453
 
379
454
  alias :compare_and_swap :cas
@@ -386,6 +461,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
386
461
  Lib.memcached_delete(@struct, key, IGNORED),
387
462
  key
388
463
  )
464
+ rescue => e
465
+ tries ||= 0
466
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
467
+ tries += 1
468
+ retry
389
469
  end
390
470
 
391
471
  # Flushes all key/value pairs from all the servers.
@@ -393,6 +473,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
393
473
  check_return_code(
394
474
  Lib.memcached_flush(@struct, IGNORED)
395
475
  )
476
+ rescue => e
477
+ tries ||= 0
478
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
479
+ tries += 1
480
+ retry
396
481
  end
397
482
 
398
483
  ### Getters
@@ -428,6 +513,11 @@ Please note that when pipelining is enabled, setter and deleter methods do not r
428
513
  check_return_code(ret, keys)
429
514
  marshal ? Marshal.load(value) : value
430
515
  end
516
+ rescue => e
517
+ tries ||= 0
518
+ raise unless tries < options[:exception_retry_limit] && should_retry(e)
519
+ tries += 1
520
+ retry
431
521
  end
432
522
 
433
523
  ### Information methods
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{memcached}
5
- s.version = "0.19.2"
5
+ s.version = "0.19.3"
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{2010-03-23}
10
+ s.date = %q{2010-04-20}
11
11
  s.description = %q{An interface to the libmemcached C client.}
12
12
  s.email = %q{}
13
13
  s.extensions = ["ext/extconf.rb"]
@@ -23,6 +23,7 @@ class MemcachedTest < Test::Unit::TestCase
23
23
  :prefix_key => @prefix_key,
24
24
  :hash => :default,
25
25
  :distribution => :modula,
26
+ # binary_protocol does not work -- test_get, test_get, test_append, and test_missing_append will fail when it is set to true.
26
27
  :binary_protocol => true}
27
28
  @binary_protocol_cache = Memcached.new(@servers, @binary_protocol_options)
28
29
 
@@ -263,21 +264,21 @@ class MemcachedTest < Test::Unit::TestCase
263
264
 
264
265
  def test_get_with_server_timeout
265
266
  socket = stub_server 43047
266
- cache = Memcached.new("localhost:43047:1", :timeout => 0.5)
267
+ cache = Memcached.new("localhost:43047:1", :timeout => 0.5, :exception_retry_limit => 0)
267
268
  assert 0.49 < (Benchmark.measure do
268
269
  assert_raise(Memcached::ATimeoutOccurred) do
269
270
  result = cache.get key
270
271
  end
271
272
  end).real
272
273
 
273
- cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.001, :rcv_timeout => 0.5)
274
+ cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.001, :rcv_timeout => 0.5, :exception_retry_limit => 0)
274
275
  assert 0.49 < (Benchmark.measure do
275
276
  assert_raise(Memcached::ATimeoutOccurred) do
276
277
  result = cache.get key
277
278
  end
278
279
  end).real
279
280
 
280
- cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.25, :rcv_timeout => 0.25)
281
+ cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.25, :rcv_timeout => 0.25, :exception_retry_limit => 0)
281
282
  assert 0.51 > (Benchmark.measure do
282
283
  assert_raise(Memcached::ATimeoutOccurred) do
283
284
  result = cache.get key
@@ -289,14 +290,14 @@ class MemcachedTest < Test::Unit::TestCase
289
290
 
290
291
  def test_get_with_no_block_server_timeout
291
292
  socket = stub_server 43048
292
- cache = Memcached.new("localhost:43048:1", :no_block => true, :timeout => 0.25)
293
+ cache = Memcached.new("localhost:43048:1", :no_block => true, :timeout => 0.25, :exception_retry_limit => 0)
293
294
  assert 0.24 < (Benchmark.measure do
294
295
  assert_raise(Memcached::ATimeoutOccurred) do
295
296
  result = cache.get key
296
297
  end
297
298
  end).real
298
299
 
299
- cache = Memcached.new("localhost:43048:1", :no_block => true, :poll_timeout => 0.25, :rcv_timeout => 0.001)
300
+ cache = Memcached.new("localhost:43048:1", :no_block => true, :poll_timeout => 0.25, :rcv_timeout => 0.001, :exception_retry_limit => 0)
300
301
  assert 0.24 < (Benchmark.measure do
301
302
  assert_raise(Memcached::ATimeoutOccurred) do
302
303
  result = cache.get key
@@ -305,7 +306,8 @@ class MemcachedTest < Test::Unit::TestCase
305
306
 
306
307
  cache = Memcached.new("localhost:43048:1", :no_block => true,
307
308
  :poll_timeout => 0.001,
308
- :rcv_timeout => 0.25 # No affect in no-block mode
309
+ :rcv_timeout => 0.25, # No affect in no-block mode
310
+ :exception_retry_limit => 0
309
311
  )
310
312
  assert 0.24 > (Benchmark.measure do
311
313
  assert_raise(Memcached::ATimeoutOccurred) do
@@ -863,7 +865,8 @@ class MemcachedTest < Test::Unit::TestCase
863
865
  :server_failure_limit => 2,
864
866
  :retry_timeout => 1,
865
867
  :hash_with_prefix_key => false,
866
- :hash => :md5
868
+ :hash => :md5,
869
+ :exception_retry_limit => 0
867
870
  )
868
871
 
869
872
  # Hit second server up to the server_failure_limit
@@ -897,6 +900,121 @@ class MemcachedTest < Test::Unit::TestCase
897
900
  socket.close
898
901
  end
899
902
 
903
+ def test_unresponsive_server_retries_greater_than_server_failure_limit
904
+ socket = stub_server 43041
905
+
906
+ cache = Memcached.new(
907
+ [@servers.last, 'localhost:43041'],
908
+ :prefix_key => @prefix_key,
909
+ :auto_eject_hosts => true,
910
+ :server_failure_limit => 2,
911
+ :retry_timeout => 1,
912
+ :hash_with_prefix_key => false,
913
+ :hash => :md5,
914
+ :exception_retry_limit => 3
915
+ )
916
+
917
+ key2 = 'test_missing_server'
918
+ assert_nothing_raised do
919
+ cache.set(key2, @value)
920
+ assert_equal cache.get(key2), @value
921
+ end
922
+
923
+ assert_nothing_raised do
924
+ cache.set(key2, @value)
925
+ assert_equal cache.get(key2), @value
926
+ end
927
+
928
+ sleep(2)
929
+
930
+ assert_nothing_raised do
931
+ cache.set(key2, @value)
932
+ assert_equal cache.get(key2), @value
933
+ end
934
+
935
+ socket.close
936
+ end
937
+
938
+ def test_unresponsive_server_retries_equals_server_failure_limit
939
+ socket = stub_server 43041
940
+
941
+ cache = Memcached.new(
942
+ [@servers.last, 'localhost:43041'],
943
+ :prefix_key => @prefix_key,
944
+ :auto_eject_hosts => true,
945
+ :server_failure_limit => 2,
946
+ :retry_timeout => 1,
947
+ :hash_with_prefix_key => false,
948
+ :hash => :md5,
949
+ :exception_retry_limit => 3
950
+ )
951
+
952
+ key2 = 'test_missing_server'
953
+ begin
954
+ cache.get(key2)
955
+ rescue => e
956
+ assert_equal Memcached::ServerIsMarkedDead, e.class
957
+ assert_match /localhost:43041/, e.message
958
+ end
959
+
960
+ assert_nothing_raised do
961
+ cache.set(key2, @value)
962
+ assert_equal cache.get(key2), @value
963
+ end
964
+
965
+ sleep(2)
966
+
967
+ begin
968
+ cache.get(key2)
969
+ rescue => e
970
+ assert_equal Memcached::ServerIsMarkedDead, e.class
971
+ assert_match /localhost:43041/, e.message
972
+ end
973
+
974
+ assert_nothing_raised do
975
+ cache.set(key2, @value)
976
+ assert_equal cache.get(key2), @value
977
+ end
978
+
979
+ socket.close
980
+ end
981
+
982
+ def test_unresponsive_server_retries_less_than_server_failure_limit
983
+ socket = stub_server 43041
984
+
985
+ cache = Memcached.new(
986
+ [@servers.last, 'localhost:43041'],
987
+ :prefix_key => @prefix_key,
988
+ :auto_eject_hosts => true,
989
+ :server_failure_limit => 2,
990
+ :retry_timeout => 1,
991
+ :hash_with_prefix_key => false,
992
+ :hash => :md5,
993
+ :exception_retry_limit => 1
994
+ )
995
+
996
+ key2 = 'test_missing_server'
997
+ assert_raise(Memcached::ATimeoutOccurred) { cache.set(key2, @value) }
998
+ begin
999
+ cache.get(key2)
1000
+ rescue => e
1001
+ assert_equal Memcached::ServerIsMarkedDead, e.class
1002
+ assert_match /localhost:43041/, e.message
1003
+ end
1004
+
1005
+ sleep(2)
1006
+
1007
+ assert_raise(Memcached::ATimeoutOccurred) { cache.set(key2, @value) }
1008
+ begin
1009
+ cache.get(key2)
1010
+ rescue => e
1011
+ assert_equal Memcached::ServerIsMarkedDead, e.class
1012
+ assert_match /localhost:43041/, e.message
1013
+ end
1014
+
1015
+ socket.close
1016
+ end
1017
+
900
1018
  def test_missing_server
901
1019
  cache = Memcached.new(
902
1020
  [@servers.last, 'localhost:43041'],
@@ -905,7 +1023,8 @@ class MemcachedTest < Test::Unit::TestCase
905
1023
  :server_failure_limit => 2,
906
1024
  :retry_timeout => 1,
907
1025
  :hash_with_prefix_key => false,
908
- :hash => :md5
1026
+ :hash => :md5,
1027
+ :exception_retry_limit => 0
909
1028
  )
910
1029
 
911
1030
  # Hit second server up to the server_failure_limit
@@ -946,7 +1065,8 @@ class MemcachedTest < Test::Unit::TestCase
946
1065
  :auto_eject_hosts => true,
947
1066
  :distribution => :random,
948
1067
  :server_failure_limit => 1,
949
- :retry_timeout => 1
1068
+ :retry_timeout => 1,
1069
+ :exception_retry_limit => 0
950
1070
  )
951
1071
 
952
1072
  # Provoke the errors in 'failures'
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 19
8
- - 2
9
- version: 0.19.2
8
+ - 3
9
+ version: 0.19.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Evan Weaver
@@ -35,7 +35,7 @@ cert_chain:
35
35
  yZ0=
36
36
  -----END CERTIFICATE-----
37
37
 
38
- date: 2010-03-23 00:00:00 -07:00
38
+ date: 2010-04-20 00:00:00 -07:00
39
39
  default_executable:
40
40
  dependencies: []
41
41
 
metadata.gz.sig CHANGED
Binary file