redis 2.0.0.rc1 → 2.0.0.rc2
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/lib/redis.rb +31 -28
- data/lib/redis/client.rb +37 -36
- data/lib/redis/distributed.rb +53 -29
- data/lib/redis/hash_ring.rb +3 -3
- data/lib/redis/subscribe.rb +18 -28
- metadata +3 -3
data/lib/redis.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
3
|
class Redis
|
4
|
-
VERSION = "2.0.0.
|
4
|
+
VERSION = "2.0.0.rc2"
|
5
5
|
|
6
6
|
class ProtocolError < RuntimeError
|
7
7
|
def initialize(reply_type)
|
@@ -146,11 +146,11 @@ class Redis
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def blpop(key, timeout)
|
149
|
-
@client.
|
149
|
+
@client.call_without_timeout(:blpop, key, timeout)
|
150
150
|
end
|
151
151
|
|
152
152
|
def brpop(key, timeout)
|
153
|
-
@client.
|
153
|
+
@client.call_without_timeout(:brpop, key, timeout)
|
154
154
|
end
|
155
155
|
|
156
156
|
def rpoplpush(source, destination)
|
@@ -430,38 +430,30 @@ class Redis
|
|
430
430
|
@client.call(:publish, channel, message)
|
431
431
|
end
|
432
432
|
|
433
|
+
def subscribed?
|
434
|
+
@client.kind_of? SubscribedClient
|
435
|
+
end
|
436
|
+
|
433
437
|
def unsubscribe(*channels)
|
434
|
-
if
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
438
|
+
raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
|
439
|
+
@client.unsubscribe(*channels)
|
440
|
+
end
|
441
|
+
|
442
|
+
def punsubscribe(*channels)
|
443
|
+
raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
|
444
|
+
@client.punsubscribe(*channels)
|
439
445
|
end
|
440
446
|
|
441
447
|
def subscribe(*channels, &block)
|
442
|
-
|
443
|
-
@client.call(:subscribe, *channels)
|
444
|
-
else
|
445
|
-
begin
|
446
|
-
original, @client = @client, SubscribedClient.new(@client)
|
447
|
-
@client.subscribe(*channels, &block)
|
448
|
-
ensure
|
449
|
-
@client = original
|
450
|
-
end
|
451
|
-
end
|
448
|
+
subscription(:subscribe, channels, block)
|
452
449
|
end
|
453
450
|
|
454
451
|
def psubscribe(*channels, &block)
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
@client.psubscribe(*channels, &block)
|
461
|
-
ensure
|
462
|
-
@client = original
|
463
|
-
end
|
464
|
-
end
|
452
|
+
subscription(:psubscribe, channels, block)
|
453
|
+
end
|
454
|
+
|
455
|
+
def id
|
456
|
+
@client.id
|
465
457
|
end
|
466
458
|
|
467
459
|
def method_missing(command, *args)
|
@@ -474,6 +466,17 @@ private
|
|
474
466
|
value == 1
|
475
467
|
end
|
476
468
|
|
469
|
+
def subscription(method, channels, block)
|
470
|
+
return @client.call(method, *channels) if subscribed?
|
471
|
+
|
472
|
+
begin
|
473
|
+
original, @client = @client, SubscribedClient.new(@client)
|
474
|
+
@client.send(method, *channels, &block)
|
475
|
+
ensure
|
476
|
+
@client = original
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
477
480
|
end
|
478
481
|
|
479
482
|
begin
|
data/lib/redis/client.rb
CHANGED
@@ -8,7 +8,8 @@ class Redis
|
|
8
8
|
DOLLAR = "$".freeze
|
9
9
|
ASTERISK = "*".freeze
|
10
10
|
|
11
|
-
attr_accessor :db, :host, :port, :password, :
|
11
|
+
attr_accessor :db, :host, :port, :password, :logger
|
12
|
+
attr :timeout
|
12
13
|
|
13
14
|
def initialize(options = {})
|
14
15
|
@host = options[:host] || "127.0.0.1"
|
@@ -28,28 +29,39 @@ class Redis
|
|
28
29
|
@sock
|
29
30
|
end
|
30
31
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
32
|
+
def id
|
33
|
+
"redis://#{host}:#{port}/#{db}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def call(*args)
|
37
|
+
process(args) do
|
38
|
+
read
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
42
|
+
def call_loop(*args)
|
43
|
+
process(args) do
|
44
|
+
loop { yield(read) }
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
48
|
def call_pipelined(commands)
|
44
|
-
|
45
|
-
|
49
|
+
process(*commands) do
|
50
|
+
Array.new(commands.size) { read }
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
def call_without_timeout(*args)
|
55
|
+
without_socket_timeout do
|
56
|
+
call(*args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def process(*commands)
|
61
|
+
logging(commands) do
|
62
|
+
ensure_connected do
|
63
|
+
@sock.write(join_commands(commands))
|
64
|
+
yield if block_given?
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
@@ -59,17 +71,19 @@ class Redis
|
|
59
71
|
end
|
60
72
|
|
61
73
|
def disconnect
|
74
|
+
return unless connected?
|
75
|
+
|
62
76
|
begin
|
63
77
|
@sock.close
|
64
78
|
rescue
|
65
79
|
ensure
|
66
80
|
@sock = nil
|
67
81
|
end
|
68
|
-
true
|
69
82
|
end
|
70
83
|
|
71
84
|
def reconnect
|
72
|
-
disconnect
|
85
|
+
disconnect
|
86
|
+
connect
|
73
87
|
end
|
74
88
|
|
75
89
|
def read
|
@@ -94,11 +108,13 @@ class Redis
|
|
94
108
|
end
|
95
109
|
|
96
110
|
def without_socket_timeout
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
111
|
+
ensure_connected do
|
112
|
+
begin
|
113
|
+
self.timeout = 0
|
114
|
+
yield
|
115
|
+
ensure
|
116
|
+
self.timeout = @timeout
|
117
|
+
end
|
102
118
|
end
|
103
119
|
end
|
104
120
|
|
@@ -127,27 +143,12 @@ class Redis
|
|
127
143
|
|
128
144
|
COMMAND_DELIMITER = "\r\n"
|
129
145
|
|
130
|
-
def process(commands)
|
131
|
-
logging(commands) do
|
132
|
-
@sock.write(join_commands(commands))
|
133
|
-
yield if block_given?
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
146
|
def join_commands(commands)
|
138
147
|
commands.map do |command|
|
139
148
|
build_command(*command).join(COMMAND_DELIMITER) + COMMAND_DELIMITER
|
140
149
|
end.join(COMMAND_DELIMITER) + COMMAND_DELIMITER
|
141
150
|
end
|
142
151
|
|
143
|
-
def process_and_read(commands)
|
144
|
-
process(commands) do
|
145
|
-
@mutex.synchronize do
|
146
|
-
Array.new(commands.size).map { read }
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
152
|
if "".respond_to?(:bytesize)
|
152
153
|
def string_size(string)
|
153
154
|
string.to_s.bytesize
|
@@ -196,7 +197,7 @@ class Redis
|
|
196
197
|
end
|
197
198
|
|
198
199
|
def logging(commands)
|
199
|
-
return yield unless @logger
|
200
|
+
return yield unless @logger && @logger.debug?
|
200
201
|
|
201
202
|
begin
|
202
203
|
commands.each do |name, *args|
|
data/lib/redis/distributed.rb
CHANGED
@@ -16,12 +16,13 @@ class Redis
|
|
16
16
|
attr_reader :ring
|
17
17
|
|
18
18
|
def initialize(urls, options = {})
|
19
|
+
@tag = options.delete(:tag) || /^{(.+?)}/
|
19
20
|
@default_options = options
|
20
21
|
@ring = HashRing.new urls.map { |url| Redis.connect(options.merge(:url => url)) }
|
21
22
|
end
|
22
23
|
|
23
24
|
def node_for(key)
|
24
|
-
@ring.get_node(key
|
25
|
+
@ring.get_node(key_tag(key) || key)
|
25
26
|
end
|
26
27
|
|
27
28
|
def nodes
|
@@ -34,7 +35,6 @@ class Redis
|
|
34
35
|
|
35
36
|
def quit
|
36
37
|
on_each_node :quit
|
37
|
-
rescue Errno::ECONNRESET
|
38
38
|
end
|
39
39
|
|
40
40
|
def select(db)
|
@@ -45,10 +45,6 @@ class Redis
|
|
45
45
|
on_each_node :ping
|
46
46
|
end
|
47
47
|
|
48
|
-
def quit
|
49
|
-
on_each_node :quit
|
50
|
-
end
|
51
|
-
|
52
48
|
def flushall
|
53
49
|
on_each_node :flushall
|
54
50
|
end
|
@@ -74,11 +70,15 @@ class Redis
|
|
74
70
|
end
|
75
71
|
|
76
72
|
def rename(old_name, new_name)
|
77
|
-
|
73
|
+
ensure_same_node(:rename, old_name, new_name) do |node|
|
74
|
+
node.rename(old_name, new_name)
|
75
|
+
end
|
78
76
|
end
|
79
77
|
|
80
78
|
def renamenx(old_name, new_name)
|
81
|
-
|
79
|
+
ensure_same_node(:renamenx, old_name, new_name) do |node|
|
80
|
+
node.renamenx(old_name, new_name)
|
81
|
+
end
|
82
82
|
end
|
83
83
|
|
84
84
|
def dbsize
|
@@ -214,7 +214,9 @@ class Redis
|
|
214
214
|
end
|
215
215
|
|
216
216
|
def rpoplpush(source, destination)
|
217
|
-
|
217
|
+
ensure_same_node(:rpoplpush, source, destination) do |node|
|
218
|
+
node.rpoplpush(source, destination)
|
219
|
+
end
|
218
220
|
end
|
219
221
|
|
220
222
|
def blpop(key, timeout)
|
@@ -238,7 +240,9 @@ class Redis
|
|
238
240
|
end
|
239
241
|
|
240
242
|
def smove(source, destination, member)
|
241
|
-
|
243
|
+
ensure_same_node(:smove, source, destination, member) do |node|
|
244
|
+
node.smove(source, destination, member)
|
245
|
+
end
|
242
246
|
end
|
243
247
|
|
244
248
|
def scard(key)
|
@@ -250,27 +254,39 @@ class Redis
|
|
250
254
|
end
|
251
255
|
|
252
256
|
def sinter(*keys)
|
253
|
-
|
257
|
+
ensure_same_node(:sinter, *keys) do |node|
|
258
|
+
node.sinter(*keys)
|
259
|
+
end
|
254
260
|
end
|
255
261
|
|
256
262
|
def sinterstore(destination, *keys)
|
257
|
-
|
263
|
+
ensure_same_node(:sinterstore, destination, *keys) do |node|
|
264
|
+
node.sinterstore(destination, *keys)
|
265
|
+
end
|
258
266
|
end
|
259
267
|
|
260
268
|
def sunion(*keys)
|
261
|
-
|
269
|
+
ensure_same_node(:sunion, *keys) do |node|
|
270
|
+
node.sunion(*keys)
|
271
|
+
end
|
262
272
|
end
|
263
273
|
|
264
|
-
def sunionstore(*keys)
|
265
|
-
|
274
|
+
def sunionstore(destination, *keys)
|
275
|
+
ensure_same_node(:sunionstore, destination, *keys) do |node|
|
276
|
+
node.sunionstore(destination, *keys)
|
277
|
+
end
|
266
278
|
end
|
267
279
|
|
268
280
|
def sdiff(*keys)
|
269
|
-
|
281
|
+
ensure_same_node(:sdiff, *keys) do |node|
|
282
|
+
node.sdiff(*keys)
|
283
|
+
end
|
270
284
|
end
|
271
285
|
|
272
|
-
def sdiffstore(*keys)
|
273
|
-
|
286
|
+
def sdiffstore(destination, *keys)
|
287
|
+
ensure_same_node(:sdiffstore, destination, *keys) do |node|
|
288
|
+
node.sdiffstore(destination, *keys)
|
289
|
+
end
|
274
290
|
end
|
275
291
|
|
276
292
|
def smembers(key)
|
@@ -294,19 +310,11 @@ class Redis
|
|
294
310
|
end
|
295
311
|
|
296
312
|
def zrange(key, start, stop, with_scores = false)
|
297
|
-
|
298
|
-
node_for(key).zrange(key, start, stop, "WITHSCORES")
|
299
|
-
else
|
300
|
-
node_for(key).zrange(key, start, stop)
|
301
|
-
end
|
313
|
+
node_for(key).zrange(key, start, stop, with_scores)
|
302
314
|
end
|
303
315
|
|
304
316
|
def zrevrange(key, start, stop, with_scores = false)
|
305
|
-
|
306
|
-
node_for(key).zrevrange(key, start, stop, "WITHSCORES")
|
307
|
-
else
|
308
|
-
node_for(key).zrevrange(key, start, stop)
|
309
|
-
end
|
317
|
+
node_for(key).zrevrange(key, start, stop, with_scores)
|
310
318
|
end
|
311
319
|
|
312
320
|
def zrangebyscore(key, min, max)
|
@@ -358,7 +366,11 @@ class Redis
|
|
358
366
|
end
|
359
367
|
|
360
368
|
def sort(key, options = {})
|
361
|
-
|
369
|
+
keys = [key, options[:by], options[:store], *Array(options[:get])].compact
|
370
|
+
|
371
|
+
ensure_same_node(:sort, *keys) do |node|
|
372
|
+
node.sort(key, options)
|
373
|
+
end
|
362
374
|
end
|
363
375
|
|
364
376
|
def multi(&block)
|
@@ -432,5 +444,17 @@ class Redis
|
|
432
444
|
def node_index_for(key)
|
433
445
|
nodes.index(node_for(key))
|
434
446
|
end
|
447
|
+
|
448
|
+
def key_tag(key)
|
449
|
+
key[@tag, 1] if @tag
|
450
|
+
end
|
451
|
+
|
452
|
+
def ensure_same_node(command, *keys)
|
453
|
+
tags = keys.map { |key| key_tag(key) }
|
454
|
+
|
455
|
+
raise CannotDistribute, command if tags.compact.uniq.size != 1
|
456
|
+
|
457
|
+
yield(node_for(keys.first))
|
458
|
+
end
|
435
459
|
end
|
436
460
|
end
|
data/lib/redis/hash_ring.rb
CHANGED
@@ -24,7 +24,7 @@ class Redis
|
|
24
24
|
def add_node(node)
|
25
25
|
@nodes << node
|
26
26
|
@replicas.times do |i|
|
27
|
-
key = Zlib.crc32("#{node}:#{i}")
|
27
|
+
key = Zlib.crc32("#{node.id}:#{i}")
|
28
28
|
@ring[key] = node
|
29
29
|
@sorted_keys << key
|
30
30
|
end
|
@@ -32,9 +32,9 @@ class Redis
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def remove_node(node)
|
35
|
-
@nodes.reject!{|n| n.
|
35
|
+
@nodes.reject!{|n| n.id == node.id}
|
36
36
|
@replicas.times do |i|
|
37
|
-
key = Zlib.crc32("#{node}:#{i}")
|
37
|
+
key = Zlib.crc32("#{node.id}:#{i}")
|
38
38
|
@ring.delete(key)
|
39
39
|
@sorted_keys.reject! {|k| k == key}
|
40
40
|
end
|
data/lib/redis/subscribe.rb
CHANGED
@@ -4,51 +4,41 @@ class Redis
|
|
4
4
|
@client = client
|
5
5
|
end
|
6
6
|
|
7
|
-
def call(
|
8
|
-
@client.
|
7
|
+
def call(*args)
|
8
|
+
@client.process(args)
|
9
9
|
end
|
10
10
|
|
11
11
|
def subscribe(*channels, &block)
|
12
|
-
|
13
|
-
|
14
|
-
sub = Subscription.new(&block)
|
12
|
+
subscription("subscribe", "unsubscribe", channels, block)
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
type, channel, message = @client.read
|
19
|
-
sub.callbacks[type].call(channel, message)
|
20
|
-
break if type == "unsubscribe" && message == 0
|
21
|
-
end
|
22
|
-
ensure
|
23
|
-
@client.call_async(:unsubscribe)
|
24
|
-
end
|
15
|
+
def psubscribe(*channels, &block)
|
16
|
+
subscription("psubscribe", "punsubscribe", channels, block)
|
25
17
|
end
|
26
18
|
|
27
19
|
def unsubscribe(*channels)
|
28
|
-
|
29
|
-
@client
|
20
|
+
call(:unsubscribe, *channels)
|
30
21
|
end
|
31
22
|
|
32
|
-
def
|
33
|
-
|
23
|
+
def punsubscribe(*channels)
|
24
|
+
call(:punsubscribe, *channels)
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
34
28
|
|
29
|
+
def subscription(start, stop, channels, block)
|
35
30
|
sub = Subscription.new(&block)
|
36
31
|
|
37
32
|
begin
|
38
|
-
|
39
|
-
type,
|
40
|
-
sub.callbacks[type].call(
|
41
|
-
break if type ==
|
33
|
+
@client.call_loop(start, *channels) do |line|
|
34
|
+
type, *rest = line
|
35
|
+
sub.callbacks[type].call(*rest)
|
36
|
+
break if type == stop && rest.last == 0
|
42
37
|
end
|
43
38
|
ensure
|
44
|
-
|
39
|
+
send(stop)
|
45
40
|
end
|
46
41
|
end
|
47
|
-
|
48
|
-
def punsubscribe(*channels)
|
49
|
-
@client.call_async(:punsubscribe, *channels)
|
50
|
-
@client
|
51
|
-
end
|
52
42
|
end
|
53
43
|
|
54
44
|
class Subscription
|
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 2
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 2.0.0.
|
9
|
+
- rc2
|
10
|
+
version: 2.0.0.rc2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ezra Zygmuntowicz
|
@@ -20,7 +20,7 @@ autorequire: redis
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2010-04-
|
23
|
+
date: 2010-04-28 00:00:00 -03:00
|
24
24
|
default_executable:
|
25
25
|
dependencies: []
|
26
26
|
|