memcache-client 1.8.1 → 1.8.2
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.rdoc +4 -0
- data/lib/memcache.rb +8 -4
- data/lib/memcache/event_machine.rb +51 -27
- data/lib/memcache/version.rb +1 -1
- data/test/test_event_machine.rb +50 -2
- data/test/test_mem_cache.rb +1 -0
- metadata +3 -3
data/History.rdoc
CHANGED
data/lib/memcache.rb
CHANGED
@@ -110,7 +110,7 @@ class MemCache
|
|
110
110
|
# Please note this feature only works in memcached 1.2.5 and later. Earlier
|
111
111
|
# versions will reply with "ERROR".
|
112
112
|
attr_reader :no_reply
|
113
|
-
|
113
|
+
|
114
114
|
##
|
115
115
|
# Accepts a list of +servers+ and a list of +opts+. +servers+ may be
|
116
116
|
# omitted. See +servers=+ for acceptable server list arguments.
|
@@ -154,10 +154,11 @@ class MemCache
|
|
154
154
|
raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
|
155
155
|
end
|
156
156
|
|
157
|
+
@evented = defined?(EM) && EM.reactor_running?
|
157
158
|
opts = DEFAULT_OPTIONS.merge opts
|
158
159
|
@namespace = opts[:namespace]
|
159
160
|
@readonly = opts[:readonly]
|
160
|
-
@multithread = opts[:multithread]
|
161
|
+
@multithread = opts[:multithread] && !@evented
|
161
162
|
@autofix_keys = opts[:autofix_keys]
|
162
163
|
@timeout = opts[:timeout]
|
163
164
|
@failover = opts[:failover]
|
@@ -170,6 +171,7 @@ class MemCache
|
|
170
171
|
logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger
|
171
172
|
|
172
173
|
Thread.current[:memcache_client] = self.object_id if !@multithread
|
174
|
+
|
173
175
|
|
174
176
|
self.servers = servers
|
175
177
|
end
|
@@ -946,6 +948,7 @@ class MemCache
|
|
946
948
|
|
947
949
|
def check_multithread_status!
|
948
950
|
return if @multithread
|
951
|
+
return if @evented
|
949
952
|
|
950
953
|
if Thread.current[:memcache_client] != self.object_id
|
951
954
|
raise MemCacheError, <<-EOM
|
@@ -1011,6 +1014,8 @@ class MemCache
|
|
1011
1014
|
@status = 'NOT CONNECTED'
|
1012
1015
|
@timeout = memcache.timeout
|
1013
1016
|
@logger = memcache.logger
|
1017
|
+
|
1018
|
+
self.extend(MemCache::EventedServer) if defined?(EM) and EM.reactor_running?
|
1014
1019
|
end
|
1015
1020
|
|
1016
1021
|
##
|
@@ -1101,8 +1106,7 @@ class MemCache
|
|
1101
1106
|
# Mark the server as dead and close its socket.
|
1102
1107
|
|
1103
1108
|
def mark_dead(error)
|
1104
|
-
|
1105
|
-
@sock = nil
|
1109
|
+
close
|
1106
1110
|
@retry = Time.now + RETRY_DELAY
|
1107
1111
|
|
1108
1112
|
reason = "#{error.class.name}: #{error.message}"
|
@@ -2,42 +2,62 @@
|
|
2
2
|
|
3
3
|
raise "memcache/event_machine requires Ruby 1.9" if RUBY_VERSION < '1.9'
|
4
4
|
|
5
|
+
require 'memcache'
|
6
|
+
require 'eventmachine'
|
5
7
|
require 'fiber'
|
6
8
|
|
7
|
-
class MemCache
|
9
|
+
class MemCache
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# Support plain old TCP socket connections if the user
|
13
|
-
# has not setup EM. Much easier to deal with in irb,
|
14
|
-
# script/console, etc.
|
15
|
-
return blocking_socket if !EM.reactor_running?
|
11
|
+
# Since we are working in a single Thread, multiple Fiber environment,
|
12
|
+
# disable the multithread Mutex as it will not work.
|
13
|
+
# DEFAULT_OPTIONS[:multithread] = false
|
16
14
|
|
17
|
-
|
15
|
+
module EventedServer
|
18
16
|
|
19
|
-
|
17
|
+
def fiber_key
|
18
|
+
@fiber_key ||= "memcached-#{@host}-#{@port}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def socket
|
22
|
+
sock = Thread.current[fiber_key]
|
23
|
+
return sock if sock and not sock.closed?
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
Thread.current[fiber_key] = nil
|
26
|
+
|
27
|
+
# If the host was dead, don't retry for a while.
|
28
|
+
return if @retry and @retry > Time.now
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
Thread.current[fiber_key] ||= begin
|
31
|
+
sock = EM::SocketConnection.connect(@host, @port, @timeout)
|
32
|
+
yielding = true
|
33
|
+
fiber = Fiber.current
|
34
|
+
sock.callback do
|
35
|
+
@status = 'CONNECTED'
|
36
|
+
@retry = nil
|
37
|
+
yielding = false
|
38
|
+
fiber.resume if Fiber.current != fiber
|
39
|
+
end
|
40
|
+
sock.errback do
|
41
|
+
sock = nil
|
42
|
+
yielding = false
|
43
|
+
fiber.resume if Fiber.current != fiber
|
44
|
+
end
|
45
|
+
Fiber.yield if yielding
|
46
|
+
sock
|
47
|
+
end
|
32
48
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
|
50
|
+
def close
|
51
|
+
sock = Thread.current[fiber_key]
|
52
|
+
if sock
|
53
|
+
sock.close if !sock.closed?
|
54
|
+
Thread.current[fiber_key] = nil
|
55
|
+
end
|
56
|
+
@retry = nil
|
57
|
+
@status = "NOT CONNECTED"
|
36
58
|
end
|
37
|
-
|
38
|
-
@sock
|
59
|
+
|
39
60
|
end
|
40
|
-
|
41
61
|
end
|
42
62
|
|
43
63
|
module EM
|
@@ -127,7 +147,11 @@ module EM
|
|
127
147
|
end
|
128
148
|
|
129
149
|
def unbind
|
130
|
-
@connected
|
150
|
+
if @connected
|
151
|
+
@connected = false
|
152
|
+
else
|
153
|
+
fail
|
154
|
+
end
|
131
155
|
end
|
132
156
|
|
133
157
|
private
|
data/lib/memcache/version.rb
CHANGED
data/test/test_event_machine.rb
CHANGED
@@ -4,6 +4,52 @@ require 'memcache'
|
|
4
4
|
|
5
5
|
class TestEventMachine < Test::Unit::TestCase
|
6
6
|
|
7
|
+
def test_concurrent_fibers
|
8
|
+
return puts("Skipping EventMachine test, not Ruby 1.9") if RUBY_VERSION < '1.9'
|
9
|
+
return puts("Skipping EventMachine test, no live server") if !live_server?
|
10
|
+
|
11
|
+
require 'eventmachine'
|
12
|
+
require 'memcache/event_machine'
|
13
|
+
ex = nil
|
14
|
+
m = MemCache.new(['127.0.0.1:11211', 'localhost:11211'])
|
15
|
+
within_em(3) do
|
16
|
+
begin
|
17
|
+
key1 = 'foo'
|
18
|
+
key2 = 'bar'*50
|
19
|
+
key3 = '£∞'*45
|
20
|
+
value1 = 'abc'
|
21
|
+
value2 = 'xyz'*1000
|
22
|
+
value3 = '∞§¶•ª'*1000
|
23
|
+
|
24
|
+
100.times do
|
25
|
+
assert_equal "STORED\r\n", m.set(key1, value1)
|
26
|
+
assert_equal "STORED\r\n", m.set(key2, value2)
|
27
|
+
assert_equal "STORED\r\n", m.set(key3, value3)
|
28
|
+
m.get(key1)
|
29
|
+
m.get(key2)
|
30
|
+
m.get(key3)
|
31
|
+
assert m.delete(key1)
|
32
|
+
assert_equal "STORED\r\n", m.set(key1, value2)
|
33
|
+
m.get(key1)
|
34
|
+
assert_equal "STORED\r\n", m.set(key2, value3)
|
35
|
+
m.get(key2)
|
36
|
+
assert_equal "STORED\r\n", m.set(key3, value1)
|
37
|
+
m.get(key3)
|
38
|
+
h = m.get_multi(key1, key2, key3)
|
39
|
+
assert h
|
40
|
+
assert_equal Hash, h.class
|
41
|
+
assert h.size > 0
|
42
|
+
end
|
43
|
+
rescue Exception => exp
|
44
|
+
puts exp.message
|
45
|
+
ex = exp
|
46
|
+
ensure
|
47
|
+
EM.stop
|
48
|
+
end
|
49
|
+
end
|
50
|
+
raise ex if ex
|
51
|
+
end
|
52
|
+
|
7
53
|
def test_live_server
|
8
54
|
return puts("Skipping EventMachine test, not Ruby 1.9") if RUBY_VERSION < '1.9'
|
9
55
|
return puts("Skipping EventMachine test, no live server") if !live_server?
|
@@ -50,9 +96,11 @@ class TestEventMachine < Test::Unit::TestCase
|
|
50
96
|
|
51
97
|
private
|
52
98
|
|
53
|
-
def within_em(&block)
|
99
|
+
def within_em(count=1, &block)
|
54
100
|
EM.run do
|
55
|
-
|
101
|
+
count.times do
|
102
|
+
Fiber.new(&block).resume
|
103
|
+
end
|
56
104
|
end
|
57
105
|
end
|
58
106
|
|
data/test/test_mem_cache.rb
CHANGED
@@ -1201,6 +1201,7 @@ class TestMemCache < Test::Unit::TestCase
|
|
1201
1201
|
# Use a null logger to verify logging doesn't blow up at runtime
|
1202
1202
|
cache = MemCache.new(['localhost:11211', '127.0.0.1:11211'], :logger => Logger.new('/dev/null'))
|
1203
1203
|
cache.flush_all
|
1204
|
+
assert_equal true, cache.multithread
|
1204
1205
|
workers = []
|
1205
1206
|
|
1206
1207
|
cache.set('f', 'zzz')
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 8
|
8
|
-
-
|
9
|
-
version: 1.8.
|
8
|
+
- 2
|
9
|
+
version: 1.8.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Eric Hodel
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-03
|
19
|
+
date: 2010-04-03 00:00:00 -05:00
|
20
20
|
default_executable: memcached_top
|
21
21
|
dependencies: []
|
22
22
|
|