redis 4.2.5 → 5.0.7
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 +167 -0
- data/README.md +102 -162
- data/lib/redis/client.rb +84 -589
- data/lib/redis/commands/bitmaps.rb +66 -0
- data/lib/redis/commands/cluster.rb +28 -0
- data/lib/redis/commands/connection.rb +53 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +254 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +437 -0
- data/lib/redis/commands/lists.rb +339 -0
- data/lib/redis/commands/pubsub.rb +54 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +214 -0
- data/lib/redis/commands/sorted_sets.rb +884 -0
- data/lib/redis/commands/streams.rb +402 -0
- data/lib/redis/commands/strings.rb +314 -0
- data/lib/redis/commands/transactions.rb +115 -0
- data/lib/redis/commands.rb +237 -0
- data/lib/redis/distributed.rb +220 -75
- data/lib/redis/errors.rb +15 -41
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +66 -120
- data/lib/redis/subscribe.rb +23 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +110 -3441
- metadata +27 -54
- data/lib/redis/cluster/command.rb +0 -81
- data/lib/redis/cluster/command_loader.rb +0 -34
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -107
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -37
- data/lib/redis/cluster/option.rb +0 -90
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -49
- data/lib/redis/cluster.rb +0 -295
- data/lib/redis/connection/command_helper.rb +0 -39
- data/lib/redis/connection/hiredis.rb +0 -67
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -427
- data/lib/redis/connection/synchrony.rb +0 -146
- data/lib/redis/connection.rb +0 -11
data/lib/redis/distributed.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "redis/hash_ring"
|
4
4
|
|
5
5
|
class Redis
|
6
6
|
class Distributed
|
@@ -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
|
@@ -115,13 +121,13 @@ class Redis
|
|
115
121
|
end
|
116
122
|
|
117
123
|
# Set a key's time to live in seconds.
|
118
|
-
def expire(key, seconds)
|
119
|
-
node_for(key).expire(key, seconds)
|
124
|
+
def expire(key, seconds, **kwargs)
|
125
|
+
node_for(key).expire(key, seconds, **kwargs)
|
120
126
|
end
|
121
127
|
|
122
128
|
# Set the expiration for a key as a UNIX timestamp.
|
123
|
-
def expireat(key, unix_time)
|
124
|
-
node_for(key).expireat(key, unix_time)
|
129
|
+
def expireat(key, unix_time, **kwargs)
|
130
|
+
node_for(key).expireat(key, unix_time, **kwargs)
|
125
131
|
end
|
126
132
|
|
127
133
|
# Get the time to live (in seconds) for a key.
|
@@ -130,13 +136,13 @@ class Redis
|
|
130
136
|
end
|
131
137
|
|
132
138
|
# Set a key's time to live in milliseconds.
|
133
|
-
def pexpire(key, milliseconds)
|
134
|
-
node_for(key).pexpire(key, milliseconds)
|
139
|
+
def pexpire(key, milliseconds, **kwarg)
|
140
|
+
node_for(key).pexpire(key, milliseconds, **kwarg)
|
135
141
|
end
|
136
142
|
|
137
143
|
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
|
138
|
-
def pexpireat(key, ms_unix_time)
|
139
|
-
node_for(key).pexpireat(key, ms_unix_time)
|
144
|
+
def pexpireat(key, ms_unix_time, **kwarg)
|
145
|
+
node_for(key).pexpireat(key, ms_unix_time, **kwarg)
|
140
146
|
end
|
141
147
|
|
142
148
|
# Get the time to live (in milliseconds) for a key.
|
@@ -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,27 +185,16 @@ class Redis
|
|
177
185
|
|
178
186
|
# Determine if a key exists.
|
179
187
|
def exists(*args)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
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)
|
196
192
|
end
|
197
193
|
end
|
198
194
|
|
199
195
|
# Determine if any of the keys exists.
|
200
196
|
def exists?(*args)
|
197
|
+
args.flatten!(1)
|
201
198
|
keys_per_node = args.group_by { |key| node_for(key) }
|
202
199
|
keys_per_node.each do |node, keys|
|
203
200
|
return true if node.exists?(*keys)
|
@@ -215,6 +212,13 @@ class Redis
|
|
215
212
|
node_for(key).move(key, db)
|
216
213
|
end
|
217
214
|
|
215
|
+
# Copy a value from one key to another.
|
216
|
+
def copy(source, destination, **options)
|
217
|
+
ensure_same_node(:copy, [source, destination]) do |node|
|
218
|
+
node.copy(source, destination, **options)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
218
222
|
# Return a random key from the keyspace.
|
219
223
|
def randomkey
|
220
224
|
raise CannotDistribute, :randomkey
|
@@ -294,7 +298,7 @@ class Redis
|
|
294
298
|
end
|
295
299
|
|
296
300
|
# Set multiple keys to multiple values.
|
297
|
-
def mset(*
|
301
|
+
def mset(*)
|
298
302
|
raise CannotDistribute, :mset
|
299
303
|
end
|
300
304
|
|
@@ -303,7 +307,7 @@ class Redis
|
|
303
307
|
end
|
304
308
|
|
305
309
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
306
|
-
def msetnx(*
|
310
|
+
def msetnx(*)
|
307
311
|
raise CannotDistribute, :msetnx
|
308
312
|
end
|
309
313
|
|
@@ -316,13 +320,25 @@ class Redis
|
|
316
320
|
node_for(key).get(key)
|
317
321
|
end
|
318
322
|
|
323
|
+
# Get the value of a key and delete it.
|
324
|
+
def getdel(key)
|
325
|
+
node_for(key).getdel(key)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Get the value of a key and sets its time to live based on options.
|
329
|
+
def getex(key, **options)
|
330
|
+
node_for(key).getex(key, **options)
|
331
|
+
end
|
332
|
+
|
319
333
|
# Get the values of all the given keys as an Array.
|
320
334
|
def mget(*keys)
|
335
|
+
keys.flatten!(1)
|
321
336
|
mapped_mget(*keys).values_at(*keys)
|
322
337
|
end
|
323
338
|
|
324
339
|
# Get the values of all the given keys as a Hash.
|
325
340
|
def mapped_mget(*keys)
|
341
|
+
keys.flatten!(1)
|
326
342
|
keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
|
327
343
|
results.merge! node.mapped_mget(*subkeys)
|
328
344
|
end
|
@@ -360,8 +376,9 @@ class Redis
|
|
360
376
|
|
361
377
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
362
378
|
def bitop(operation, destkey, *keys)
|
379
|
+
keys.flatten!(1)
|
363
380
|
ensure_same_node(:bitop, [destkey] + keys) do |node|
|
364
|
-
node.bitop(operation, destkey,
|
381
|
+
node.bitop(operation, destkey, keys)
|
365
382
|
end
|
366
383
|
end
|
367
384
|
|
@@ -393,6 +410,21 @@ class Redis
|
|
393
410
|
node_for(key).llen(key)
|
394
411
|
end
|
395
412
|
|
413
|
+
# Remove the first/last element in a list, append/prepend it to another list and return it.
|
414
|
+
def lmove(source, destination, where_source, where_destination)
|
415
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
416
|
+
node.lmove(source, destination, where_source, where_destination)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
# Remove the first/last element in a list and append/prepend it
|
421
|
+
# to another list and return it, or block until one is available.
|
422
|
+
def blmove(source, destination, where_source, where_destination, timeout: 0)
|
423
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
424
|
+
node.blmove(source, destination, where_source, where_destination, timeout: timeout)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
396
428
|
# Prepend one or more values to a list.
|
397
429
|
def lpush(key, value)
|
398
430
|
node_for(key).lpush(key, value)
|
@@ -413,14 +445,14 @@ class Redis
|
|
413
445
|
node_for(key).rpushx(key, value)
|
414
446
|
end
|
415
447
|
|
416
|
-
# Remove and get the first
|
417
|
-
def lpop(key)
|
418
|
-
node_for(key).lpop(key)
|
448
|
+
# Remove and get the first elements in a list.
|
449
|
+
def lpop(key, count = nil)
|
450
|
+
node_for(key).lpop(key, count)
|
419
451
|
end
|
420
452
|
|
421
|
-
# Remove and get the last
|
422
|
-
def rpop(key)
|
423
|
-
node_for(key).rpop(key)
|
453
|
+
# Remove and get the last elements in a list.
|
454
|
+
def rpop(key, count = nil)
|
455
|
+
node_for(key).rpop(key, count)
|
424
456
|
end
|
425
457
|
|
426
458
|
# Remove the last element in a list, append it to another list and return
|
@@ -435,22 +467,15 @@ class Redis
|
|
435
467
|
timeout = if args.last.is_a?(Hash)
|
436
468
|
options = args.pop
|
437
469
|
options[:timeout]
|
438
|
-
elsif args.last.respond_to?(:to_int)
|
439
|
-
# Issue deprecation notice in obnoxious mode...
|
440
|
-
args.pop.to_int
|
441
|
-
end
|
442
|
-
|
443
|
-
if args.size > 1
|
444
|
-
# Issue deprecation notice in obnoxious mode...
|
445
470
|
end
|
446
471
|
|
447
|
-
|
472
|
+
args.flatten!(1)
|
448
473
|
|
449
|
-
ensure_same_node(cmd,
|
474
|
+
ensure_same_node(cmd, args) do |node|
|
450
475
|
if timeout
|
451
|
-
node.__send__(cmd,
|
476
|
+
node.__send__(cmd, args, timeout: timeout)
|
452
477
|
else
|
453
|
-
node.__send__(cmd,
|
478
|
+
node.__send__(cmd, args)
|
454
479
|
end
|
455
480
|
end
|
456
481
|
end
|
@@ -461,6 +486,18 @@ class Redis
|
|
461
486
|
_bpop(:blpop, args)
|
462
487
|
end
|
463
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
|
+
|
464
501
|
# Remove and get the last element in a list, or block until one is
|
465
502
|
# available.
|
466
503
|
def brpop(*args)
|
@@ -469,9 +506,9 @@ class Redis
|
|
469
506
|
|
470
507
|
# Pop a value from a list, push it to another list and return it; or block
|
471
508
|
# until one is available.
|
472
|
-
def brpoplpush(source, destination,
|
509
|
+
def brpoplpush(source, destination, **options)
|
473
510
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
474
|
-
node.brpoplpush(source, destination,
|
511
|
+
node.brpoplpush(source, destination, **options)
|
475
512
|
end
|
476
513
|
end
|
477
514
|
|
@@ -505,19 +542,43 @@ class Redis
|
|
505
542
|
node_for(key).ltrim(key, start, stop)
|
506
543
|
end
|
507
544
|
|
545
|
+
# Iterate over keys, blocking and removing elements from the first non empty liist found.
|
546
|
+
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
|
547
|
+
ensure_same_node(:blmpop, keys) do |node|
|
548
|
+
node.blmpop(timeout, *keys, modifier: modifier, count: count)
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
# Iterate over keys, removing elements from the first non list found.
|
553
|
+
def lmpop(*keys, modifier: "LEFT", count: nil)
|
554
|
+
ensure_same_node(:lmpop, keys) do |node|
|
555
|
+
node.lmpop(*keys, modifier: modifier, count: count)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
508
559
|
# Get the number of members in a set.
|
509
560
|
def scard(key)
|
510
561
|
node_for(key).scard(key)
|
511
562
|
end
|
512
563
|
|
513
564
|
# Add one or more members to a set.
|
514
|
-
def sadd(key,
|
515
|
-
node_for(key).sadd(key,
|
565
|
+
def sadd(key, *members)
|
566
|
+
node_for(key).sadd(key, *members)
|
567
|
+
end
|
568
|
+
|
569
|
+
# Add one or more members to a set.
|
570
|
+
def sadd?(key, *members)
|
571
|
+
node_for(key).sadd?(key, *members)
|
516
572
|
end
|
517
573
|
|
518
574
|
# Remove one or more members from a set.
|
519
|
-
def srem(key,
|
520
|
-
node_for(key).srem(key,
|
575
|
+
def srem(key, *members)
|
576
|
+
node_for(key).srem(key, *members)
|
577
|
+
end
|
578
|
+
|
579
|
+
# Remove one or more members from a set.
|
580
|
+
def srem?(key, *members)
|
581
|
+
node_for(key).srem?(key, *members)
|
521
582
|
end
|
522
583
|
|
523
584
|
# Remove and return a random member from a set.
|
@@ -542,6 +603,11 @@ class Redis
|
|
542
603
|
node_for(key).sismember(key, member)
|
543
604
|
end
|
544
605
|
|
606
|
+
# Determine if multiple values are members of a set.
|
607
|
+
def smismember(key, *members)
|
608
|
+
node_for(key).smismember(key, *members)
|
609
|
+
end
|
610
|
+
|
545
611
|
# Get all the members in a set.
|
546
612
|
def smembers(key)
|
547
613
|
node_for(key).smembers(key)
|
@@ -559,43 +625,49 @@ class Redis
|
|
559
625
|
|
560
626
|
# Subtract multiple sets.
|
561
627
|
def sdiff(*keys)
|
628
|
+
keys.flatten!(1)
|
562
629
|
ensure_same_node(:sdiff, keys) do |node|
|
563
|
-
node.sdiff(
|
630
|
+
node.sdiff(keys)
|
564
631
|
end
|
565
632
|
end
|
566
633
|
|
567
634
|
# Subtract multiple sets and store the resulting set in a key.
|
568
635
|
def sdiffstore(destination, *keys)
|
569
|
-
|
570
|
-
|
636
|
+
keys.flatten!(1)
|
637
|
+
ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
|
638
|
+
node.sdiffstore(destination, keys)
|
571
639
|
end
|
572
640
|
end
|
573
641
|
|
574
642
|
# Intersect multiple sets.
|
575
643
|
def sinter(*keys)
|
644
|
+
keys.flatten!(1)
|
576
645
|
ensure_same_node(:sinter, keys) do |node|
|
577
|
-
node.sinter(
|
646
|
+
node.sinter(keys)
|
578
647
|
end
|
579
648
|
end
|
580
649
|
|
581
650
|
# Intersect multiple sets and store the resulting set in a key.
|
582
651
|
def sinterstore(destination, *keys)
|
583
|
-
|
584
|
-
|
652
|
+
keys.flatten!(1)
|
653
|
+
ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
|
654
|
+
node.sinterstore(destination, keys)
|
585
655
|
end
|
586
656
|
end
|
587
657
|
|
588
658
|
# Add multiple sets.
|
589
659
|
def sunion(*keys)
|
660
|
+
keys.flatten!(1)
|
590
661
|
ensure_same_node(:sunion, keys) do |node|
|
591
|
-
node.sunion(
|
662
|
+
node.sunion(keys)
|
592
663
|
end
|
593
664
|
end
|
594
665
|
|
595
666
|
# Add multiple sets and store the resulting set in a key.
|
596
667
|
def sunionstore(destination, *keys)
|
597
|
-
|
598
|
-
|
668
|
+
keys.flatten!(1)
|
669
|
+
ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
|
670
|
+
node.sunionstore(destination, keys)
|
599
671
|
end
|
600
672
|
end
|
601
673
|
|
@@ -626,11 +698,43 @@ class Redis
|
|
626
698
|
node_for(key).zscore(key, member)
|
627
699
|
end
|
628
700
|
|
629
|
-
#
|
701
|
+
# Get one or more random members from a sorted set.
|
702
|
+
def zrandmember(key, count = nil, **options)
|
703
|
+
node_for(key).zrandmember(key, count, **options)
|
704
|
+
end
|
705
|
+
|
706
|
+
# Get the scores associated with the given members in a sorted set.
|
707
|
+
def zmscore(key, *members)
|
708
|
+
node_for(key).zmscore(key, *members)
|
709
|
+
end
|
710
|
+
|
711
|
+
# Iterate over keys, blocking and removing members from the first non empty sorted set found.
|
712
|
+
def bzmpop(timeout, *keys, modifier: "MIN", count: nil)
|
713
|
+
ensure_same_node(:bzmpop, keys) do |node|
|
714
|
+
node.bzmpop(timeout, *keys, modifier: modifier, count: count)
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
# Iterate over keys, removing members from the first non empty sorted set found.
|
719
|
+
def zmpop(*keys, modifier: "MIN", count: nil)
|
720
|
+
ensure_same_node(:zmpop, keys) do |node|
|
721
|
+
node.zmpop(*keys, modifier: modifier, count: count)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
630
726
|
def zrange(key, start, stop, **options)
|
631
727
|
node_for(key).zrange(key, start, stop, **options)
|
632
728
|
end
|
633
729
|
|
730
|
+
# Select a range of members in a sorted set, by index, score or lexicographical ordering
|
731
|
+
# and store the resulting sorted set in a new key.
|
732
|
+
def zrangestore(dest_key, src_key, start, stop, **options)
|
733
|
+
ensure_same_node(:zrangestore, [dest_key, src_key]) do |node|
|
734
|
+
node.zrangestore(dest_key, src_key, start, stop, **options)
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
634
738
|
# Return a range of members in a sorted set, by index, with scores ordered
|
635
739
|
# from high to low.
|
636
740
|
def zrevrange(key, start, stop, **options)
|
@@ -674,21 +778,56 @@ class Redis
|
|
674
778
|
node_for(key).zcount(key, min, max)
|
675
779
|
end
|
676
780
|
|
781
|
+
# Get the intersection of multiple sorted sets
|
782
|
+
def zinter(*keys, **options)
|
783
|
+
keys.flatten!(1)
|
784
|
+
ensure_same_node(:zinter, keys) do |node|
|
785
|
+
node.zinter(keys, **options)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
677
789
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
678
790
|
# key.
|
679
|
-
def zinterstore(destination, keys, **options)
|
680
|
-
|
791
|
+
def zinterstore(destination, *keys, **options)
|
792
|
+
keys.flatten!(1)
|
793
|
+
ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
|
681
794
|
node.zinterstore(destination, keys, **options)
|
682
795
|
end
|
683
796
|
end
|
684
797
|
|
798
|
+
# Return the union of multiple sorted sets.
|
799
|
+
def zunion(*keys, **options)
|
800
|
+
keys.flatten!(1)
|
801
|
+
ensure_same_node(:zunion, keys) do |node|
|
802
|
+
node.zunion(keys, **options)
|
803
|
+
end
|
804
|
+
end
|
805
|
+
|
685
806
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
686
|
-
def zunionstore(destination, keys, **options)
|
687
|
-
|
807
|
+
def zunionstore(destination, *keys, **options)
|
808
|
+
keys.flatten!(1)
|
809
|
+
ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
|
688
810
|
node.zunionstore(destination, keys, **options)
|
689
811
|
end
|
690
812
|
end
|
691
813
|
|
814
|
+
# Return the difference between the first and all successive input sorted sets.
|
815
|
+
def zdiff(*keys, **options)
|
816
|
+
keys.flatten!(1)
|
817
|
+
ensure_same_node(:zdiff, keys) do |node|
|
818
|
+
node.zdiff(keys, **options)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
# Compute the difference between the first and all successive input sorted sets
|
823
|
+
# and store the resulting sorted set in a new key.
|
824
|
+
def zdiffstore(destination, *keys, **options)
|
825
|
+
keys.flatten!(1)
|
826
|
+
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
827
|
+
node.zdiffstore(destination, keys, **options)
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
692
831
|
# Get the number of fields in a hash.
|
693
832
|
def hlen(key)
|
694
833
|
node_for(key).hlen(key)
|
@@ -710,7 +849,7 @@ class Redis
|
|
710
849
|
end
|
711
850
|
|
712
851
|
def mapped_hmset(key, hash)
|
713
|
-
node_for(key).hmset(key,
|
852
|
+
node_for(key).hmset(key, hash)
|
714
853
|
end
|
715
854
|
|
716
855
|
# Get the value of a hash field.
|
@@ -720,16 +859,23 @@ class Redis
|
|
720
859
|
|
721
860
|
# Get the values of all the given hash fields.
|
722
861
|
def hmget(key, *fields)
|
723
|
-
|
862
|
+
fields.flatten!(1)
|
863
|
+
node_for(key).hmget(key, fields)
|
724
864
|
end
|
725
865
|
|
726
866
|
def mapped_hmget(key, *fields)
|
727
|
-
|
867
|
+
fields.flatten!(1)
|
868
|
+
node_for(key).mapped_hmget(key, fields)
|
869
|
+
end
|
870
|
+
|
871
|
+
def hrandfield(key, count = nil, **options)
|
872
|
+
node_for(key).hrandfield(key, count, **options)
|
728
873
|
end
|
729
874
|
|
730
875
|
# Delete one or more hash fields.
|
731
876
|
def hdel(key, *fields)
|
732
|
-
|
877
|
+
fields.flatten!(1)
|
878
|
+
node_for(key).hdel(key, fields)
|
733
879
|
end
|
734
880
|
|
735
881
|
# Determine if a hash field exists.
|
@@ -786,7 +932,7 @@ class Redis
|
|
786
932
|
|
787
933
|
# Stop listening for messages posted to the given channels.
|
788
934
|
def unsubscribe(*channels)
|
789
|
-
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
935
|
+
raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
|
790
936
|
|
791
937
|
@subscribed_node.unsubscribe(*channels)
|
792
938
|
end
|
@@ -833,9 +979,7 @@ class Redis
|
|
833
979
|
def multi(&block)
|
834
980
|
raise CannotDistribute, :multi unless @watch_key
|
835
981
|
|
836
|
-
|
837
|
-
@watch_key = nil if block_given?
|
838
|
-
result
|
982
|
+
node_for(@watch_key).multi(&block)
|
839
983
|
end
|
840
984
|
|
841
985
|
# Execute all commands issued after MULTI.
|
@@ -925,7 +1069,8 @@ class Redis
|
|
925
1069
|
end
|
926
1070
|
|
927
1071
|
def key_tag(key)
|
928
|
-
key.to_s
|
1072
|
+
key = key.to_s
|
1073
|
+
key[@tag, 1] if key.match?(@tag)
|
929
1074
|
end
|
930
1075
|
|
931
1076
|
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 OutOfMemoryError < CommandError
|
30
|
+
end
|
31
|
+
|
23
32
|
# Base error for connection related errors.
|
24
33
|
class BaseConnectionError < BaseError
|
25
34
|
end
|
@@ -40,49 +49,14 @@ class Redis
|
|
40
49
|
class InheritedError < BaseConnectionError
|
41
50
|
end
|
42
51
|
|
52
|
+
# Generally raised during Redis failover scenarios
|
53
|
+
class ReadOnlyError < BaseConnectionError
|
54
|
+
end
|
55
|
+
|
43
56
|
# Raised when client options are invalid.
|
44
57
|
class InvalidClientOptionError < BaseError
|
45
58
|
end
|
46
59
|
|
47
|
-
class
|
48
|
-
# Raised when client connected to redis as cluster mode
|
49
|
-
# and some cluster subcommands were called.
|
50
|
-
class OrchestrationCommandNotSupported < BaseError
|
51
|
-
def initialize(command, subcommand = '')
|
52
|
-
str = [command, subcommand].map(&:to_s).reject(&:empty?).join(' ').upcase
|
53
|
-
msg = "#{str} command should be used with care "\
|
54
|
-
'only by applications orchestrating Redis Cluster, like redis-trib, '\
|
55
|
-
'and the command if used out of the right context can leave the cluster '\
|
56
|
-
'in a wrong state or cause data loss.'
|
57
|
-
super(msg)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Raised when error occurs on any node of cluster.
|
62
|
-
class CommandErrorCollection < BaseError
|
63
|
-
attr_reader :errors
|
64
|
-
|
65
|
-
# @param errors [Hash{String => Redis::CommandError}]
|
66
|
-
# @param error_message [String]
|
67
|
-
def initialize(errors, error_message = 'Command errors were replied on any node')
|
68
|
-
@errors = errors
|
69
|
-
super(error_message)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Raised when cluster client can't select node.
|
74
|
-
class AmbiguousNodeError < BaseError
|
75
|
-
def initialize(command)
|
76
|
-
super("Cluster client doesn't know which node the #{command} command should be sent to.")
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Raised when commands in pipelining include cross slot keys.
|
81
|
-
class CrossSlotPipeliningError < BaseError
|
82
|
-
def initialize(keys)
|
83
|
-
super("Cluster client couldn't send pipelining to single node. "\
|
84
|
-
"The commands include cross slot keys. #{keys}")
|
85
|
-
end
|
86
|
-
end
|
60
|
+
class SubscriptionError < BaseError
|
87
61
|
end
|
88
62
|
end
|