redis 3.3.5 → 5.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +290 -2
  3. data/README.md +146 -146
  4. data/lib/redis/client.rb +79 -541
  5. data/lib/redis/commands/bitmaps.rb +66 -0
  6. data/lib/redis/commands/cluster.rb +28 -0
  7. data/lib/redis/commands/connection.rb +53 -0
  8. data/lib/redis/commands/geo.rb +84 -0
  9. data/lib/redis/commands/hashes.rb +254 -0
  10. data/lib/redis/commands/hyper_log_log.rb +37 -0
  11. data/lib/redis/commands/keys.rb +437 -0
  12. data/lib/redis/commands/lists.rb +339 -0
  13. data/lib/redis/commands/pubsub.rb +54 -0
  14. data/lib/redis/commands/scripting.rb +114 -0
  15. data/lib/redis/commands/server.rb +188 -0
  16. data/lib/redis/commands/sets.rb +214 -0
  17. data/lib/redis/commands/sorted_sets.rb +884 -0
  18. data/lib/redis/commands/streams.rb +402 -0
  19. data/lib/redis/commands/strings.rb +314 -0
  20. data/lib/redis/commands/transactions.rb +115 -0
  21. data/lib/redis/commands.rb +237 -0
  22. data/lib/redis/distributed.rb +328 -108
  23. data/lib/redis/errors.rb +23 -1
  24. data/lib/redis/hash_ring.rb +36 -79
  25. data/lib/redis/pipeline.rb +69 -83
  26. data/lib/redis/subscribe.rb +26 -19
  27. data/lib/redis/version.rb +3 -1
  28. data/lib/redis.rb +115 -2695
  29. metadata +38 -218
  30. data/.gitignore +0 -16
  31. data/.travis/Gemfile +0 -11
  32. data/.travis.yml +0 -89
  33. data/.yardopts +0 -3
  34. data/Gemfile +0 -4
  35. data/Rakefile +0 -87
  36. data/benchmarking/logging.rb +0 -71
  37. data/benchmarking/pipeline.rb +0 -51
  38. data/benchmarking/speed.rb +0 -21
  39. data/benchmarking/suite.rb +0 -24
  40. data/benchmarking/worker.rb +0 -71
  41. data/examples/basic.rb +0 -15
  42. data/examples/consistency.rb +0 -114
  43. data/examples/dist_redis.rb +0 -43
  44. data/examples/incr-decr.rb +0 -17
  45. data/examples/list.rb +0 -26
  46. data/examples/pubsub.rb +0 -37
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sentinel.rb +0 -41
  50. data/examples/sets.rb +0 -36
  51. data/examples/unicorn/config.ru +0 -3
  52. data/examples/unicorn/unicorn.rb +0 -20
  53. data/lib/redis/connection/command_helper.rb +0 -44
  54. data/lib/redis/connection/hiredis.rb +0 -66
  55. data/lib/redis/connection/registry.rb +0 -12
  56. data/lib/redis/connection/ruby.rb +0 -429
  57. data/lib/redis/connection/synchrony.rb +0 -133
  58. data/lib/redis/connection.rb +0 -9
  59. data/redis.gemspec +0 -44
  60. data/test/bitpos_test.rb +0 -69
  61. data/test/blocking_commands_test.rb +0 -42
  62. data/test/client_test.rb +0 -59
  63. data/test/command_map_test.rb +0 -30
  64. data/test/commands_on_hashes_test.rb +0 -21
  65. data/test/commands_on_hyper_log_log_test.rb +0 -21
  66. data/test/commands_on_lists_test.rb +0 -20
  67. data/test/commands_on_sets_test.rb +0 -77
  68. data/test/commands_on_sorted_sets_test.rb +0 -137
  69. data/test/commands_on_strings_test.rb +0 -101
  70. data/test/commands_on_value_types_test.rb +0 -133
  71. data/test/connection_handling_test.rb +0 -277
  72. data/test/connection_test.rb +0 -57
  73. data/test/db/.gitkeep +0 -0
  74. data/test/distributed_blocking_commands_test.rb +0 -46
  75. data/test/distributed_commands_on_hashes_test.rb +0 -10
  76. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  77. data/test/distributed_commands_on_lists_test.rb +0 -22
  78. data/test/distributed_commands_on_sets_test.rb +0 -83
  79. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  80. data/test/distributed_commands_on_strings_test.rb +0 -59
  81. data/test/distributed_commands_on_value_types_test.rb +0 -95
  82. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  83. data/test/distributed_connection_handling_test.rb +0 -23
  84. data/test/distributed_internals_test.rb +0 -79
  85. data/test/distributed_key_tags_test.rb +0 -52
  86. data/test/distributed_persistence_control_commands_test.rb +0 -26
  87. data/test/distributed_publish_subscribe_test.rb +0 -92
  88. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  89. data/test/distributed_scripting_test.rb +0 -102
  90. data/test/distributed_sorting_test.rb +0 -20
  91. data/test/distributed_test.rb +0 -58
  92. data/test/distributed_transactions_test.rb +0 -32
  93. data/test/encoding_test.rb +0 -18
  94. data/test/error_replies_test.rb +0 -59
  95. data/test/fork_safety_test.rb +0 -65
  96. data/test/helper.rb +0 -232
  97. data/test/helper_test.rb +0 -24
  98. data/test/internals_test.rb +0 -417
  99. data/test/lint/blocking_commands.rb +0 -150
  100. data/test/lint/hashes.rb +0 -162
  101. data/test/lint/hyper_log_log.rb +0 -60
  102. data/test/lint/lists.rb +0 -143
  103. data/test/lint/sets.rb +0 -140
  104. data/test/lint/sorted_sets.rb +0 -316
  105. data/test/lint/strings.rb +0 -260
  106. data/test/lint/value_types.rb +0 -122
  107. data/test/persistence_control_commands_test.rb +0 -26
  108. data/test/pipelining_commands_test.rb +0 -242
  109. data/test/publish_subscribe_test.rb +0 -282
  110. data/test/remote_server_control_commands_test.rb +0 -118
  111. data/test/scanning_test.rb +0 -413
  112. data/test/scripting_test.rb +0 -78
  113. data/test/sentinel_command_test.rb +0 -80
  114. data/test/sentinel_test.rb +0 -255
  115. data/test/sorting_test.rb +0 -59
  116. data/test/ssl_test.rb +0 -73
  117. data/test/support/connection/hiredis.rb +0 -1
  118. data/test/support/connection/ruby.rb +0 -1
  119. data/test/support/connection/synchrony.rb +0 -17
  120. data/test/support/redis_mock.rb +0 -130
  121. data/test/support/ssl/gen_certs.sh +0 -31
  122. data/test/support/ssl/trusted-ca.crt +0 -25
  123. data/test/support/ssl/trusted-ca.key +0 -27
  124. data/test/support/ssl/trusted-cert.crt +0 -81
  125. data/test/support/ssl/trusted-cert.key +0 -28
  126. data/test/support/ssl/untrusted-ca.crt +0 -26
  127. data/test/support/ssl/untrusted-ca.key +0 -27
  128. data/test/support/ssl/untrusted-cert.crt +0 -82
  129. data/test/support/ssl/untrusted-cert.key +0 -28
  130. data/test/support/wire/synchrony.rb +0 -24
  131. data/test/support/wire/thread.rb +0 -5
  132. data/test/synchrony_driver.rb +0 -88
  133. data/test/test.conf.erb +0 -9
  134. data/test/thread_safety_test.rb +0 -62
  135. data/test/transactions_test.rb +0 -264
  136. data/test/unknown_commands_test.rb +0 -14
  137. data/test/url_param_test.rb +0 -138
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "redis/hash_ring"
2
4
 
