redis 4.1.4 → 4.2.5

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,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "hash_ring"
3
4
 
4
5
  class Redis
5
6
  class Distributed
6
-
7
7
  class CannotDistribute < RuntimeError
8
8
  def initialize(command)
9
9
  @command = command
10
10
  end
11
11
 
12
12
  def message
13
- "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic."
13
+ "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
14
+ "to be on the same server or because we cannot guarantee that the operation will be atomic."
14
15
  end
15
16
  end
16
17
 
@@ -23,10 +24,14 @@ class Redis
23
24
  @default_options = options.dup
24
25
  node_configs.each { |node_config| add_node(node_config) }
25
26
  @subscribed_node = nil
27
+ @watch_key = nil
26
28
  end
27
29
 
28
30
  def node_for(key)
29
- @ring.get_node(key_tag(key.to_s) || key.to_s)
31
+ key = key_tag(key.to_s) || key.to_s
32
+ raise CannotDistribute, :watch if @watch_key && @watch_key != key
33
+
34
+ @ring.get_node(key)
30
35
  end
31
36
 
32
37
  def nodes
@@ -34,9 +39,9 @@ class Redis
34
39
  end
35
40
 
36
41
  def add_node(options)
37
- options = { :url => options } if options.is_a?(String)
42
+ options = { url: options } if options.is_a?(String)
38
43
  options = @default_options.merge(options)
39
- @ring.add_node Redis.new( options )
44
+ @ring.add_node Redis.new(options)
40
45
  end
41
46
 
42
47
  # Change the selected database for the current connection.
@@ -145,12 +150,12 @@ class Redis
145
150
  end
146
151
 
147
152
  # Create a key using the serialized value, previously obtained using DUMP.
148
- def restore(key, ttl, serialized_value, options = {})
149
- node_for(key).restore(key, ttl, serialized_value, options)
153
+ def restore(key, ttl, serialized_value, **options)
154
+ node_for(key).restore(key, ttl, serialized_value, **options)
150
155
  end
151
156
 
152
157
  # Transfer a key from the connected instance to another instance.
153
- def migrate(key, options)
158
+ def migrate(_key, _options)
154
159
  raise CannotDistribute, :migrate
155
160
  end
156
161
 
@@ -171,8 +176,33 @@ class Redis
171
176
  end
172
177
 
173
178
  # Determine if a key exists.
174
- def exists(key)
175
- node_for(key).exists(key)
179
+ def exists(*args)
180
+ if !Redis.exists_returns_integer && args.size == 1
181
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
182
+ "use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
183
+ "(#{::Kernel.caller(1, 1).first})\n"
184
+
185
+ if defined?(::Warning)
186
+ ::Warning.warn(message)
187
+ else
188
+ warn(message)
189
+ end
190
+ exists?(*args)
191
+ else
192
+ keys_per_node = args.group_by { |key| node_for(key) }
193
+ keys_per_node.inject(0) do |sum, (node, keys)|
194
+ sum + node._exists(*keys)
195
+ end
196
+ end
197
+ end
198
+
199
+ # Determine if any of the keys exists.
200
+ def exists?(*args)
201
+ keys_per_node = args.group_by { |key| node_for(key) }
202
+ keys_per_node.each do |node, keys|
203
+ return true if node.exists?(*keys)
204
+ end
205
+ false
176
206
  end
177
207
 
178
208
  # Find all keys matching the given pattern.
@@ -205,11 +235,11 @@ class Redis
205
235
  end
206
236
 
207
237
  # Sort the elements in a list, set or sorted set.
208
- def sort(key, options = {})
238
+ def sort(key, **options)
209
239
  keys = [key, options[:by], options[:store], *Array(options[:get])].compact
210
240
 
211
241
  ensure_same_node(:sort, keys) do |node|
212
- node.sort(key, options)
242
+ node.sort(key, **options)
213
243
  end
214
244
  end
215
245
 
@@ -244,8 +274,8 @@ class Redis
244
274
  end
245
275
 
246
276
  # Set the string value of a key.
