redis 4.8.1 → 5.0.0
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 +23 -4
- data/README.md +75 -161
- data/lib/redis/client.rb +78 -606
- data/lib/redis/commands/bitmaps.rb +4 -1
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +3 -3
- data/lib/redis/commands/hashes.rb +8 -5
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +1 -19
- data/lib/redis/commands/lists.rb +20 -25
- data/lib/redis/commands/pubsub.rb +7 -25
- data/lib/redis/commands/server.rb +14 -14
- data/lib/redis/commands/sets.rb +31 -40
- data/lib/redis/commands/sorted_sets.rb +18 -12
- data/lib/redis/commands/streams.rb +12 -10
- data/lib/redis/commands/strings.rb +14 -13
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +1 -6
- data/lib/redis/distributed.rb +86 -64
- data/lib/redis/errors.rb +11 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +43 -222
- data/lib/redis/subscribe.rb +23 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +80 -185
- metadata +11 -55
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
data/lib/redis/distributed.rb
CHANGED
@@ -20,7 +20,7 @@ class Redis
|
|
20
20
|
def initialize(node_configs, options = {})
|
21
21
|
@tag = options[:tag] || /^\{(.+?)\}/
|
22
22
|
@ring = options[:ring] || HashRing.new
|
23
|
-
@node_configs = node_configs.dup
|
23
|
+
@node_configs = node_configs.map(&:dup)
|
24
24
|
@default_options = options.dup
|
25
25
|
node_configs.each { |node_config| add_node(node_config) }
|
26
26
|
@subscribed_node = nil
|
@@ -41,6 +41,8 @@ class Redis
|
|
41
41
|
def add_node(options)
|
42
42
|
options = { url: options } if options.is_a?(String)
|
43
43
|
options = @default_options.merge(options)
|
44
|
+
options.delete(:tag)
|
45
|
+
options.delete(:ring)
|
44
46
|
@ring.add_node Redis.new(options)
|
45
47
|
end
|
46
48
|
|
@@ -64,6 +66,10 @@ class Redis
|
|
64
66
|
on_each_node :quit
|
65
67
|
end
|
66
68
|
|
69
|
+
def close
|
70
|
+
on_each_node :close
|
71
|
+
end
|
72
|
+
|
67
73
|
# Asynchronously save the dataset to disk.
|
68
74
|
def bgsave
|
69
75
|
on_each_node :bgsave
|
@@ -161,6 +167,7 @@ class Redis
|
|
161
167
|
|
162
168
|
# Delete a key.
|
163
169
|
def del(*args)
|
170
|
+
args.flatten!(1)
|
164
171
|
keys_per_node = args.group_by { |key| node_for(key) }
|
165
172
|
keys_per_node.inject(0) do |sum, (node, keys)|
|
166
173
|
sum + node.del(*keys)
|
@@ -169,6 +176,7 @@ class Redis
|
|
169
176
|
|
170
177
|
# Unlink keys.
|
171
178
|
def unlink(*args)
|
179
|
+
args.flatten!(1)
|
172
180
|
keys_per_node = args.group_by { |key| node_for(key) }
|
173
181
|
keys_per_node.inject(0) do |sum, (node, keys)|
|
174
182
|
sum + node.unlink(*keys)
|
@@ -177,23 +185,16 @@ class Redis
|
|
177
185
|
|
178
186
|
# Determine if a key exists.
|
179
187
|
def exists(*args)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
188
|
+
args.flatten!(1)
|
189
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
190
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
191
|
+
sum + node.exists(*keys)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
195
195
|
# Determine if any of the keys exists.
|
196
196
|
def exists?(*args)
|
197
|
+
args.flatten!(1)
|
197
198
|
keys_per_node = args.group_by { |key| node_for(key) }
|
198
199
|
keys_per_node.each do |node, keys|
|
199
200
|
return true if node.exists?(*keys)
|
@@ -297,7 +298,7 @@ class Redis
|
|
297
298
|
end
|
298
299
|
|
299
300
|
# Set multiple keys to multiple values.
|
300
|
-
def mset(*
|
301
|
+
def mset(*)
|
301
302
|
raise CannotDistribute, :mset
|
302
303
|
end
|
303
304
|
|
@@ -306,7 +307,7 @@ class Redis
|
|
306
307
|
end
|
307
308
|
|
308
309
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
309
|
-
def msetnx(*
|
310
|
+
def msetnx(*)
|
310
311
|
raise CannotDistribute, :msetnx
|
311
312
|
end
|
312
313
|
|
@@ -331,11 +332,13 @@ class Redis
|
|
331
332
|
|
332
333
|
# Get the values of all the given keys as an Array.
|
333
334
|
def mget(*keys)
|
335
|
+
keys.flatten!(1)
|
334
336
|
mapped_mget(*keys).values_at(*keys)
|
335
337
|
end
|
336
338
|
|
337
339
|
# Get the values of all the given keys as a Hash.
|
338
340
|
def mapped_mget(*keys)
|
341
|
+
keys.flatten!(1)
|
339
342
|
keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
|
340
343
|
results.merge! node.mapped_mget(*subkeys)
|
341
344
|
end
|
@@ -373,8 +376,9 @@ class Redis
|
|
373
376
|
|
374
377
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
375
378
|
def bitop(operation, destkey, *keys)
|
379
|
+
keys.flatten!(1)
|
376
380
|
ensure_same_node(:bitop, [destkey] + keys) do |node|
|
377
|
-
node.bitop(operation, destkey,
|
381
|
+
node.bitop(operation, destkey, keys)
|
378
382
|
end
|
379
383
|
end
|
380
384
|
|
@@ -463,23 +467,15 @@ class Redis
|
|
463
467
|
timeout = if args.last.is_a?(Hash)
|
464
468
|
options = args.pop
|
465
469
|
options[:timeout]
|
466
|
-
elsif args.last.respond_to?(:to_int)
|
467
|
-
last_arg = args.pop
|
468
|
-
::Redis.deprecate!(
|
469
|
-
"Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
|
470
|
-
" redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
|
471
|
-
"(called from: #{caller(2, 1).first})"
|
472
|
-
)
|
473
|
-
last_arg.to_int
|
474
470
|
end
|
475
471
|
|
476
|
-
|
472
|
+
args.flatten!(1)
|
477
473
|
|
478
|
-
ensure_same_node(cmd,
|
474
|
+
ensure_same_node(cmd, args) do |node|
|
479
475
|
if timeout
|
480
|
-
node.__send__(cmd,
|
476
|
+
node.__send__(cmd, args, timeout: timeout)
|
481
477
|
else
|
482
|
-
node.__send__(cmd,
|
478
|
+
node.__send__(cmd, args)
|
483
479
|
end
|
484
480
|
end
|
485
481
|
end
|
@@ -490,6 +486,18 @@ class Redis
|
|
490
486
|
_bpop(:blpop, args)
|
491
487
|
end
|
492
488
|
|
489
|
+
def bzpopmax(*args)
|
490
|
+
_bpop(:bzpopmax, args) do |reply|
|
491
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def bzpopmin(*args)
|
496
|
+
_bpop(:bzpopmin, args) do |reply|
|
497
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
493
501
|
# Remove and get the last element in a list, or block until one is
|
494
502
|
# available.
|
495
503
|
def brpop(*args)
|
@@ -498,9 +506,9 @@ class Redis
|
|
498
506
|
|
499
507
|
# Pop a value from a list, push it to another list and return it; or block
|
500
508
|
# until one is available.
|
501
|
-
def brpoplpush(source, destination,
|
509
|
+
def brpoplpush(source, destination, **options)
|
502
510
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
503
|
-
node.brpoplpush(source, destination,
|
511
|
+
node.brpoplpush(source, destination, **options)
|
504
512
|
end
|
505
513
|
end
|
506
514
|
|
@@ -540,23 +548,23 @@ class Redis
|
|
540
548
|
end
|
541
549
|
|
542
550
|
# Add one or more members to a set.
|
543
|
-
def sadd(key,
|
544
|
-
node_for(key).sadd(key,
|
551
|
+
def sadd(key, *members)
|
552
|
+
node_for(key).sadd(key, *members)
|
545
553
|
end
|
546
554
|
|
547
555
|
# Add one or more members to a set.
|
548
|
-
def sadd?(key,
|
549
|
-
node_for(key).sadd?(key,
|
556
|
+
def sadd?(key, *members)
|
557
|
+
node_for(key).sadd?(key, *members)
|
550
558
|
end
|
551
559
|
|
552
560
|
# Remove one or more members from a set.
|
553
|
-
def srem(key,
|
554
|
-
node_for(key).srem(key,
|
561
|
+
def srem(key, *members)
|
562
|
+
node_for(key).srem(key, *members)
|
555
563
|
end
|
556
564
|
|
557
565
|
# Remove one or more members from a set.
|
558
|
-
def srem?(key,
|
559
|
-
node_for(key).srem?(key,
|
566
|
+
def srem?(key, *members)
|
567
|
+
node_for(key).srem?(key, *members)
|
560
568
|
end
|
561
569
|
|
562
570
|
# Remove and return a random member from a set.
|
@@ -603,43 +611,49 @@ class Redis
|
|
603
611
|
|
604
612
|
# Subtract multiple sets.
|
605
613
|
def sdiff(*keys)
|
614
|
+
keys.flatten!(1)
|
606
615
|
ensure_same_node(:sdiff, keys) do |node|
|
607
|
-
node.sdiff(
|
616
|
+
node.sdiff(keys)
|
608
617
|
end
|
609
618
|
end
|
610
619
|
|
611
620
|
# Subtract multiple sets and store the resulting set in a key.
|
612
621
|
def sdiffstore(destination, *keys)
|
613
|
-
|
614
|
-
|
622
|
+
keys.flatten!(1)
|
623
|
+
ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
|
624
|
+
node.sdiffstore(destination, keys)
|
615
625
|
end
|
616
626
|
end
|
617
627
|
|
618
628
|
# Intersect multiple sets.
|
619
629
|
def sinter(*keys)
|
630
|
+
keys.flatten!(1)
|
620
631
|
ensure_same_node(:sinter, keys) do |node|
|
621
|
-
node.sinter(
|
632
|
+
node.sinter(keys)
|
622
633
|
end
|
623
634
|
end
|
624
635
|
|
625
636
|
# Intersect multiple sets and store the resulting set in a key.
|
626
637
|
def sinterstore(destination, *keys)
|
627
|
-
|
628
|
-
|
638
|
+
keys.flatten!(1)
|
639
|
+
ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
|
640
|
+
node.sinterstore(destination, keys)
|
629
641
|
end
|
630
642
|
end
|
631
643
|
|
632
644
|
# Add multiple sets.
|
633
645
|
def sunion(*keys)
|
646
|
+
keys.flatten!(1)
|
634
647
|
ensure_same_node(:sunion, keys) do |node|
|
635
|
-
node.sunion(
|
648
|
+
node.sunion(keys)
|
636
649
|
end
|
637
650
|
end
|
638
651
|
|
639
652
|
# Add multiple sets and store the resulting set in a key.
|
640
653
|
def sunionstore(destination, *keys)
|
641
|
-
|
642
|
-
|
654
|
+
keys.flatten!(1)
|
655
|
+
ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
|
656
|
+
node.sunionstore(destination, keys)
|
643
657
|
end
|
644
658
|
end
|
645
659
|
|
@@ -738,43 +752,49 @@ class Redis
|
|
738
752
|
|
739
753
|
# Get the intersection of multiple sorted sets
|
740
754
|
def zinter(*keys, **options)
|
755
|
+
keys.flatten!(1)
|
741
756
|
ensure_same_node(:zinter, keys) do |node|
|
742
|
-
node.zinter(
|
757
|
+
node.zinter(keys, **options)
|
743
758
|
end
|
744
759
|
end
|
745
760
|
|
746
761
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
747
762
|
# key.
|
748
|
-
def zinterstore(destination, keys, **options)
|
749
|
-
|
763
|
+
def zinterstore(destination, *keys, **options)
|
764
|
+
keys.flatten!(1)
|
765
|
+
ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
|
750
766
|
node.zinterstore(destination, keys, **options)
|
751
767
|
end
|
752
768
|
end
|
753
769
|
|
754
770
|
# Return the union of multiple sorted sets.
|
755
771
|
def zunion(*keys, **options)
|
772
|
+
keys.flatten!(1)
|
756
773
|
ensure_same_node(:zunion, keys) do |node|
|
757
|
-
node.zunion(
|
774
|
+
node.zunion(keys, **options)
|
758
775
|
end
|
759
776
|
end
|
760
777
|
|
761
778
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
762
|
-
def zunionstore(destination, keys, **options)
|
763
|
-
|
779
|
+
def zunionstore(destination, *keys, **options)
|
780
|
+
keys.flatten!(1)
|
781
|
+
ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
|
764
782
|
node.zunionstore(destination, keys, **options)
|
765
783
|
end
|
766
784
|
end
|
767
785
|
|
768
786
|
# Return the difference between the first and all successive input sorted sets.
|
769
787
|
def zdiff(*keys, **options)
|
788
|
+
keys.flatten!(1)
|
770
789
|
ensure_same_node(:zdiff, keys) do |node|
|
771
|
-
node.zdiff(
|
790
|
+
node.zdiff(keys, **options)
|
772
791
|
end
|
773
792
|
end
|
774
793
|
|
775
794
|
# Compute the difference between the first and all successive input sorted sets
|
776
795
|
# and store the resulting sorted set in a new key.
|
777
|
-
def zdiffstore(destination, keys, **options)
|
796
|
+
def zdiffstore(destination, *keys, **options)
|
797
|
+
keys.flatten!(1)
|
778
798
|
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
779
799
|
node.zdiffstore(destination, keys, **options)
|
780
800
|
end
|
@@ -801,7 +821,7 @@ class Redis
|
|
801
821
|
end
|
802
822
|
|
803
823
|
def mapped_hmset(key, hash)
|
804
|
-
node_for(key).hmset(key,
|
824
|
+
node_for(key).hmset(key, hash)
|
805
825
|
end
|
806
826
|
|
807
827
|
# Get the value of a hash field.
|
@@ -811,11 +831,13 @@ class Redis
|
|
811
831
|
|
812
832
|
# Get the values of all the given hash fields.
|
813
833
|
def hmget(key, *fields)
|
814
|
-
|
834
|
+
fields.flatten!(1)
|
835
|
+
node_for(key).hmget(key, fields)
|
815
836
|
end
|
816
837
|
|
817
838
|
def mapped_hmget(key, *fields)
|
818
|
-
|
839
|
+
fields.flatten!(1)
|
840
|
+
node_for(key).mapped_hmget(key, fields)
|
819
841
|
end
|
820
842
|
|
821
843
|
def hrandfield(key, count = nil, **options)
|
@@ -824,7 +846,8 @@ class Redis
|
|
824
846
|
|
825
847
|
# Delete one or more hash fields.
|
826
848
|
def hdel(key, *fields)
|
827
|
-
|
849
|
+
fields.flatten!(1)
|
850
|
+
node_for(key).hdel(key, fields)
|
828
851
|
end
|
829
852
|
|
830
853
|
# Determine if a hash field exists.
|
@@ -881,7 +904,7 @@ class Redis
|
|
881
904
|
|
882
905
|
# Stop listening for messages posted to the given channels.
|
883
906
|
def unsubscribe(*channels)
|
884
|
-
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
907
|
+
raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
|
885
908
|
|
886
909
|
@subscribed_node.unsubscribe(*channels)
|
887
910
|
end
|
@@ -928,9 +951,7 @@ class Redis
|
|
928
951
|
def multi(&block)
|
929
952
|
raise CannotDistribute, :multi unless @watch_key
|
930
953
|
|
931
|
-
|
932
|
-
@watch_key = nil if block_given?
|
933
|
-
result
|
954
|
+
node_for(@watch_key).multi(&block)
|
934
955
|
end
|
935
956
|
|
936
957
|
# Execute all commands issued after MULTI.
|
@@ -1020,7 +1041,8 @@ class Redis
|
|
1020
1041
|
end
|
1021
1042
|
|
1022
1043
|
def key_tag(key)
|
1023
|
-
key.to_s
|
1044
|
+
key = key.to_s
|
1045
|
+
key[@tag, 1] if key.match?(@tag)
|
1024
1046
|
end
|
1025
1047
|
|
1026
1048
|
def ensure_same_node(command, keys)
|
data/lib/redis/errors.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class Redis
|
4
4
|
# Base error for all redis-rb errors.
|
5
|
-
class BaseError <
|
5
|
+
class BaseError < StandardError
|
6
6
|
end
|
7
7
|
|
8
8
|
# Raised by the connection when a protocol error occurs.
|
@@ -20,6 +20,15 @@ class Redis
|
|
20
20
|
class CommandError < BaseError
|
21
21
|
end
|
22
22
|
|
23
|
+
class PermissionError < CommandError
|
24
|
+
end
|
25
|
+
|
26
|
+
class WrongTypeError < CommandError
|
27
|
+
end
|
28
|
+
|
29
|
+
class ReadOnlyError < CommandError
|
30
|
+
end
|
31
|
+
|
23
32
|
# Base error for connection related errors.
|
24
33
|
class BaseConnectionError < BaseError
|
25
34
|
end
|
@@ -44,54 +53,6 @@ class Redis
|
|
44
53
|
class InvalidClientOptionError < BaseError
|
45
54
|
end
|
46
55
|
|
47
|
-
class
|
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
|
-
|
57
|
-
# Raised when client connected to redis as cluster mode
|
58
|
-
# and some cluster subcommands were called.
|
59
|
-
class OrchestrationCommandNotSupported < BaseError
|
60
|
-
def initialize(command, subcommand = '')
|
61
|
-
str = [command, subcommand].map(&:to_s).reject(&:empty?).join(' ').upcase
|
62
|
-
msg = "#{str} command should be used with care "\
|
63
|
-
'only by applications orchestrating Redis Cluster, like redis-trib, '\
|
64
|
-
'and the command if used out of the right context can leave the cluster '\
|
65
|
-
'in a wrong state or cause data loss.'
|
66
|
-
super(msg)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Raised when error occurs on any node of cluster.
|
71
|
-
class CommandErrorCollection < BaseError
|
72
|
-
attr_reader :errors
|
73
|
-
|
74
|
-
# @param errors [Hash{String => Redis::CommandError}]
|
75
|
-
# @param error_message [String]
|
76
|
-
def initialize(errors, error_message = 'Command errors were replied on any node')
|
77
|
-
@errors = errors
|
78
|
-
super(error_message)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# Raised when cluster client can't select node.
|
83
|
-
class AmbiguousNodeError < BaseError
|
84
|
-
def initialize(command)
|
85
|
-
super("Cluster client doesn't know which node the #{command} command should be sent to.")
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Raised when commands in pipelining include cross slot keys.
|
90
|
-
class CrossSlotPipeliningError < BaseError
|
91
|
-
def initialize(keys)
|
92
|
-
super("Cluster client couldn't send pipelining to single node. "\
|
93
|
-
"The commands include cross slot keys. #{keys}")
|
94
|
-
end
|
95
|
-
end
|
56
|
+
class SubscriptionError < BaseError
|
96
57
|
end
|
97
58
|
end
|
data/lib/redis/hash_ring.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'zlib'
|
4
|
+
require 'digest/md5'
|
4
5
|
|
5
6
|
class Redis
|
6
7
|
class HashRing
|
@@ -25,7 +26,7 @@ class Redis
|
|
25
26
|
def add_node(node)
|
26
27
|
@nodes << node
|
27
28
|
@replicas.times do |i|
|
28
|
-
key =
|
29
|
+
key = server_hash_for("#{node.id}:#{i}")
|
29
30
|
@ring[key] = node
|
30
31
|
@sorted_keys << key
|
31
32
|
end
|
@@ -35,7 +36,7 @@ class Redis
|
|
35
36
|
def remove_node(node)
|
36
37
|
@nodes.reject! { |n| n.id == node.id }
|
37
38
|
@replicas.times do |i|
|
38
|
-
key =
|
39
|
+
key = server_hash_for("#{node.id}:#{i}")
|
39
40
|
@ring.delete(key)
|
40
41
|
@sorted_keys.reject! { |k| k == key }
|
41
42
|
end
|
@@ -43,47 +44,46 @@ class Redis
|
|
43
44
|
|
44
45
|
# get the node in the hash ring for this key
|
45
46
|
def get_node(key)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
def get_node_pos(key)
|
50
|
-
return [nil, nil] if @ring.empty?
|
51
|
-
|
52
|
-
crc = Zlib.crc32(key)
|
53
|
-
idx = HashRing.binary_search(@sorted_keys, crc)
|
54
|
-
[@ring[@sorted_keys[idx]], idx]
|
47
|
+
hash = hash_for(key)
|
48
|
+
idx = binary_search(@sorted_keys, hash)
|
49
|
+
@ring[@sorted_keys[idx]]
|
55
50
|
end
|
56
51
|
|
57
52
|
def iter_nodes(key)
|
58
53
|
return [nil, nil] if @ring.empty?
|
59
54
|
|
60
|
-
|
55
|
+
crc = hash_for(key)
|
56
|
+
pos = binary_search(@sorted_keys, crc)
|
61
57
|
@ring.size.times do |n|
|
62
58
|
yield @ring[@sorted_keys[(pos + n) % @ring.size]]
|
63
59
|
end
|
64
60
|
end
|
65
61
|
|
62
|
+
private
|
63
|
+
|
64
|
+
def hash_for(key)
|
65
|
+
Zlib.crc32(key)
|
66
|
+
end
|
67
|
+
|
68
|
+
def server_hash_for(key)
|
69
|
+
Digest::MD5.digest(key).unpack1("L>")
|
70
|
+
end
|
71
|
+
|
66
72
|
# Find the closest index in HashRing with value <= the given value
|
67
|
-
def
|
68
|
-
upper = ary.size
|
73
|
+
def binary_search(ary, value)
|
74
|
+
upper = ary.size
|
69
75
|
lower = 0
|
70
|
-
idx = 0
|
71
|
-
|
72
|
-
while lower <= upper
|
73
|
-
idx = (lower + upper) / 2
|
74
|
-
comp = ary[idx] <=> value
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
upper =
|
77
|
+
while lower < upper
|
78
|
+
mid = (lower + upper) / 2
|
79
|
+
if ary[mid] > value
|
80
|
+
upper = mid
|
80
81
|
else
|
81
|
-
lower =
|
82
|
+
lower = mid + 1
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
upper
|
86
|
-
upper
|
86
|
+
upper - 1
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|