3
5
  class Redis
4
6
  class Distributed
5
-
6
7
  class CannotDistribute < RuntimeError
7
8
  def initialize(command)
8
9
  @command = command
9
10
  end
10
11
 
11
12
  def message
12
- "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic."
13
+ "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
14
+ "to be on the same server or because we cannot guarantee that the operation will be atomic."
13
15
  end
14
16
  end
15
17
 
@@ -18,14 +20,18 @@ class Redis
18
20
  def initialize(node_configs, options = {})
19
21
  @tag = options[:tag] || /^\{(.+?)\}/
20
22
  @ring = options[:ring] || HashRing.new
21
- @node_configs = node_configs.dup
23
+ @node_configs = node_configs.map(&:dup)
22
24
  @default_options = options.dup
23
25
  node_configs.each { |node_config| add_node(node_config) }
24
26
  @subscribed_node = nil
27
+ @watch_key = nil
25
28
  end
26
29
 
27
30
  def node_for(key)
28
- @ring.get_node(key_tag(key.to_s) || key.to_s)
31
+ key = key_tag(key.to_s) || key.to_s
32
+ raise CannotDistribute, :watch if @watch_key && @watch_key != key
33
+
34
+ @ring.get_node(key)
29
35
  end
30
36
 
31
37
  def nodes