247
- def set(key, value, options = {})
248
- node_for(key).set(key, value, options)
277
+ def set(key, value, **options)
278
+ node_for(key).set(key, value, **options)
249
279
  end
250
280
 
251
281
  # Set the time to live in seconds of a key.
@@ -264,20 +294,20 @@ class Redis
264
294
  end
265
295
 
266
296
  # Set multiple keys to multiple values.
267
- def mset(*args)
297
+ def mset(*_args)
268
298
  raise CannotDistribute, :mset
269
299
  end
270
300
 
271
- def mapped_mset(hash)
301
+ def mapped_mset(_hash)
272
302
  raise CannotDistribute, :mapped_mset
273
303
  end
274
304
 
275
305
  # Set multiple keys to multiple values, only if none of the keys exist.
276
- def msetnx(*args)
306
+ def msetnx(*_args)
277
307
  raise CannotDistribute, :msetnx
278
308
  end
279
309
 
280
- def mapped_msetnx(hash)
310
+ def mapped_msetnx(_hash)
281
311
  raise CannotDistribute, :mapped_msetnx
282
312
  end
283
313
 
@@ -336,7 +366,7 @@ class Redis
336
366
  end
337
367
 
338
368
  # Return the position of the first bit set to 1 or 0 in a string.
339
- def bitpos(key, bit, start=nil, stop=nil)
369
+ def bitpos(key, bit, start = nil, stop = nil)
340
370
  node_for(key).bitpos(key, bit, start, stop)
341
371
  end
342
372
 
@@ -354,7 +384,7 @@ class Redis
354
384
  get(key)
355
385
  end
356
386
 
357
- def []=(key,value)
387
+ def []=(key, value)
358
388
  set(key, value)
359
389
  end
360
390
 
@@ -439,15 +469,9 @@ class Redis
439
469
 
440
470
  # Pop a value from a list, push it to another list and return it; or block
441
471
  # until one is available.
442
- def brpoplpush(source, destination, options = {})
443
- case options
444
- when Integer
445
- # Issue deprecation notice in obnoxious mode...
446
- options = { :timeout => options }
447
- end
448
-
472
+ def brpoplpush(source, destination, deprecated_timeout = 0, **options)
449
473
  ensure_same_node(:brpoplpush, [source, destination]) do |node|
450
- node.brpoplpush(source, destination, options)
474
+ node.brpoplpush(source, destination, deprecated_timeout, **options)
451
475
  end
452
476
  end
453
477
 
@@ -524,13 +548,13 @@ class Redis
524
548
  end
525
549
 
526
550
  # Scan a set
527
- def sscan(key, cursor, options={})
528
- node_for(key).sscan(key, cursor, options)
551
+ def sscan(key, cursor, **options)
552
+ node_for(key).sscan(key, cursor, **options)
529
553
  end
530
554
 
531
555
  # Scan a set and return an enumerator
532
- def sscan_each(key, options={}, &block)
533
- node_for(key).sscan_each(key, options, &block)
556
+ def sscan_each(key, **options, &block)
557
+ node_for(key).sscan_each(key, **options, &block)
534
558
  end
535
559
 
536
560
  # Subtract multiple sets.
@@ -585,6 +609,7 @@ class Redis
585
609
  def zadd(key, *args)
586
610
  node_for(key).zadd(key, *args)
587
611
  end
612
+ ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
588
613
 
589
614
  # Increment the score of a member in a sorted set.
590
615
  def zincrby(key, increment, member)
@@ -602,14 +627,14 @@ class Redis
602
627
  end
603
628
 
604
629
  # Return a range of members in a sorted set, by index.
605
- def zrange(key, start, stop, options = {})
606
- node_for(key).zrange(key, start, stop, options)
630
+ def zrange(key, start, stop, **options)
631
+ node_for(key).zrange(key, start, stop, **options)
607
632
  end
608
633
 
609
634
  # Return a range of members in a sorted set, by index, with scores ordered
610
635
  # from high to low.
