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.
@@ -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