@@ -33,9 +39,11 @@ class Redis
33
39
  end
34
40
 
35
41
  def add_node(options)
36
- options = { :url => options } if options.is_a?(String)
42
+ options = { url: options } if options.is_a?(String)
37
43
  options = @default_options.merge(options)
38
- @ring.add_node Redis.new( options )
44
+ options.delete(:tag)
45
+ options.delete(:ring)
46
+ @ring.add_node Redis.new(options)
39
47
  end
40
48
 
41
49
  # Change the selected database for the current connection.
@@ -58,6 +66,10 @@ class Redis
58
66
  on_each_node :quit
59
67
  end
60
68
 
69
+ def close
70
+ on_each_node :close
71
+ end
72
+
61
73
  # Asynchronously save the dataset to disk.
62
74
  def bgsave
63
75
  on_each_node :bgsave
@@ -109,13 +121,13 @@ class Redis
109
121
  end
110
122
 
111
123
  # Set a key's time to live in seconds.
112
- def expire(key, seconds)
113
- node_for(key).expire(key, seconds)
124
+ def expire(key, seconds, **kwargs)
125
+ node_for(key).expire(key, seconds, **kwargs)
114
126
  end
115
127
 
116
128
  # Set the expiration for a key as a UNIX timestamp.
117
- def expireat(key, unix_time)
118
- node_for(key).expireat(key, unix_time)
129
+ def expireat(key, unix_time, **kwargs)
130
+ node_for(key).expireat(key, unix_time, **kwargs)
119
131
  end
120
132
 
121
133
  # Get the time to live (in seconds) for a key.
@@ -124,13 +136,13 @@ class Redis
124
136
  end
125
137
 
126
138
  # Set a key's time to live in milliseconds.
127
- def pexpire(key, milliseconds)
128
- node_for(key).pexpire(key, milliseconds)
139
+ def pexpire(key, milliseconds, **kwarg)
140
+ node_for(key).pexpire(key, milliseconds, **kwarg)
129
141
  end
130
142
 
131
143
  # Set the expiration for a key as number of milliseconds from UNIX Epoch.
132
- def pexpireat(key, ms_unix_time)
133
- 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)
134
146
  end
135
147
 
136
148
  # Get the time to live (in milliseconds) for a key.
@@ -144,26 +156,50 @@ class Redis
144
156
  end
145
157
 
146
158
  # Create a key using the serialized value, previously obtained using DUMP.
147
- def restore(key, ttl, serialized_value)
148
- node_for(key).restore(key, ttl, serialized_value)
159
+ def restore(key, ttl, serialized_value, **options)
160
+ node_for(key).restore(key, ttl, serialized_value, **options)
149
161
  end
150
162
 
151
163
  # Transfer a key from the connected instance to another instance.