611
- def zrevrange(key, start, stop, options = {})
612
- node_for(key).zrevrange(key, start, stop, options)
636
+ def zrevrange(key, start, stop, **options)
637
+ node_for(key).zrevrange(key, start, stop, **options)
613
638
  end
614
639
 
615
640
  # Determine the index of a member in a sorted set.
@@ -629,14 +654,14 @@ class Redis
629
654
  end
630
655
 
631
656
  # Return a range of members in a sorted set, by score.
632
- def zrangebyscore(key, min, max, options = {})
633
- node_for(key).zrangebyscore(key, min, max, options)
657
+ def zrangebyscore(key, min, max, **options)
658
+ node_for(key).zrangebyscore(key, min, max, **options)
634
659
  end
635
660
 
636
661
  # Return a range of members in a sorted set, by score, with scores ordered
637
662
  # from high to low.
638
- def zrevrangebyscore(key, max, min, options = {})
639
- node_for(key).zrevrangebyscore(key, max, min, options)
663
+ def zrevrangebyscore(key, max, min, **options)
664
+ node_for(key).zrevrangebyscore(key, max, min, **options)
640
665
  end
641
666
 
642
667
  # Remove all members in a sorted set within the given scores.
@@ -651,16 +676,16 @@ class Redis
651
676
 
652
677
  # Intersect multiple sorted sets and store the resulting sorted set in a new
653
678
  # key.
654
- def zinterstore(destination, keys, options = {})
679
+ def zinterstore(destination, keys, **options)
655
680
  ensure_same_node(:zinterstore, [destination] + keys) do |node|
656
- node.zinterstore(destination, keys, options)
681
+ node.zinterstore(destination, keys, **options)
657
682
  end
658
683
  end
659
684
 
660
685
  # Add multiple sorted sets and store the resulting sorted set in a new key.
661
- def zunionstore(destination, keys, options = {})
686
+ def zunionstore(destination, keys, **options)
662
687
  ensure_same_node(:zunionstore, [destination] + keys) do |node|
663
- node.zunionstore(destination, keys, options)
688
+ node.zunionstore(destination, keys, **options)
664
689
  end
665
690
  end
666
691
 
@@ -669,9 +694,9 @@ class Redis
669
694
  node_for(key).hlen(key)
670
695
  end
671
696
 
672
- # Set the string value of a hash field.
673
- def hset(key, field, value)
674
- node_for(key).hset(key, field, value)
697
+ # Set multiple hash fields to multiple values.
698
+ def hset(key, *attrs)
699
+ node_for(key).hset(key, *attrs)
675
700
  end
676
701
 
677
702
  # Set the value of a hash field, only if the field does not exist.
@@ -743,7 +768,7 @@ class Redis
743
768
  end
744
769
 
745
770
  def subscribed?
746
- !! @subscribed_node
771
+ !!@subscribed_node
747
772
  end
748
773
 
749
774
  # Listen for messages published to the given channels.
@@ -761,7 +786,8 @@ class Redis
761
786
 
762
787
  # Stop listening for messages posted to the given channels.
763
788
  def unsubscribe(*channels)
764
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
789
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
790
+
765
791
  @subscribed_node.unsubscribe(*channels)
766
792
  end
767
793
 
@@ -777,13 +803,26 @@ class Redis
777
803
  end
778
804
 
779
805
  # Watch the given keys to determine execution of the MULTI/EXEC block.
780
- def watch(*keys)
781
- raise CannotDistribute, :watch
806
+ def watch(*keys, &block)
807
+ ensure_same_node(:watch, keys) do |node|
808
+ @watch_key = key_tag(keys.first) || keys.first.to_s
809
+
810
+ begin
811
+ node.watch(*keys, &block)
812
+ rescue StandardError
813
+ @watch_key = nil
814
+ raise
815
+ end
816
+ end
782
817
  end
783
818
 
784
819
  # Forget about all watched keys.
785
820
  def unwatch
