redis 4.1.4 → 4.7.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 +141 -0
- data/README.md +52 -27
- data/lib/redis/client.rb +122 -87
- data/lib/redis/cluster/command.rb +4 -6
- data/lib/redis/cluster/command_loader.rb +8 -9
- data/lib/redis/cluster/node.rb +17 -1
- data/lib/redis/cluster/node_loader.rb +8 -11
- data/lib/redis/cluster/option.rb +18 -5
- data/lib/redis/cluster/slot.rb +28 -14
- data/lib/redis/cluster/slot_loader.rb +11 -15
- data/lib/redis/cluster.rb +37 -13
- data/lib/redis/commands/bitmaps.rb +63 -0
- data/lib/redis/commands/cluster.rb +45 -0
- data/lib/redis/commands/connection.rb +58 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +251 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +411 -0
- data/lib/redis/commands/lists.rb +289 -0
- data/lib/redis/commands/pubsub.rb +72 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +207 -0
- data/lib/redis/commands/sorted_sets.rb +812 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +139 -0
- data/lib/redis/commands.rb +242 -0
- data/lib/redis/connection/command_helper.rb +4 -2
- data/lib/redis/connection/hiredis.rb +6 -7
- data/lib/redis/connection/registry.rb +1 -1
- data/lib/redis/connection/ruby.rb +106 -114
- data/lib/redis/connection/synchrony.rb +16 -10
- data/lib/redis/connection.rb +2 -1
- data/lib/redis/distributed.rb +200 -65
- data/lib/redis/errors.rb +10 -0
- data/lib/redis/hash_ring.rb +14 -14
- data/lib/redis/pipeline.rb +133 -10
- data/lib/redis/subscribe.rb +10 -12
- data/lib/redis/version.rb +2 -1
- data/lib/redis.rb +158 -3358
- metadata +32 -10
data/lib/redis/distributed.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "redis/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,29 @@ 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
|
+
::Redis.deprecate!(
|
182
|
+
"`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
|
183
|
+
"use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
|
184
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
185
|
+
)
|
186
|
+
exists?(*args)
|
187
|
+
else
|
188
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
189
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
190
|
+
sum + node._exists(*keys)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Determine if any of the keys exists.
|
196
|
+
def exists?(*args)
|
197
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
198
|
+
keys_per_node.each do |node, keys|
|
199
|
+
return true if node.exists?(*keys)
|
200
|
+
end
|
201
|
+
false
|
176
202
|
end
|
177
203
|
|
178
204
|
# Find all keys matching the given pattern.
|
@@ -185,6 +211,13 @@ class Redis
|
|
185
211
|
node_for(key).move(key, db)
|
186
212
|
end
|
187
213
|
|
214
|
+
# Copy a value from one key to another.
|
215
|
+
def copy(source, destination, **options)
|
216
|
+
ensure_same_node(:copy, [source, destination]) do |node|
|
217
|
+
node.copy(source, destination, **options)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
188
221
|
# Return a random key from the keyspace.
|
189
222
|
def randomkey
|
190
223
|
raise CannotDistribute, :randomkey
|
@@ -205,11 +238,11 @@ class Redis
|
|
205
238
|
end
|
206
239
|
|
207
240
|
# Sort the elements in a list, set or sorted set.
|
208
|
-
def sort(key, options
|
241
|
+
def sort(key, **options)
|
209
242
|
keys = [key, options[:by], options[:store], *Array(options[:get])].compact
|
210
243
|
|
211
244
|
ensure_same_node(:sort, keys) do |node|
|
212
|
-
node.sort(key, options)
|
245
|
+
node.sort(key, **options)
|
213
246
|
end
|
214
247
|
end
|
215
248
|
|
@@ -244,8 +277,8 @@ class Redis
|
|
244
277
|
end
|
245
278
|
|
246
279
|
# Set the string value of a key.
|
247
|
-
def set(key, value, options
|
248
|
-
node_for(key).set(key, value, options)
|
280
|
+
def set(key, value, **options)
|
281
|
+
node_for(key).set(key, value, **options)
|
249
282
|
end
|
250
283
|
|
251
284
|
# Set the time to live in seconds of a key.
|
@@ -264,20 +297,20 @@ class Redis
|
|
264
297
|
end
|
265
298
|
|
266
299
|
# Set multiple keys to multiple values.
|
267
|
-
def mset(*
|
300
|
+
def mset(*_args)
|
268
301
|
raise CannotDistribute, :mset
|
269
302
|
end
|
270
303
|
|
271
|
-
def mapped_mset(
|
304
|
+
def mapped_mset(_hash)
|
272
305
|
raise CannotDistribute, :mapped_mset
|
273
306
|
end
|
274
307
|
|
275
308
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
276
|
-
def msetnx(*
|
309
|
+
def msetnx(*_args)
|
277
310
|
raise CannotDistribute, :msetnx
|
278
311
|
end
|
279
312
|
|
280
|
-
def mapped_msetnx(
|
313
|
+
def mapped_msetnx(_hash)
|
281
314
|
raise CannotDistribute, :mapped_msetnx
|
282
315
|
end
|
283
316
|
|
@@ -286,6 +319,16 @@ class Redis
|
|
286
319
|
node_for(key).get(key)
|
287
320
|
end
|
288
321
|
|
322
|
+
# Get the value of a key and delete it.
|
323
|
+
def getdel(key)
|
324
|
+
node_for(key).getdel(key)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Get the value of a key and sets its time to live based on options.
|
328
|
+
def getex(key, **options)
|
329
|
+
node_for(key).getex(key, **options)
|
330
|
+
end
|
331
|
+
|
289
332
|
# Get the values of all the given keys as an Array.
|
290
333
|
def mget(*keys)
|
291
334
|
mapped_mget(*keys).values_at(*keys)
|
@@ -336,7 +379,7 @@ class Redis
|
|
336
379
|
end
|
337
380
|
|
338
381
|
# Return the position of the first bit set to 1 or 0 in a string.
|
339
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
382
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
340
383
|
node_for(key).bitpos(key, bit, start, stop)
|
341
384
|
end
|
342
385
|
|
@@ -354,7 +397,7 @@ class Redis
|
|
354
397
|
get(key)
|
355
398
|
end
|
356
399
|
|
357
|
-
def []=(key,value)
|
400
|
+
def []=(key, value)
|
358
401
|
set(key, value)
|
359
402
|
end
|
360
403
|
|
@@ -363,6 +406,21 @@ class Redis
|
|
363
406
|
node_for(key).llen(key)
|
364
407
|
end
|
365
408
|
|
409
|
+
# Remove the first/last element in a list, append/prepend it to another list and return it.
|
410
|
+
def lmove(source, destination, where_source, where_destination)
|
411
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
412
|
+
node.lmove(source, destination, where_source, where_destination)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Remove the first/last element in a list and append/prepend it
|
417
|
+
# to another list and return it, or block until one is available.
|
418
|
+
def blmove(source, destination, where_source, where_destination, timeout: 0)
|
419
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
420
|
+
node.blmove(source, destination, where_source, where_destination, timeout: timeout)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
366
424
|
# Prepend one or more values to a list.
|
367
425
|
def lpush(key, value)
|
368
426
|
node_for(key).lpush(key, value)
|
@@ -383,14 +441,14 @@ class Redis
|
|
383
441
|
node_for(key).rpushx(key, value)
|
384
442
|
end
|
385
443
|
|
386
|
-
# Remove and get the first
|
387
|
-
def lpop(key)
|
388
|
-
node_for(key).lpop(key)
|
444
|
+
# Remove and get the first elements in a list.
|
445
|
+
def lpop(key, count = nil)
|
446
|
+
node_for(key).lpop(key, count)
|
389
447
|
end
|
390
448
|
|
391
|
-
# Remove and get the last
|
392
|
-
def rpop(key)
|
393
|
-
node_for(key).rpop(key)
|
449
|
+
# Remove and get the last elements in a list.
|
450
|
+
def rpop(key, count = nil)
|
451
|
+
node_for(key).rpop(key, count)
|
394
452
|
end
|
395
453
|
|
396
454
|
# Remove the last element in a list, append it to another list and return
|
@@ -439,15 +497,9 @@ class Redis
|
|
439
497
|
|
440
498
|
# Pop a value from a list, push it to another list and return it; or block
|
441
499
|
# 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
|
-
|
500
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, **options)
|
449
501
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
450
|
-
node.brpoplpush(source, destination, options)
|
502
|
+
node.brpoplpush(source, destination, deprecated_timeout, **options)
|
451
503
|
end
|
452
504
|
end
|
453
505
|
|
@@ -518,19 +570,24 @@ class Redis
|
|
518
570
|
node_for(key).sismember(key, member)
|
519
571
|
end
|
520
572
|
|
573
|
+
# Determine if multiple values are members of a set.
|
574
|
+
def smismember(key, *members)
|
575
|
+
node_for(key).smismember(key, *members)
|
576
|
+
end
|
577
|
+
|
521
578
|
# Get all the members in a set.
|
522
579
|
def smembers(key)
|
523
580
|
node_for(key).smembers(key)
|
524
581
|
end
|
525
582
|
|
526
583
|
# Scan a set
|
527
|
-
def sscan(key, cursor, options
|
528
|
-
node_for(key).sscan(key, cursor, options)
|
584
|
+
def sscan(key, cursor, **options)
|
585
|
+
node_for(key).sscan(key, cursor, **options)
|
529
586
|
end
|
530
587
|
|
531
588
|
# Scan a set and return an enumerator
|
532
|
-
def sscan_each(key, options
|
533
|
-
node_for(key).sscan_each(key, options, &block)
|
589
|
+
def sscan_each(key, **options, &block)
|
590
|
+
node_for(key).sscan_each(key, **options, &block)
|
534
591
|
end
|
535
592
|
|
536
593
|
# Subtract multiple sets.
|
@@ -585,6 +642,7 @@ class Redis
|
|
585
642
|
def zadd(key, *args)
|
586
643
|
node_for(key).zadd(key, *args)
|
587
644
|
end
|
645
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
588
646
|
|
589
647
|
# Increment the score of a member in a sorted set.
|
590
648
|
def zincrby(key, increment, member)
|
@@ -601,15 +659,33 @@ class Redis
|
|
601
659
|
node_for(key).zscore(key, member)
|
602
660
|
end
|
603
661
|
|
604
|
-
#
|
605
|
-
def
|
606
|
-
node_for(key).
|
662
|
+
# Get one or more random members from a sorted set.
|
663
|
+
def zrandmember(key, count = nil, **options)
|
664
|
+
node_for(key).zrandmember(key, count, **options)
|
665
|
+
end
|
666
|
+
|
667
|
+
# Get the scores associated with the given members in a sorted set.
|
668
|
+
def zmscore(key, *members)
|
669
|
+
node_for(key).zmscore(key, *members)
|
670
|
+
end
|
671
|
+
|
672
|
+
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
673
|
+
def zrange(key, start, stop, **options)
|
674
|
+
node_for(key).zrange(key, start, stop, **options)
|
675
|
+
end
|
676
|
+
|
677
|
+
# Select a range of members in a sorted set, by index, score or lexicographical ordering
|
678
|
+
# and store the resulting sorted set in a new key.
|
679
|
+
def zrangestore(dest_key, src_key, start, stop, **options)
|
680
|
+
ensure_same_node(:zrangestore, [dest_key, src_key]) do |node|
|
681
|
+
node.zrangestore(dest_key, src_key, start, stop, **options)
|
682
|
+
end
|
607
683
|
end
|
608
684
|
|
609
685
|
# Return a range of members in a sorted set, by index, with scores ordered
|
610
686
|
# from high to low.
|
611
|
-
def zrevrange(key, start, stop, options
|
612
|
-
node_for(key).zrevrange(key, start, stop, options)
|
687
|
+
def zrevrange(key, start, stop, **options)
|
688
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
613
689
|
end
|
614
690
|
|
615
691
|
# Determine the index of a member in a sorted set.
|
@@ -629,14 +705,14 @@ class Redis
|
|
629
705
|
end
|
630
706
|
|
631
707
|
# 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)
|
708
|
+
def zrangebyscore(key, min, max, **options)
|
709
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
634
710
|
end
|
635
711
|
|
636
712
|
# Return a range of members in a sorted set, by score, with scores ordered
|
637
713
|
# from high to low.
|
638
|
-
def zrevrangebyscore(key, max, min, options
|
639
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
714
|
+
def zrevrangebyscore(key, max, min, **options)
|
715
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
640
716
|
end
|
641
717
|
|
642
718
|
# Remove all members in a sorted set within the given scores.
|
@@ -649,18 +725,47 @@ class Redis
|
|
649
725
|
node_for(key).zcount(key, min, max)
|
650
726
|
end
|
651
727
|
|
728
|
+
# Get the intersection of multiple sorted sets
|
729
|
+
def zinter(*keys, **options)
|
730
|
+
ensure_same_node(:zinter, keys) do |node|
|
731
|
+
node.zinter(*keys, **options)
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
652
735
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
653
736
|
# key.
|
654
|
-
def zinterstore(destination, keys, options
|
737
|
+
def zinterstore(destination, keys, **options)
|
655
738
|
ensure_same_node(:zinterstore, [destination] + keys) do |node|
|
656
|
-
node.zinterstore(destination, keys, options)
|
739
|
+
node.zinterstore(destination, keys, **options)
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
# Return the union of multiple sorted sets.
|
744
|
+
def zunion(*keys, **options)
|
745
|
+
ensure_same_node(:zunion, keys) do |node|
|
746
|
+
node.zunion(*keys, **options)
|
657
747
|
end
|
658
748
|
end
|
659
749
|
|
660
750
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
661
|
-
def zunionstore(destination, keys, options
|
751
|
+
def zunionstore(destination, keys, **options)
|
662
752
|
ensure_same_node(:zunionstore, [destination] + keys) do |node|
|
663
|
-
node.zunionstore(destination, keys, options)
|
753
|
+
node.zunionstore(destination, keys, **options)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
# Return the difference between the first and all successive input sorted sets.
|
758
|
+
def zdiff(*keys, **options)
|
759
|
+
ensure_same_node(:zdiff, keys) do |node|
|
760
|
+
node.zdiff(*keys, **options)
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
# Compute the difference between the first and all successive input sorted sets
|
765
|
+
# and store the resulting sorted set in a new key.
|
766
|
+
def zdiffstore(destination, keys, **options)
|
767
|
+
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
768
|
+
node.zdiffstore(destination, keys, **options)
|
664
769
|
end
|
665
770
|
end
|
666
771
|
|
@@ -669,9 +774,9 @@ class Redis
|
|
669
774
|
node_for(key).hlen(key)
|
670
775
|
end
|
671
776
|
|
672
|
-
# Set
|
673
|
-
def hset(key,
|
674
|
-
node_for(key).hset(key,
|
777
|
+
# Set multiple hash fields to multiple values.
|
778
|
+
def hset(key, *attrs)
|
779
|
+
node_for(key).hset(key, *attrs)
|
675
780
|
end
|
676
781
|
|
677
782
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -702,6 +807,10 @@ class Redis
|
|
702
807
|
Hash[*fields.zip(hmget(key, *fields)).flatten]
|
703
808
|
end
|
704
809
|
|
810
|
+
def hrandfield(key, count = nil, **options)
|
811
|
+
node_for(key).hrandfield(key, count, **options)
|
812
|
+
end
|
813
|
+
|
705
814
|
# Delete one or more hash fields.
|
706
815
|
def hdel(key, *fields)
|
707
816
|
node_for(key).hdel(key, *fields)
|
@@ -743,7 +852,7 @@ class Redis
|
|
743
852
|
end
|
744
853
|
|
745
854
|
def subscribed?
|
746
|
-
|
855
|
+
!!@subscribed_node
|
747
856
|
end
|
748
857
|
|
749
858
|
# Listen for messages published to the given channels.
|
@@ -761,7 +870,8 @@ class Redis
|
|
761
870
|
|
762
871
|
# Stop listening for messages posted to the given channels.
|
763
872
|
def unsubscribe(*channels)
|
764
|
-
raise
|
873
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
874
|
+
|
765
875
|
@subscribed_node.unsubscribe(*channels)
|
766
876
|
end
|
767
877
|
|
@@ -777,13 +887,26 @@ class Redis
|
|
777
887
|
end
|
778
888
|
|
779
889
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
780
|
-
def watch(*keys)
|
781
|
-
|
890
|
+
def watch(*keys, &block)
|
891
|
+
ensure_same_node(:watch, keys) do |node|
|
892
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
893
|
+
|
894
|
+
begin
|
895
|
+
node.watch(*keys, &block)
|
896
|
+
rescue StandardError
|
897
|
+
@watch_key = nil
|
898
|
+
raise
|
899
|
+
end
|
900
|
+
end
|
782
901
|
end
|
783
902
|
|
784
903
|
# Forget about all watched keys.
|
785
904
|
def unwatch
|
786
|
-
raise CannotDistribute, :unwatch
|
905
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
906
|
+
|
907
|
+
result = node_for(@watch_key).unwatch
|
908
|
+
@watch_key = nil
|
909
|
+
result
|
787
910
|
end
|
788
911
|
|
789
912
|
def pipelined
|
@@ -791,18 +914,30 @@ class Redis
|
|
791
914
|
end
|
792
915
|
|
793
916
|
# Mark the start of a transaction block.
|
794
|
-
def multi
|
795
|
-
raise CannotDistribute, :multi
|
917
|
+
def multi(&block)
|
918
|
+
raise CannotDistribute, :multi unless @watch_key
|
919
|
+
|
920
|
+
result = node_for(@watch_key).multi(&block)
|
921
|
+
@watch_key = nil if block_given?
|
922
|
+
result
|
796
923
|
end
|
797
924
|
|
798
925
|
# Execute all commands issued after MULTI.
|
799
926
|
def exec
|
800
|
-
raise CannotDistribute, :exec
|
927
|
+
raise CannotDistribute, :exec unless @watch_key
|
928
|
+
|
929
|
+
result = node_for(@watch_key).exec
|
930
|
+
@watch_key = nil
|
931
|
+
result
|
801
932
|
end
|
802
933
|
|
803
934
|
# Discard all commands issued after MULTI.
|
804
935
|
def discard
|
805
|
-
raise CannotDistribute, :discard
|
936
|
+
raise CannotDistribute, :discard unless @watch_key
|
937
|
+
|
938
|
+
result = node_for(@watch_key).discard
|
939
|
+
@watch_key = nil
|
940
|
+
result
|
806
941
|
end
|
807
942
|
|
808
943
|
# Control remote script registry.
|
@@ -861,7 +996,7 @@ class Redis
|
|
861
996
|
self.class.new(@node_configs, @default_options)
|
862
997
|
end
|
863
998
|
|
864
|
-
|
999
|
+
protected
|
865
1000
|
|
866
1001
|
def on_each_node(command, *args)
|
867
1002
|
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
|
@@ -44,6 +45,15 @@ class Redis
|
|
44
45
|
end
|
45
46
|
|
46
47
|
class Cluster
|
48
|
+
# Raised when client connected to redis as cluster mode
|
49
|
+
# and failed to fetch cluster state information by commands.
|
50
|
+
class InitialSetupError < BaseError
|
51
|
+
# @param errors [Array<Redis::BaseError>]
|
52
|
+
def initialize(errors)
|
53
|
+
super("Redis client could not fetch cluster information: #{errors.map(&:message).uniq.join(',')}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
47
57
|
# Raised when client connected to redis as cluster mode
|
48
58
|
# and some cluster subcommands were called.
|
49
59
|
class OrchestrationCommandNotSupported < BaseError
|
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
|