152
- def migrate(key, options)
164
+ def migrate(_key, _options)
153
165
  raise CannotDistribute, :migrate
154
166
  end
155
167
 
156
168
  # Delete a key.
157
169
  def del(*args)
170
+ args.flatten!(1)
158
171
  keys_per_node = args.group_by { |key| node_for(key) }
159
172
  keys_per_node.inject(0) do |sum, (node, keys)|
160
173
  sum + node.del(*keys)
161
174
  end
162
175
  end
163
176
 
177
+ # Unlink keys.
178
+ def unlink(*args)
179
+ args.flatten!(1)
180
+ keys_per_node = args.group_by { |key| node_for(key) }
181
+ keys_per_node.inject(0) do |sum, (node, keys)|
182
+ sum + node.unlink(*keys)
183
+ end
184
+ end
185
+
164
186
  # Determine if a key exists.
165
- def exists(key)
166
- node_for(key).exists(key)
187
+ def exists(*args)
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
+ end
193
+ end
194
+
195
+ # Determine if any of the keys exists.
196
+ def exists?(*args)
197
+ args.flatten!(1)
198
+ keys_per_node = args.group_by { |key| node_for(key) }
199
+ keys_per_node.each do |node, keys|
200
+ return true if node.exists?(*keys)
201
+ end
202
+ false
167
203
  end
168
204
 
169
205
  # Find all keys matching the given pattern.
@@ -176,6 +212,13 @@ class Redis
176
212
  node_for(key).move(key, db)
177
213
  end
178
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
+
179
222
  # Return a random key from the keyspace.
180
223
  def randomkey
181
224
  raise CannotDistribute, :randomkey
@@ -196,11 +239,11 @@ class Redis
196
239
  end
197
240
 
198
241
  # Sort the elements in a list, set or sorted set.
199
- def sort(key, options = {})
242
+ def sort(key, **options)
200
243
  keys = [key, options[:by], options[:store], *Array(options[:get])].compact
201
244
 
202
245
  ensure_same_node(:sort, keys) do |node|
203
- node.sort(key, options)
246
+ node.sort(key, **options)
204
247
  end
205
248
  end
206
249
 
@@ -235,8 +278,8 @@ class Redis
235
278
  end
236
279
 
237
280
  # Set the string value of a key.
238
- def set(key, value, options = {})
239
- node_for(key).set(key, value, options)
281
+ def set(key, value, **options)
282
+ node_for(key).set(key, value, **options)
240
283
  end
241
284
 
242
285
  # Set the time to live in seconds of a key.
@@ -255,20 +298,20 @@ class Redis
255
298
  end
256
299
 
257
300
  # Set multiple keys to multiple values.
258
- def mset(*args)
301
+ def mset(*)
259
302
  raise CannotDistribute, :mset
260
303
  end
261
304
 
262
- def mapped_mset(hash)
305
+ def mapped_mset(_hash)
263
306
  raise CannotDistribute, :mapped_mset
264
307
  end
265
308
 
266
309
  # Set multiple keys to multiple values, only if none of the keys exist.
267
- def msetnx(*args)
310
+ def msetnx(*)
268
311
  raise CannotDistribute, :msetnx
269
312
  end
270
313
 
271
- def mapped_msetnx(hash)
314
+ def mapped_msetnx(_hash)
272
315
  raise CannotDistribute, :mapped_msetnx
273
316
  end
274
317
 
@@ -277,13 +320,28 @@ class Redis
277
320
  node_for(key).get(key)
278
321
  end
279
322
 
280
- # Get the values of all the given keys.
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
+
333
+ # Get the values of all the given keys as an Array.
281
334
  def mget(*keys)
282
- raise CannotDistribute, :mget
335
+ keys.flatten!(1)
336
+ mapped_mget(*keys).values_at(*keys)
283
337
  end
284
338
 
339
+ # Get the values of all the given keys as a Hash.
285
340
  def mapped_mget(*keys)
