memcache-client 1.8.1 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|