mperham-memcache-client 1.6.3 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +13 -2
- data/lib/memcache.rb +56 -3
- data/test/test_mem_cache.rb +26 -0
- metadata +4 -15
- data/lib/continuum.rb +0 -77
- data/lib/memcache_util.rb +0 -102
data/History.txt
CHANGED
@@ -1,7 +1,18 @@
|
|
1
|
-
= 1.6.
|
1
|
+
= 1.6.4 (2009-02-19)
|
2
|
+
|
3
|
+
* Remove native code altogether. The speedup was only 10% on Ruby 1.8.6 and did not work
|
4
|
+
on Ruby 1.9.1.
|
5
|
+
|
6
|
+
* Removed memcache_util.rb from the distribution. If you are using it, please copy the code
|
7
|
+
into your own project. The file will live in the github repository for a few more months
|
8
|
+
for this purposes. http://github.com/mperham/memcache-client/raw/7a276089aa3c914e47e3960f9740ac7377204970/lib/memcache_util.rb
|
9
|
+
|
10
|
+
* Roll continuum.rb into memcache.rb. The project is again a single Ruby file, with no dependencies.
|
11
|
+
|
12
|
+
= 1.6.3 (2009-02-14)
|
2
13
|
|
3
14
|
* Remove gem native extension in preference to RubyInline. This allows the gem to install
|
4
|
-
and work on JRuby.
|
15
|
+
and work on JRuby and Ruby 1.8.5 when the native code fails to compile.
|
5
16
|
|
6
17
|
= 1.6.2 (2009-02-04)
|
7
18
|
|
data/lib/memcache.rb
CHANGED
@@ -6,8 +6,6 @@ require 'timeout'
|
|
6
6
|
require 'zlib'
|
7
7
|
require 'digest/sha1'
|
8
8
|
|
9
|
-
require 'continuum'
|
10
|
-
|
11
9
|
##
|
12
10
|
# A Ruby client library for memcached.
|
13
11
|
#
|
@@ -17,7 +15,7 @@ class MemCache
|
|
17
15
|
##
|
18
16
|
# The version of MemCache you are using.
|
19
17
|
|
20
|
-
VERSION = '1.6.
|
18
|
+
VERSION = '1.6.4'
|
21
19
|
|
22
20
|
##
|
23
21
|
# Default options for the cache object.
|
@@ -120,6 +118,8 @@ class MemCache
|
|
120
118
|
|
121
119
|
logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger
|
122
120
|
|
121
|
+
Thread.current[:memcache_client] = self.object_id if !@multithread
|
122
|
+
|
123
123
|
self.servers = servers
|
124
124
|
end
|
125
125
|
|
@@ -606,6 +606,8 @@ class MemCache
|
|
606
606
|
# failures (but does still apply to unexpectedly lost connections etc.).
|
607
607
|
|
608
608
|
def with_socket_management(server, &block)
|
609
|
+
check_multithread_status!
|
610
|
+
|
609
611
|
@mutex.lock if @multithread
|
610
612
|
retried = false
|
611
613
|
|
@@ -697,6 +699,18 @@ class MemCache
|
|
697
699
|
((total_servers * Continuum::POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
|
698
700
|
end
|
699
701
|
|
702
|
+
def check_multithread_status!
|
703
|
+
return if @multithread
|
704
|
+
|
705
|
+
if Thread.current[:memcache_client] != self.object_id
|
706
|
+
raise MemCacheError, <<-EOM
|
707
|
+
You are accessing this memcache-client instance from multiple threads but have not enabled multithread support.
|
708
|
+
Normally: MemCache.new(['localhost:11211'], :multithread => true)
|
709
|
+
In Rails: config.cache_store = [:mem_cache_store, 'localhost:11211', { :multithread => true }]
|
710
|
+
EOM
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
700
714
|
##
|
701
715
|
# This class represents a memcached server instance.
|
702
716
|
|
@@ -894,3 +908,42 @@ class TCPTimeoutSocket
|
|
894
908
|
@sock.close
|
895
909
|
end
|
896
910
|
end
|
911
|
+
|
912
|
+
module Continuum
|
913
|
+
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
914
|
+
|
915
|
+
# Find the closest index in Continuum with value <= the given value
|
916
|
+
def self.binary_search(ary, value, &block)
|
917
|
+
upper = ary.size - 1
|
918
|
+
lower = 0
|
919
|
+
idx = 0
|
920
|
+
|
921
|
+
while(lower <= upper) do
|
922
|
+
idx = (lower + upper) / 2
|
923
|
+
comp = ary[idx].value <=> value
|
924
|
+
|
925
|
+
if comp == 0
|
926
|
+
return idx
|
927
|
+
elsif comp > 0
|
928
|
+
upper = idx - 1
|
929
|
+
else
|
930
|
+
lower = idx + 1
|
931
|
+
end
|
932
|
+
end
|
933
|
+
return upper
|
934
|
+
end
|
935
|
+
|
936
|
+
class Entry
|
937
|
+
attr_reader :value
|
938
|
+
attr_reader :server
|
939
|
+
|
940
|
+
def initialize(val, srv)
|
941
|
+
@value = val
|
942
|
+
@server = srv
|
943
|
+
end
|
944
|
+
|
945
|
+
def inspect
|
946
|
+
"<#{value}, #{server.host}:#{server.port}>"
|
947
|
+
end
|
948
|
+
end
|
949
|
+
end
|
data/test/test_mem_cache.rb
CHANGED
@@ -333,6 +333,32 @@ class TestMemCache < Test::Unit::TestCase
|
|
333
333
|
assert !server.alive?
|
334
334
|
end
|
335
335
|
|
336
|
+
def test_multithread_error
|
337
|
+
server = FakeServer.new
|
338
|
+
|
339
|
+
# Write two messages to the socket to test failover
|
340
|
+
server.socket.data.write "bogus response\r\nbogus response\r\n"
|
341
|
+
server.socket.data.rewind
|
342
|
+
|
343
|
+
@cache.servers = []
|
344
|
+
@cache.servers << server
|
345
|
+
|
346
|
+
assert_nothing_raised do
|
347
|
+
@cache.set 'a', 1
|
348
|
+
end
|
349
|
+
|
350
|
+
passed = true
|
351
|
+
Thread.new do
|
352
|
+
begin
|
353
|
+
@cache.set 'b', 2
|
354
|
+
passed = false
|
355
|
+
rescue MemCache::MemCacheError => me
|
356
|
+
passed = me.message =~ /multiple threads/
|
357
|
+
end
|
358
|
+
end
|
359
|
+
assert passed
|
360
|
+
end
|
361
|
+
|
336
362
|
def test_initialize
|
337
363
|
cache = MemCache.new :namespace => 'my_namespace', :readonly => true
|
338
364
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mperham-memcache-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Hodel
|
@@ -11,19 +11,10 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2009-02-
|
14
|
+
date: 2009-02-13 00:00:00 -08:00
|
15
15
|
default_executable:
|
16
|
-
dependencies:
|
17
|
-
|
18
|
-
name:
|
19
|
-
- RubyInline
|
20
|
-
version_requirement:
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
-
requirements:
|
23
|
-
- - ">="
|
24
|
-
- !ruby/object:Gem::Version
|
25
|
-
version: "0"
|
26
|
-
version:
|
16
|
+
dependencies: []
|
17
|
+
|
27
18
|
description: A Ruby library for accessing memcached.
|
28
19
|
email: mperham@gmail.com
|
29
20
|
executables: []
|
@@ -37,9 +28,7 @@ files:
|
|
37
28
|
- LICENSE.txt
|
38
29
|
- History.txt
|
39
30
|
- Rakefile
|
40
|
-
- lib/continuum.rb
|
41
31
|
- lib/memcache.rb
|
42
|
-
- lib/memcache_util.rb
|
43
32
|
has_rdoc: false
|
44
33
|
homepage: http://github.com/mperham/memcache-client
|
45
34
|
post_install_message:
|
data/lib/continuum.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
module Continuum
|
2
|
-
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
3
|
-
|
4
|
-
class << self
|
5
|
-
|
6
|
-
begin
|
7
|
-
require 'inline'
|
8
|
-
inline do |builder|
|
9
|
-
builder.c <<-EOM
|
10
|
-
int binary_search(VALUE ary, unsigned int r) {
|
11
|
-
int upper = RARRAY_LEN(ary) - 1;
|
12
|
-
int lower = 0;
|
13
|
-
int idx = 0;
|
14
|
-
ID value = rb_intern("value");
|
15
|
-
|
16
|
-
while (lower <= upper) {
|
17
|
-
idx = (lower + upper) / 2;
|
18
|
-
|
19
|
-
VALUE continuumValue = rb_funcall(RARRAY_PTR(ary)[idx], value, 0);
|
20
|
-
unsigned int l = NUM2UINT(continuumValue);
|
21
|
-
if (l == r) {
|
22
|
-
return idx;
|
23
|
-
}
|
24
|
-
else if (l > r) {
|
25
|
-
upper = idx - 1;
|
26
|
-
}
|
27
|
-
else {
|
28
|
-
lower = idx + 1;
|
29
|
-
}
|
30
|
-
}
|
31
|
-
return upper;
|
32
|
-
}
|
33
|
-
EOM
|
34
|
-
end
|
35
|
-
rescue Exception => e
|
36
|
-
puts "Unable to generate native code, falling back to Ruby: #{e.message}"
|
37
|
-
|
38
|
-
# slow but pure ruby version
|
39
|
-
# Find the closest index in Continuum with value <= the given value
|
40
|
-
def binary_search(ary, value, &block)
|
41
|
-
upper = ary.size - 1
|
42
|
-
lower = 0
|
43
|
-
idx = 0
|
44
|
-
|
45
|
-
while(lower <= upper) do
|
46
|
-
idx = (lower + upper) / 2
|
47
|
-
comp = ary[idx].value <=> value
|
48
|
-
|
49
|
-
if comp == 0
|
50
|
-
return idx
|
51
|
-
elsif comp > 0
|
52
|
-
upper = idx - 1
|
53
|
-
else
|
54
|
-
lower = idx + 1
|
55
|
-
end
|
56
|
-
end
|
57
|
-
return upper
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
class Entry
|
65
|
-
attr_reader :value
|
66
|
-
attr_reader :server
|
67
|
-
|
68
|
-
def initialize(val, srv)
|
69
|
-
@value = val
|
70
|
-
@server = srv
|
71
|
-
end
|
72
|
-
|
73
|
-
def inspect
|
74
|
-
"<#{value}, #{server.host}:#{server.port}>"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
data/lib/memcache_util.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# A utility wrapper around the MemCache client to simplify cache access. All
|
3
|
-
# methods silently ignore MemCache errors.
|
4
|
-
|
5
|
-
module Cache
|
6
|
-
|
7
|
-
##
|
8
|
-
# Try to return a logger object that does not rely
|
9
|
-
# on ActiveRecord for logging.
|
10
|
-
def self.logger
|
11
|
-
@logger ||= if defined? Rails.logger # Rails 2.1 +
|
12
|
-
Rails.logger
|
13
|
-
elsif defined? RAILS_DEFAULT_LOGGER # Rails 1.2.2 +
|
14
|
-
RAILS_DEFAULT_LOGGER
|
15
|
-
else
|
16
|
-
ActiveRecord::Base.logger # ... very old Rails.
|
17
|
-
end
|
18
|
-
end
|
19
|
-
##
|
20
|
-
# Returns the object at +key+ from the cache if successful, or nil if either
|
21
|
-
# the object is not in the cache or if there was an error attermpting to
|
22
|
-
# access the cache.
|
23
|
-
#
|
24
|
-
# If there is a cache miss and a block is given the result of the block will
|
25
|
-
# be stored in the cache with optional +expiry+, using the +add+ method rather
|
26
|
-
# than +set+.
|
27
|
-
|
28
|
-
def self.get(key, expiry = 0)
|
29
|
-
start_time = Time.now
|
30
|
-
value = CACHE.get key
|
31
|
-
elapsed = Time.now - start_time
|
32
|
-
logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
|
33
|
-
if value.nil? and block_given? then
|
34
|
-
value = yield
|
35
|
-
add key, value, expiry
|
36
|
-
end
|
37
|
-
value
|
38
|
-
rescue MemCache::MemCacheError => err
|
39
|
-
logger.debug "MemCache Error: #{err.message}"
|
40
|
-
if block_given? then
|
41
|
-
value = yield
|
42
|
-
put key, value, expiry
|
43
|
-
end
|
44
|
-
value
|
45
|
-
end
|
46
|
-
|
47
|
-
##
|
48
|
-
# Sets +value+ in the cache at +key+, with an optional +expiry+ time in
|
49
|
-
# seconds.
|
50
|
-
|
51
|
-
def self.put(key, value, expiry = 0)
|
52
|
-
start_time = Time.now
|
53
|
-
CACHE.set key, value, expiry
|
54
|
-
elapsed = Time.now - start_time
|
55
|
-
logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
|
56
|
-
value
|
57
|
-
rescue MemCache::MemCacheError => err
|
58
|
-
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
59
|
-
nil
|
60
|
-
end
|
61
|
-
|
62
|
-
##
|
63
|
-
# Sets +value+ in the cache at +key+, with an optional +expiry+ time in
|
64
|
-
# seconds. If +key+ already exists in cache, returns nil.
|
65
|
-
|
66
|
-
def self.add(key, value, expiry = 0)
|
67
|
-
start_time = Time.now
|
68
|
-
response = CACHE.add key, value, expiry
|
69
|
-
elapsed = Time.now - start_time
|
70
|
-
logger.debug('MemCache Add (%0.6f) %s' % [elapsed, key])
|
71
|
-
(response == "STORED\r\n") ? value : nil
|
72
|
-
rescue MemCache::MemCacheError => err
|
73
|
-
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
74
|
-
nil
|
75
|
-
end
|
76
|
-
|
77
|
-
##
|
78
|
-
# Deletes +key+ from the cache in +delay+ seconds.
|
79
|
-
|
80
|
-
def self.delete(key, delay = nil)
|
81
|
-
start_time = Time.now
|
82
|
-
CACHE.delete key, delay
|
83
|
-
elapsed = Time.now - start_time
|
84
|
-
logger.debug('MemCache Delete (%0.6f) %s' %
|
85
|
-
[elapsed, key])
|
86
|
-
nil
|
87
|
-
rescue MemCache::MemCacheError => err
|
88
|
-
logger.debug "MemCache Error: #{err.message}"
|
89
|
-
nil
|
90
|
-
end
|
91
|
-
|
92
|
-
##
|
93
|
-
# Resets all connections to MemCache servers.
|
94
|
-
|
95
|
-
def self.reset
|
96
|
-
CACHE.reset
|
97
|
-
logger.debug 'MemCache Connections Reset'
|
98
|
-
nil
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|