286
- raise CannotDistribute, :mapped_mget
341
+ keys.flatten!(1)
342
+ keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
343
+ results.merge! node.mapped_mget(*subkeys)
344
+ end
287
345
  end
288
346
 
289
347
  # Overwrite part of a string at key starting at the specified offset.
@@ -318,13 +376,14 @@ class Redis
318
376
 
319
377
  # Perform a bitwise operation between strings and store the resulting string in a key.
320
378
  def bitop(operation, destkey, *keys)
379
+ keys.flatten!(1)
321
380
  ensure_same_node(:bitop, [destkey] + keys) do |node|
322
- node.bitop(operation, destkey, *keys)
381
+ node.bitop(operation, destkey, keys)
323
382
  end
324
383
  end
325
384
 
326
385
  # Return the position of the first bit set to 1 or 0 in a string.
327
- def bitpos(key, bit, start=nil, stop=nil)
386
+ def bitpos(key, bit, start = nil, stop = nil)
328
387
  node_for(key).bitpos(key, bit, start, stop)
329
388
  end
330
389
 
@@ -342,7 +401,7 @@ class Redis
342
401
  get(key)
343
402
  end
344
403
 
345
- def []=(key,value)
404
+ def []=(key, value)
346
405
  set(key, value)
347
406
  end
348
407
 
@@ -351,6 +410,21 @@ class Redis
351
410
  node_for(key).llen(key)
352
411
  end
353
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
+
354
428
  # Prepend one or more values to a list.
355
429
  def lpush(key, value)
356
430
  node_for(key).lpush(key, value)
@@ -371,14 +445,14 @@ class Redis
371
445
  node_for(key).rpushx(key, value)
372
446
  end
373
447
 
374
- # Remove and get the first element in a list.
375
- def lpop(key)
376
- 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)
377
451
  end
378
452
 
379
- # Remove and get the last element in a list.
380
- def rpop(key)
381
- 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)
382
456
  end
383
457
 
384
458
  # Remove the last element in a list, append it to another list and return
@@ -390,24 +464,19 @@ class Redis
390
464
  end
391
465
 
392
466
  def _bpop(cmd, args)
393
- options = {}
394
-
395
- case args.last
396
- when Hash
467
+ timeout = if args.last.is_a?(Hash)
397
468
  options = args.pop
398
- when Integer
399
- # Issue deprecation notice in obnoxious mode...
400
- options[:timeout] = args.pop
401
- end
402
-
403
- if args.size > 1
404
- # Issue deprecation notice in obnoxious mode...
469
+ options[:timeout]
405
470
  end
406
471
 
407
- keys = args.flatten
472
+ args.flatten!(1)
408
473
 
409
- ensure_same_node(cmd, keys) do |node|
410
- node.__send__(cmd, keys, options)
474
+ ensure_same_node(cmd, args) do |node|
475
+ if timeout
476
+ node.__send__(cmd, args, timeout: timeout)
477
+ else
478
+ node.__send__(cmd, args)
479
+ end
411
480
  end
412
481
  end
413
482
 
@@ -417,6 +486,18 @@ class Redis
417
486
  _bpop(:blpop, args)
418
487
  end
419
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
+
420
501
  # Remove and get the last element in a list, or block until one is
421
502
  # available.
422
503
  def brpop(*args)
@@ -425,15 +506,9 @@ class Redis
425
506
 
426
507
  # Pop a value from a list, push it to another list and return it; or block
427
508
  # until one is available.
428
- def brpoplpush(source, destination, options = {})
429
- case options
430
- when Integer
431
- # Issue deprecation notice in obnoxious mode...
432
- options = { :timeout => options }
433
- end
434
-
509
+ def brpoplpush(source, destination, **options)
435
510
  ensure_same_node(:brpoplpush, [source, destination]) do |node|
436
- node.brpoplpush(source, destination, options)
511
+ node.brpoplpush(source, destination, **options)
437
512
  end
438
513
  end
439
514
 