786
- raise CannotDistribute, :unwatch
821
+ raise CannotDistribute, :unwatch unless @watch_key
822
+
823
+ result = node_for(@watch_key).unwatch
824
+ @watch_key = nil
825
+ result
787
826
  end
788
827
 
789
828
  def pipelined
@@ -791,18 +830,30 @@ class Redis
791
830
  end
792
831
 
793
832
  # Mark the start of a transaction block.
794
- def multi
795
- raise CannotDistribute, :multi
833
+ def multi(&block)
834
+ raise CannotDistribute, :multi unless @watch_key
835
+
836
+ result = node_for(@watch_key).multi(&block)
837
+ @watch_key = nil if block_given?
838
+ result
796
839
  end
797
840
 
798
841
  # Execute all commands issued after MULTI.
799
842
  def exec
800
- raise CannotDistribute, :exec
843
+ raise CannotDistribute, :exec unless @watch_key
844
+
845
+ result = node_for(@watch_key).exec
846
+ @watch_key = nil
847
+ result
801
848
  end
802
849
 
803
850
  # Discard all commands issued after MULTI.
804
851
  def discard
805
- raise CannotDistribute, :discard
852
+ raise CannotDistribute, :discard unless @watch_key
853
+
854
+ result = node_for(@watch_key).discard
855
+ @watch_key = nil
856
+ result
806
857
  end
807
858
 
808
859
  # Control remote script registry.
@@ -861,7 +912,7 @@ class Redis
861
912
  self.class.new(@node_configs, @default_options)
862
913
  end
863
914
 
864
- protected
915
+ protected
865
916
 
866
917
  def on_each_node(command, *args)
867
918
  nodes.map do |node|
data/lib/redis/errors.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  # Base error for all redis-rb errors.
4
5
  class BaseError < RuntimeError
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'zlib'
3
4
 
4
5
  class Redis
5
6
  class HashRing
6
-
7
7
  POINTS_PER_SERVER = 160 # this is the default in libmemcached
8
8
 
9
9
  attr_reader :ring, :sorted_keys, :replicas, :nodes
@@ -11,7 +11,7 @@ class Redis
11
11
  # nodes is a list of objects that have a proper to_s representation.
12
12
  # replicas indicates how many virtual points should be used pr. node,
13
13
  # replicas are required to improve the distribution.
14
- def initialize(nodes=[], replicas=POINTS_PER_SERVER)
14
+ def initialize(nodes = [], replicas = POINTS_PER_SERVER)
15
15
  @replicas = replicas
16
16
  @ring = {}
17
17
  @nodes = []
@@ -33,11 +33,11 @@ class Redis
33
33
  end
34
34
 
35
35
  def remove_node(node)
36
- @nodes.reject!{|n| n.id == node.id}
36
+ @nodes.reject! { |n| n.id == node.id }
37
37
  @replicas.times do |i|
38
38
  key = Zlib.crc32("#{node.id}:#{i}")
39
39
  @ring.delete(key)
40
- @sorted_keys.reject! {|k| k == key}
40
+ @sorted_keys.reject! { |k| k == key }
41
41
  end
42
42
  end
43
43
 
@@ -47,27 +47,29 @@ class Redis
47
47
  end
48
48
 
49
49
  def get_node_pos(key)
50
- return [nil,nil] if @ring.size == 0
50
+ return [nil, nil] if @ring.empty?
51
+
51
52
  crc = Zlib.crc32(key)
52
53
  idx = HashRing.binary_search(@sorted_keys, crc)
53
- return [@ring[@sorted_keys[idx]], idx]
54
+ [@ring[@sorted_keys[idx]], idx]
54
55
  end
55
56
 
56
57
  def iter_nodes(key)
57
- return [nil,nil] if @ring.size == 0
58
+ return [nil, nil] if @ring.empty?
59
+
58
60
  _, pos = get_node_pos(key)
59
61
  @ring.size.times do |n|
60
- yield @ring[@sorted_keys[(pos+n) % @ring.size]]
62
+ yield @ring[@sorted_keys[(pos + n) % @ring.size]]
61
63
  end
62
64
  end
