redis 4.1.4 → 4.5.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -0
- data/README.md +27 -17
- data/lib/redis/client.rb +108 -74
- data/lib/redis/cluster/command_loader.rb +6 -7
- data/lib/redis/cluster/node.rb +5 -1
- data/lib/redis/cluster/option.rb +9 -3
- data/lib/redis/cluster/slot.rb +28 -14
- data/lib/redis/cluster/slot_loader.rb +2 -3
- data/lib/redis/cluster.rb +13 -13
- data/lib/redis/connection/command_helper.rb +4 -2
- data/lib/redis/connection/hiredis.rb +3 -3
- data/lib/redis/connection/registry.rb +1 -1
- data/lib/redis/connection/ruby.rb +92 -109
- data/lib/redis/connection/synchrony.rb +8 -4
- data/lib/redis/connection.rb +1 -0
- data/lib/redis/distributed.rb +161 -63
- data/lib/redis/errors.rb +1 -0
- data/lib/redis/hash_ring.rb +14 -14
- data/lib/redis/pipeline.rb +6 -8
- data/lib/redis/subscribe.rb +10 -12
- data/lib/redis/version.rb +2 -1
- data/lib/redis.rb +597 -261
- metadata +15 -10
data/lib/redis/distributed.rb
CHANGED
@@ -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
|
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
|
-
|
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 = { :
|
42
|
+
options = { url: options } if options.is_a?(String)
|
38
43
|
options = @default_options.merge(options)
|
39
|
-
@ring.add_node Redis.new(
|
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(
|
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(
|
175
|
-
|
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(*
|
297
|
+
def mset(*_args)
|
268
298
|
raise CannotDistribute, :mset
|
269
299
|
end
|
270
300
|
|
271
|
-
def mapped_mset(
|
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(*
|
306
|
+
def msetnx(*_args)
|
277
307
|
raise CannotDistribute, :msetnx
|
278
308
|
end
|
279
309
|
|
280
|
-
def mapped_msetnx(
|
310
|
+
def mapped_msetnx(_hash)
|
281
311
|
raise CannotDistribute, :mapped_msetnx
|
282
312
|
end
|
283
313
|
|
@@ -286,6 +316,16 @@ class Redis
|
|
286
316
|
node_for(key).get(key)
|
287
317
|
end
|
288
318
|
|
319
|
+
# Get the value of a key and delete it.
|
320
|
+
def getdel(key)
|
321
|
+
node_for(key).getdel(key)
|
322
|
+
end
|
323
|
+
|
324
|
+
# Get the value of a key and sets its time to live based on options.
|
325
|
+
def getex(key, **options)
|
326
|
+
node_for(key).getex(key, **options)
|
327
|
+
end
|
328
|
+
|
289
329
|
# Get the values of all the given keys as an Array.
|
290
330
|
def mget(*keys)
|
291
331
|
mapped_mget(*keys).values_at(*keys)
|
@@ -336,7 +376,7 @@ class Redis
|
|
336
376
|
end
|
337
377
|
|
338
378
|
# Return the position of the first bit set to 1 or 0 in a string.
|
339
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
379
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
340
380
|
node_for(key).bitpos(key, bit, start, stop)
|
341
381
|
end
|
342
382
|
|
@@ -354,7 +394,7 @@ class Redis
|
|
354
394
|
get(key)
|
355
395
|
end
|
356
396
|
|
357
|
-
def []=(key,value)
|
397
|
+
def []=(key, value)
|
358
398
|
set(key, value)
|
359
399
|
end
|
360
400
|
|
@@ -363,6 +403,21 @@ class Redis
|
|
363
403
|
node_for(key).llen(key)
|
364
404
|
end
|
365
405
|
|
406
|
+
# Remove the first/last element in a list, append/prepend it to another list and return it.
|
407
|
+
def lmove(source, destination, where_source, where_destination)
|
408
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
409
|
+
node.lmove(source, destination, where_source, where_destination)
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# Remove the first/last element in a list and append/prepend it
|
414
|
+
# to another list and return it, or block until one is available.
|
415
|
+
def blmove(source, destination, where_source, where_destination, timeout: 0)
|
416
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
417
|
+
node.blmove(source, destination, where_source, where_destination, timeout: timeout)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
366
421
|
# Prepend one or more values to a list.
|
367
422
|
def lpush(key, value)
|
368
423
|
node_for(key).lpush(key, value)
|
@@ -383,14 +438,14 @@ class Redis
|
|
383
438
|
node_for(key).rpushx(key, value)
|
384
439
|
end
|
385
440
|
|
386
|
-
# Remove and get the first
|
387
|
-
def lpop(key)
|
388
|
-
node_for(key).lpop(key)
|
441
|
+
# Remove and get the first elements in a list.
|
442
|
+
def lpop(key, count = nil)
|
443
|
+
node_for(key).lpop(key, count)
|
389
444
|
end
|
390
445
|
|
391
|
-
# Remove and get the last
|
392
|
-
def rpop(key)
|
393
|
-
node_for(key).rpop(key)
|
446
|
+
# Remove and get the last elements in a list.
|
447
|
+
def rpop(key, count = nil)
|
448
|
+
node_for(key).rpop(key, count)
|
394
449
|
end
|
395
450
|
|
396
451
|
# Remove the last element in a list, append it to another list and return
|
@@ -439,15 +494,9 @@ class Redis
|
|
439
494
|
|
440
495
|
# Pop a value from a list, push it to another list and return it; or block
|
441
496
|
# until one is available.
|
442
|
-
def brpoplpush(source, destination,
|
443
|
-
case options
|
444
|
-
when Integer
|
445
|
-
# Issue deprecation notice in obnoxious mode...
|
446
|
-
options = { :timeout => options }
|
447
|
-
end
|
448
|
-
|
497
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, **options)
|
449
498
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
450
|
-
node.brpoplpush(source, destination, options)
|
499
|
+
node.brpoplpush(source, destination, deprecated_timeout, **options)
|
451
500
|
end
|
452
501
|
end
|
453
502
|
|
@@ -518,19 +567,24 @@ class Redis
|
|
518
567
|
node_for(key).sismember(key, member)
|
519
568
|
end
|
520
569
|
|
570
|
+
# Determine if multiple values are members of a set.
|
571
|
+
def smismember(key, *members)
|
572
|
+
node_for(key).smismember(key, *members)
|
573
|
+
end
|
574
|
+
|
521
575
|
# Get all the members in a set.
|
522
576
|
def smembers(key)
|
523
577
|
node_for(key).smembers(key)
|
524
578
|
end
|
525
579
|
|
526
580
|
# Scan a set
|
527
|
-
def sscan(key, cursor, options
|
528
|
-
node_for(key).sscan(key, cursor, options)
|
581
|
+
def sscan(key, cursor, **options)
|
582
|
+
node_for(key).sscan(key, cursor, **options)
|
529
583
|
end
|
530
584
|
|
531
585
|
# Scan a set and return an enumerator
|
532
|
-
def sscan_each(key, options
|
533
|
-
node_for(key).sscan_each(key, options, &block)
|
586
|
+
def sscan_each(key, **options, &block)
|
587
|
+
node_for(key).sscan_each(key, **options, &block)
|
534
588
|
end
|
535
589
|
|
536
590
|
# Subtract multiple sets.
|
@@ -585,6 +639,7 @@ class Redis
|
|
585
639
|
def zadd(key, *args)
|
586
640
|
node_for(key).zadd(key, *args)
|
587
641
|
end
|
642
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
588
643
|
|
589
644
|
# Increment the score of a member in a sorted set.
|
590
645
|
def zincrby(key, increment, member)
|
@@ -601,15 +656,25 @@ class Redis
|
|
601
656
|
node_for(key).zscore(key, member)
|
602
657
|
end
|
603
658
|
|
659
|
+
# Get one or more random members from a sorted set.
|
660
|
+
def zrandmember(key, count = nil, **options)
|
661
|
+
node_for(key).zrandmember(key, count, **options)
|
662
|
+
end
|
663
|
+
|
664
|
+
# Get the scores associated with the given members in a sorted set.
|
665
|
+
def zmscore(key, *members)
|
666
|
+
node_for(key).zmscore(key, *members)
|
667
|
+
end
|
668
|
+
|
604
669
|
# 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)
|
670
|
+
def zrange(key, start, stop, **options)
|
671
|
+
node_for(key).zrange(key, start, stop, **options)
|
607
672
|
end
|
608
673
|
|
609
674
|
# Return a range of members in a sorted set, by index, with scores ordered
|
610
675
|
# from high to low.
|
611
|
-
def zrevrange(key, start, stop, options
|
612
|
-
node_for(key).zrevrange(key, start, stop, options)
|
676
|
+
def zrevrange(key, start, stop, **options)
|
677
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
613
678
|
end
|
614
679
|
|
615
680
|
# Determine the index of a member in a sorted set.
|
@@ -629,14 +694,14 @@ class Redis
|
|
629
694
|
end
|
630
695
|
|
631
696
|
# 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)
|
697
|
+
def zrangebyscore(key, min, max, **options)
|
698
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
634
699
|
end
|
635
700
|
|
636
701
|
# Return a range of members in a sorted set, by score, with scores ordered
|
637
702
|
# from high to low.
|
638
|
-
def zrevrangebyscore(key, max, min, options
|
639
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
703
|
+
def zrevrangebyscore(key, max, min, **options)
|
704
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
640
705
|
end
|
641
706
|
|
642
707
|
# Remove all members in a sorted set within the given scores.
|
@@ -649,18 +714,25 @@ class Redis
|
|
649
714
|
node_for(key).zcount(key, min, max)
|
650
715
|
end
|
651
716
|
|
717
|
+
# Get the intersection of multiple sorted sets
|
718
|
+
def zinter(*keys, **options)
|
719
|
+
ensure_same_node(:zinter, keys) do |node|
|
720
|
+
node.zinter(*keys, **options)
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
652
724
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
653
725
|
# key.
|
654
|
-
def zinterstore(destination, keys, options
|
726
|
+
def zinterstore(destination, keys, **options)
|
655
727
|
ensure_same_node(:zinterstore, [destination] + keys) do |node|
|
656
|
-
node.zinterstore(destination, keys, options)
|
728
|
+
node.zinterstore(destination, keys, **options)
|
657
729
|
end
|
658
730
|
end
|
659
731
|
|
660
732
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
661
|
-
def zunionstore(destination, keys, options
|
733
|
+
def zunionstore(destination, keys, **options)
|
662
734
|
ensure_same_node(:zunionstore, [destination] + keys) do |node|
|
663
|
-
node.zunionstore(destination, keys, options)
|
735
|
+
node.zunionstore(destination, keys, **options)
|
664
736
|
end
|
665
737
|
end
|
666
738
|
|
@@ -669,9 +741,9 @@ class Redis
|
|
669
741
|
node_for(key).hlen(key)
|
670
742
|
end
|
671
743
|
|
672
|
-
# Set
|
673
|
-
def hset(key,
|
674
|
-
node_for(key).hset(key,
|
744
|
+
# Set multiple hash fields to multiple values.
|
745
|
+
def hset(key, *attrs)
|
746
|
+
node_for(key).hset(key, *attrs)
|
675
747
|
end
|
676
748
|
|
677
749
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -743,7 +815,7 @@ class Redis
|
|
743
815
|
end
|
744
816
|
|
745
817
|
def subscribed?
|
746
|
-
|
818
|
+
!!@subscribed_node
|
747
819
|
end
|
748
820
|
|
749
821
|
# Listen for messages published to the given channels.
|
@@ -761,7 +833,8 @@ class Redis
|
|
761
833
|
|
762
834
|
# Stop listening for messages posted to the given channels.
|
763
835
|
def unsubscribe(*channels)
|
764
|
-
raise
|
836
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
837
|
+
|
765
838
|
@subscribed_node.unsubscribe(*channels)
|
766
839
|
end
|
767
840
|
|
@@ -777,13 +850,26 @@ class Redis
|
|
777
850
|
end
|
778
851
|
|
779
852
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
780
|
-
def watch(*keys)
|
781
|
-
|
853
|
+
def watch(*keys, &block)
|
854
|
+
ensure_same_node(:watch, keys) do |node|
|
855
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
856
|
+
|
857
|
+
begin
|
858
|
+
node.watch(*keys, &block)
|
859
|
+
rescue StandardError
|
860
|
+
@watch_key = nil
|
861
|
+
raise
|
862
|
+
end
|
863
|
+
end
|
782
864
|
end
|
783
865
|
|
784
866
|
# Forget about all watched keys.
|
785
867
|
def unwatch
|
786
|
-
raise CannotDistribute, :unwatch
|
868
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
869
|
+
|
870
|
+
result = node_for(@watch_key).unwatch
|
871
|
+
@watch_key = nil
|
872
|
+
result
|
787
873
|
end
|
788
874
|
|
789
875
|
def pipelined
|
@@ -791,18 +877,30 @@ class Redis
|
|
791
877
|
end
|
792
878
|
|
793
879
|
# Mark the start of a transaction block.
|
794
|
-
def multi
|
795
|
-
raise CannotDistribute, :multi
|
880
|
+
def multi(&block)
|
881
|
+
raise CannotDistribute, :multi unless @watch_key
|
882
|
+
|
883
|
+
result = node_for(@watch_key).multi(&block)
|
884
|
+
@watch_key = nil if block_given?
|
885
|
+
result
|
796
886
|
end
|
797
887
|
|
798
888
|
# Execute all commands issued after MULTI.
|
799
889
|
def exec
|
800
|
-
raise CannotDistribute, :exec
|
890
|
+
raise CannotDistribute, :exec unless @watch_key
|
891
|
+
|
892
|
+
result = node_for(@watch_key).exec
|
893
|
+
@watch_key = nil
|
894
|
+
result
|
801
895
|
end
|
802
896
|
|
803
897
|
# Discard all commands issued after MULTI.
|
804
898
|
def discard
|
805
|
-
raise CannotDistribute, :discard
|
899
|
+
raise CannotDistribute, :discard unless @watch_key
|
900
|
+
|
901
|
+
result = node_for(@watch_key).discard
|
902
|
+
@watch_key = nil
|
903
|
+
result
|
806
904
|
end
|
807
905
|
|
808
906
|
# Control remote script registry.
|
@@ -861,7 +959,7 @@ class Redis
|
|
861
959
|
self.class.new(@node_configs, @default_options)
|
862
960
|
end
|
863
961
|
|
864
|
-
|
962
|
+
protected
|
865
963
|
|
866
964
|
def on_each_node(command, *args)
|
867
965
|
nodes.map do |node|
|
data/lib/redis/errors.rb
CHANGED
data/lib/redis/hash_ring.rb
CHANGED
@@ -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.
|
50
|
+
return [nil, nil] if @ring.empty?
|
51
|
+
|
51
52
|
crc = Zlib.crc32(key)
|
52
53
|
idx = HashRing.binary_search(@sorted_keys, crc)
|
53
|
-
|
54
|
+
[@ring[@sorted_keys[idx]], idx]
|
54
55
|
end
|
55
56
|
|
56
57
|
def iter_nodes(key)
|
57
|
-
return [nil,nil] if @ring.
|
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
|
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
|
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
|
-
|
85
|
-
end
|
86
|
-
return upper
|
85
|
+
upper = ary.size - 1 if upper < 0
|
86
|
+
upper
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
data/lib/redis/pipeline.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
169
|
+
::Kernel.raise(@object) if @object.is_a?(::RuntimeError)
|
172
170
|
@object
|
173
171
|
end
|
174
172
|
|
data/lib/redis/subscribe.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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] =
|
60
|
+
hash[key] = ->(*_) {}
|
63
61
|
end
|
64
62
|
|
65
63
|
yield(self)
|
data/lib/redis/version.rb
CHANGED