@@ -467,19 +542,43 @@ class Redis
467
542
  node_for(key).ltrim(key, start, stop)
468
543
  end
469
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
+
470
559
  # Get the number of members in a set.
471
560
  def scard(key)
472
561
  node_for(key).scard(key)
473
562
  end
474
563
 
475
564
  # Add one or more members to a set.
476
- def sadd(key, member)
477
- node_for(key).sadd(key, member)
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)
572
+ end
573
+
574
+ # Remove one or more members from a set.
575
+ def srem(key, *members)
576
+ node_for(key).srem(key, *members)
478
577
  end
479
578
 
480
579
  # Remove one or more members from a set.
481
- def srem(key, member)
482
- node_for(key).srem(key, member)
580
+ def srem?(key, *members)
581
+ node_for(key).srem?(key, *members)
483
582
  end
484
583
 
485
584
  # Remove and return a random member from a set.
@@ -504,50 +603,71 @@ class Redis
504
603
  node_for(key).sismember(key, member)
505
604
  end
506
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
+
507
611
  # Get all the members in a set.
508
612
  def smembers(key)
509
613
  node_for(key).smembers(key)
510
614
  end
511
615
 
616
+ # Scan a set
617
+ def sscan(key, cursor, **options)
618
+ node_for(key).sscan(key, cursor, **options)
619
+ end
620
+
621
+ # Scan a set and return an enumerator
622
+ def sscan_each(key, **options, &block)
623
+ node_for(key).sscan_each(key, **options, &block)
624
+ end
625
+
512
626
  # Subtract multiple sets.
513
627
  def sdiff(*keys)
628
+ keys.flatten!(1)
514
629
  ensure_same_node(:sdiff, keys) do |node|
515
- node.sdiff(*keys)
630
+ node.sdiff(keys)
516
631
  end
517
632
  end
518
633
 
519
634
  # Subtract multiple sets and store the resulting set in a key.
520
635
  def sdiffstore(destination, *keys)
521
- ensure_same_node(:sdiffstore, [destination] + keys) do |node|
522
- node.sdiffstore(destination, *keys)
636
+ keys.flatten!(1)
637
+ ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
638
+ node.sdiffstore(destination, keys)
523
639
  end
524
640
  end
525
641
 
526
642
  # Intersect multiple sets.
527
643
  def sinter(*keys)
644
+ keys.flatten!(1)
528
645
  ensure_same_node(:sinter, keys) do |node|
529
- node.sinter(*keys)
646
+ node.sinter(keys)
530
647
  end
531
648
  end
532
649
 
533
650
  # Intersect multiple sets and store the resulting set in a key.
534
651
  def sinterstore(destination, *keys)
535
- ensure_same_node(:sinterstore, [destination] + keys) do |node|
536
- node.sinterstore(destination, *keys)
652
+ keys.flatten!(1)
653
+ ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
654
+ node.sinterstore(destination, keys)
537
655
  end
538
656
  end
539
657
 
540
658
  # Add multiple sets.
541
659
  def sunion(*keys)
660
+ keys.flatten!(1)
542
661
  ensure_same_node(:sunion, keys) do |node|
543
- node.sunion(*keys)
662
+ node.sunion(keys)
544
663
  end
545
664
  end
546
665
 
547
666
  # Add multiple sets and store the resulting set in a key.
548
667
  def sunionstore(destination, *keys)
549
- ensure_same_node(:sunionstore, [destination] + keys) do |node|
550
- node.sunionstore(destination, *keys)
668
+ keys.flatten!(1)
669
+ ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
670
+ node.sunionstore(destination, keys)
551
671
  end
552
672
  end
553
673
 
@@ -561,6 +681,7 @@ class Redis
561
681
  def zadd(key, *args)
562
682
  node_for(key).zadd(key, *args)
563
683
  end
684
+ ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
564
685
 
565
686
  # Increment the score of a member in a sorted set.
566
687
  def zincrby(key, increment, member)