63
65
 
64
66
  # Find the closest index in HashRing with value <= the given value
65
- def self.binary_search(ary, value, &block)
67
+ def self.binary_search(ary, value)
66
68
  upper = ary.size - 1
67
69
  lower = 0
68
70
  idx = 0
69
71
 
70
- while(lower <= upper) do
72
+ while lower <= upper
71
73
  idx = (lower + upper) / 2
72
74
  comp = ary[idx] <=> value
73
75
 
@@ -80,10 +82,8 @@ class Redis
80
82
  end
81
83
  end
82
84
 
83
- if upper < 0
84
- upper = ary.size - 1
85
- end
86
- return upper
85
+ upper = ary.size - 1 if upper < 0
86
+ upper
87
87
  end
88
88
  end
89
89
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  class Pipeline
4
5
  attr_accessor :db
@@ -61,7 +62,7 @@ class Redis
61
62
  @futures.map(&:timeout)
62
63
  end
63
64
 
64
- def with_reconnect(val=true)
65
+ def with_reconnect(val = true)
65
66
  @with_reconnect = false unless val
66
67
  yield
67
68
  end
@@ -93,7 +94,8 @@ class Redis
93
94
 
94
95
  if exec.size < futures.size
95
96
  # Some command wasn't recognized by Redis.
96
- raise replies.detect { |r| r.is_a?(CommandError) }
97
+ command_error = replies.detect { |r| r.is_a?(CommandError) }
98
+ raise command_error
97
99
  end
98
100
 
99
101
  super(exec) do |reply|
@@ -145,11 +147,7 @@ class Redis
145
147
  message << " - You probably meant to call .value == or .value !="
146
148
  message << " (#{::Kernel.caller(1, 1).first})\n"
147
149
 
148
- if defined?(::Warning)
149
- ::Warning.warn(message)
150
- else
151
- $stderr.puts(message)
152
- end
150
+ ::Kernel.warn(message)
153
151
 
154
152
  super
155
153
  end
@@ -168,7 +166,7 @@ class Redis
168
166
  end
169
167
 
170
168
  def value
171
- ::Kernel.raise(@object) if @object.kind_of?(::RuntimeError)
169
+ ::Kernel.raise(@object) if @object.is_a?(::RuntimeError)
172
170
  @object
173
171
  end
174
172
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  class SubscribedClient
4
5
  def initialize(client)
@@ -33,24 +34,21 @@ class Redis
33
34
  call([:punsubscribe, *channels])
34
35
  end
35
36
 
36
- protected
37
+ protected
37
38
 
38
39
  def subscription(start, stop, channels, block, timeout = 0)
39
40
  sub = Subscription.new(&block)
40
41
 
41
42
  unsubscribed = false
42
43
 
43
- begin
44
- @client.call_loop([start, *channels], timeout) do |line|
45
- type, *rest = line
46
- sub.callbacks[type].call(*rest)
47
- unsubscribed = type == stop && rest.last == 0
48
- break if unsubscribed
49
- end
50
- ensure
51
- # No need to unsubscribe here. The real client closes the connection
52
- # whenever an exception is raised (see #ensure_connected).
44
+ @client.call_loop([start, *channels], timeout) do |line|
45
+ type, *rest = line
46
+ sub.callbacks[type].call(*rest)
47
+ unsubscribed = type == stop && rest.last == 0
48
+ break if unsubscribed
53
49
  end
50
+ # No need to unsubscribe here. The real client closes the connection
51
+ # whenever an exception is raised (see #ensure_connected).
54
52
  end
55
53
  end
56
54
 
@@ -59,7 +57,7 @@ class Redis
59
57
 
60
58
  def initialize
61
59
  @callbacks = Hash.new do |hash, key|
62
- hash[key] = lambda { |*_| }
60
+ hash[key] = ->(*_) {}
63
61
  end
64
62
 
65
63
  yield(self)
data/lib/redis/version.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
- VERSION = '4.1.4'
4
+ VERSION = '4.2.5'
4
5
  end