redis 2.0.0.rc1 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  class Redis
4
- VERSION = "2.0.0.rc1"
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.call_blocking(:blpop, key, timeout)
149
+ @client.call_without_timeout(:blpop, key, timeout)
150
150
  end
151
151
 
152
152
  def brpop(key, timeout)
153
- @client.call_blocking(:brpop, key, timeout)
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 @client.kind_of?(SubscribedClient)
435
- @client = @client.unsubscribe(*channels)
436
- else
437
- @client.call(:unsubscribe, *channels)
438
- end
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
- if @client.kind_of?(SubscribedClient)
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
- if @client.kind_of?(SubscribedClient)
456
- @client.call(:psubscribe, *channels)
457
- else
458
- begin
459
- original, @client = @client, SubscribedClient.new(@client)
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
@@ -8,7 +8,8 @@ class Redis
8
8
  DOLLAR = "$".freeze
9
9
  ASTERISK = "*".freeze
10
10
 
11
- attr_accessor :db, :host, :port, :password, :timeout, :logger
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 call(name, *args)
32
- ensure_connected do
33
- process_and_read([[name, *args]]).first
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 call_async(name, *args)
38
- ensure_connected do
39
- process([[name, *args]])
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
- ensure_connected do
45
- process_and_read(commands)
49
+ process(*commands) do
50
+ Array.new(commands.size) { read }
46
51
  end
47
52
  end
48
53
 
49
- def call_blocking(name, *args)
50
- ensure_connected do
51
- without_socket_timeout do
52
- call(name, *args)
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 && connect
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
- begin
98
- self.timeout = 0
99
- yield
100
- ensure
101
- self.timeout = @timeout
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|
@@ -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.to_s)
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
- raise CannotDistribute, :rename
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
- raise CannotDistribute, :renamenx
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
- raise CannotDistribute, :rpoplpush
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
- raise CannotDistribute, :smove
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
- raise CannotDistribute, :sinter
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
- raise CannotDistribute, :sinterstore
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
- raise CannotDistribute, :sunion
269
+ ensure_same_node(:sunion, *keys) do |node|
270
+ node.sunion(*keys)
271
+ end
262
272
  end
263
273
 
264
- def sunionstore(*keys)
265
- raise CannotDistribute, :sunionstore
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
- raise CannotDistribute, :sdiff
281
+ ensure_same_node(:sdiff, *keys) do |node|
282
+ node.sdiff(*keys)
283
+ end
270
284
  end
271
285
 
272
- def sdiffstore(*keys)
273
- raise CannotDistribute, :sdiffstore
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
- if with_scores
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
- if with_scores
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
- raise CannotDistribute, :sort
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
@@ -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.to_s == node.to_s}
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
@@ -4,51 +4,41 @@ class Redis
4
4
  @client = client
5
5
  end
6
6
 
7
- def call(command, *args)
8
- @client.call_async(command, *args)
7
+ def call(*args)
8
+ @client.process(args)
9
9
  end
10
10
 
11
11
  def subscribe(*channels, &block)
12
- @client.call_async(:subscribe, *channels)
13
-
14
- sub = Subscription.new(&block)
12
+ subscription("subscribe", "unsubscribe", channels, block)
13
+ end
15
14
 
16
- begin
17
- loop do
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
- @client.call_async(:unsubscribe, *channels)
29
- @client
20
+ call(:unsubscribe, *channels)
30
21
  end
31
22
 
32
- def psubscribe(*channels, &block)
33
- @client.call_async(:psubscribe, *channels)
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
- loop do
39
- type, pattern, channel, message = @client.read
40
- sub.callbacks[type].call(pattern, channel, message)
41
- break if type == "punsubscribe" && channel == 0
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
- @client.call_async(:punsubscribe)
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
- - rc1
10
- version: 2.0.0.rc1
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-26 00:00:00 -03:00
23
+ date: 2010-04-28 00:00:00 -03:00
24
24
  default_executable:
25
25
  dependencies: []
26
26