@@ -577,15 +698,47 @@ class Redis
577
698
  node_for(key).zscore(key, member)
578
699
  end
579
700
 
580
- # Return a range of members in a sorted set, by index.
581
- def zrange(key, start, stop, options = {})
582
- node_for(key).zrange(key, start, stop, options)
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.
726
+ def zrange(key, start, stop, **options)
727
+ node_for(key).zrange(key, start, stop, **options)
728
+ end
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
583
736
  end
584
737
 
585
738
  # Return a range of members in a sorted set, by index, with scores ordered
586
739
  # from high to low.
587
- def zrevrange(key, start, stop, options = {})
588
- node_for(key).zrevrange(key, start, stop, options)
740
+ def zrevrange(key, start, stop, **options)
741
+ node_for(key).zrevrange(key, start, stop, **options)
589
742
  end
590
743
 
591
744
  # Determine the index of a member in a sorted set.
@@ -605,14 +758,14 @@ class Redis
605
758
  end
606
759
 
607
760
  # Return a range of members in a sorted set, by score.
608
- def zrangebyscore(key, min, max, options = {})
609
- node_for(key).zrangebyscore(key, min, max, options)
761
+ def zrangebyscore(key, min, max, **options)
762
+ node_for(key).zrangebyscore(key, min, max, **options)
610
763
  end
611
764
 
612
765
  # Return a range of members in a sorted set, by score, with scores ordered
613
766
  # from high to low.
614
- def zrevrangebyscore(key, max, min, options = {})
615
- node_for(key).zrevrangebyscore(key, max, min, options)
767
+ def zrevrangebyscore(key, max, min, **options)
768
+ node_for(key).zrevrangebyscore(key, max, min, **options)
616
769
  end
617
770
 
618
771
  # Remove all members in a sorted set within the given scores.
@@ -625,18 +778,53 @@ class Redis
625
778
  node_for(key).zcount(key, min, max)
626
779
  end
627
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
+
628
789
  # Intersect multiple sorted sets and store the resulting sorted set in a new
629
790
  # key.
630
- def zinterstore(destination, keys, options = {})
631
- ensure_same_node(:zinterstore, [destination] + keys) do |node|
632
- node.zinterstore(destination, keys, options)
791
+ def zinterstore(destination, *keys, **options)
792
+ keys.flatten!(1)
793
+ ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
794
+ node.zinterstore(destination, keys, **options)
795
+ end
796
+ end
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)
633
803
  end
634
804
  end
635
805
 
636
806
  # Add multiple sorted sets and store the resulting sorted set in a new key.
637
- def zunionstore(destination, keys, options = {})
638
- ensure_same_node(:zunionstore, [destination] + keys) do |node|
639
- node.zunionstore(destination, keys, options)
807
+ def zunionstore(destination, *keys, **options)
808
+ keys.flatten!(1)
809
+ ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
810
+ node.zunionstore(destination, keys, **options)
811
+ end
812
+ end
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)
640
828
  end
641
829
  end
642
830
 
@@ -645,9 +833,9 @@ class Redis
645
833
  node_for(key).hlen(key)
646
834
  end
647
835
 
648
- # Set the string value of a hash field.
649
- def hset(key, field, value)
650
- node_for(key).hset(key, field, value)
836
+ # Set multiple hash fields to multiple values.
837
+ def hset(key, *attrs)
838
+ node_for(key).hset(key, *attrs)
651
839
  end
652
840
 
653
841
  # Set the value of a hash field, only if the field does not exist.
@@ -661,7 +849,7 @@ class Redis
661
849
  end
662
850
 
663
851
  def mapped_hmset(key, hash)
664
- node_for(key).hmset(key, *hash.to_a.flatten)
852
+ node_for(key).hmset(key, hash)
665
853
  end
666
854
 
667
855
  # Get the value of a hash field.
@@ -671,16 +859,23 @@ class Redis
671
859
 
672
860
  # Get the values of all the given hash fields.
673
861
  def hmget(key, *fields)
674
- node_for(key).hmget(key, *fields)
862
+ fields.flatten!(1)
863
+ node_for(key).hmget(key, fields)
675
864
  end
676
865
 
677
866
  def mapped_hmget(key, *fields)
678
- Hash[*fields.zip(hmget(key, *fields)).flatten]
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)
679
873
  end
680
874
 
681
875
  # Delete one or more hash fields.
682
- def hdel(key, field)
683
- node_for(key).hdel(key, field)
876
+ def hdel(key, *fields)
877
+ fields.flatten!(1)
878
+ node_for(key).hdel(key, fields)
684
879
  end
685
880
 
686
881
  # Determine if a hash field exists.
@@ -719,7 +914,7 @@ class Redis
719
914
  end
720
915
 
721
916
  def subscribed?
722
- !! @subscribed_node
917
+ !!@subscribed_node
723
918
  end
724
919
 
725
920
  # Listen for messages published to the given channels.
@@ -737,7 +932,8 @@ class Redis
737
932
 
738
933
  # Stop listening for messages posted to the given channels.
739
934
  def unsubscribe(*channels)
740
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
935
+ raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
936
+
741
937
  @subscribed_node.unsubscribe(*channels)
742
938
  end
743
939
 
@@ -753,13 +949,26 @@ class Redis
753
949
  end
754
950
 
755
951
  # Watch the given keys to determine execution of the MULTI/EXEC block.
756
- def watch(*keys)
757
- raise CannotDistribute, :watch
952
+ def watch(*keys, &block)
953
+ ensure_same_node(:watch, keys) do |node|
954
+ @watch_key = key_tag(keys.first) || keys.first.to_s
955
+
956
+ begin
957
+ node.watch(*keys, &block)
958
+ rescue StandardError
959
+ @watch_key = nil
960
+ raise
961
+ end
962
+ end
758
963
  end
759
964
 
760
965
  # Forget about all watched keys.
761
966
  def unwatch
762
- raise CannotDistribute, :unwatch
967
+ raise CannotDistribute, :unwatch unless @watch_key
968
+
969
+ result = node_for(@watch_key).unwatch
970
+ @watch_key = nil
971
+ result
763
972
  end
764
973
 
765
974
  def pipelined
@@ -767,18 +976,28 @@ class Redis
767
976
  end
768
977
 
769
978
  # Mark the start of a transaction block.
770
- def multi
771
- raise CannotDistribute, :multi
979
+ def multi(&block)
980
+ raise CannotDistribute, :multi unless @watch_key
981
+
982
+ node_for(@watch_key).multi(&block)
772
983
  end
773
984
 
774
985
  # Execute all commands issued after MULTI.
775
986
  def exec
776
- raise CannotDistribute, :exec
987
+ raise CannotDistribute, :exec unless @watch_key
988
+
989
+ result = node_for(@watch_key).exec
990
+ @watch_key = nil
991
+ result
777
992
  end
778
993
 
779
994
  # Discard all commands issued after MULTI.
780
995
  def discard
781
- raise CannotDistribute, :discard
996
+ raise CannotDistribute, :discard unless @watch_key
997
+
998
+ result = node_for(@watch_key).discard
999
+ @watch_key = nil
1000
+ result
782
1001
  end
783
1002
 
784
1003
  # Control remote script registry.
@@ -837,7 +1056,7 @@ class Redis
837
1056
  self.class.new(@node_configs, @default_options)
838
1057
  end
839
1058
 
840
- protected
1059
+ protected
841
1060
 
842
1061
  def on_each_node(command, *args)
843
1062
  nodes.map do |node|
@@ -850,7 +1069,8 @@ class Redis
850
1069
  end
851
1070
 
852
1071
  def key_tag(key)
853
- key.to_s[@tag, 1] if @tag
1072
+ key = key.to_s
1073
+ key[@tag, 1] if key.match?(@tag)
854
1074
  end
855
1075
 
856
1076
  def ensure_same_node(command, keys)