redis 4.0.0.rc1 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +164 -3
  3. data/README.md +127 -18
  4. data/lib/redis/client.rb +164 -93
  5. data/lib/redis/cluster/command.rb +81 -0
  6. data/lib/redis/cluster/command_loader.rb +33 -0
  7. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  8. data/lib/redis/cluster/node.rb +108 -0
  9. data/lib/redis/cluster/node_key.rb +31 -0
  10. data/lib/redis/cluster/node_loader.rb +37 -0
  11. data/lib/redis/cluster/option.rb +93 -0
  12. data/lib/redis/cluster/slot.rb +86 -0
  13. data/lib/redis/cluster/slot_loader.rb +49 -0
  14. data/lib/redis/cluster.rb +291 -0
  15. data/lib/redis/connection/command_helper.rb +5 -2
  16. data/lib/redis/connection/hiredis.rb +4 -3
  17. data/lib/redis/connection/registry.rb +2 -1
  18. data/lib/redis/connection/ruby.rb +125 -106
  19. data/lib/redis/connection/synchrony.rb +18 -5
  20. data/lib/redis/connection.rb +2 -0
  21. data/lib/redis/distributed.rb +995 -0
  22. data/lib/redis/errors.rb +48 -0
  23. data/lib/redis/hash_ring.rb +89 -0
  24. data/lib/redis/pipeline.rb +55 -9
  25. data/lib/redis/subscribe.rb +11 -12
  26. data/lib/redis/version.rb +3 -1
  27. data/lib/redis.rb +1433 -381
  28. metadata +34 -141
  29. data/.gitignore +0 -16
  30. data/.travis/Gemfile +0 -11
  31. data/.travis.yml +0 -71
  32. data/.yardopts +0 -3
  33. data/Gemfile +0 -3
  34. data/benchmarking/logging.rb +0 -71
  35. data/benchmarking/pipeline.rb +0 -51
  36. data/benchmarking/speed.rb +0 -21
  37. data/benchmarking/suite.rb +0 -24
  38. data/benchmarking/worker.rb +0 -71
  39. data/examples/basic.rb +0 -15
  40. data/examples/consistency.rb +0 -114
  41. data/examples/incr-decr.rb +0 -17
  42. data/examples/list.rb +0 -26
  43. data/examples/pubsub.rb +0 -37
  44. data/examples/sentinel/sentinel.conf +0 -9
  45. data/examples/sentinel/start +0 -49
  46. data/examples/sentinel.rb +0 -41
  47. data/examples/sets.rb +0 -36
  48. data/examples/unicorn/config.ru +0 -3
  49. data/examples/unicorn/unicorn.rb +0 -20
  50. data/makefile +0 -42
  51. data/redis.gemspec +0 -40
  52. data/test/bitpos_test.rb +0 -63
  53. data/test/blocking_commands_test.rb +0 -183
  54. data/test/client_test.rb +0 -59
  55. data/test/command_map_test.rb +0 -28
  56. data/test/commands_on_hashes_test.rb +0 -174
  57. data/test/commands_on_hyper_log_log_test.rb +0 -70
  58. data/test/commands_on_lists_test.rb +0 -154
  59. data/test/commands_on_sets_test.rb +0 -208
  60. data/test/commands_on_sorted_sets_test.rb +0 -444
  61. data/test/commands_on_strings_test.rb +0 -338
  62. data/test/commands_on_value_types_test.rb +0 -246
  63. data/test/connection_handling_test.rb +0 -275
  64. data/test/db/.gitkeep +0 -0
  65. data/test/encoding_test.rb +0 -14
  66. data/test/error_replies_test.rb +0 -57
  67. data/test/fork_safety_test.rb +0 -60
  68. data/test/helper.rb +0 -179
  69. data/test/helper_test.rb +0 -22
  70. data/test/internals_test.rb +0 -435
  71. data/test/persistence_control_commands_test.rb +0 -24
  72. data/test/pipelining_commands_test.rb +0 -238
  73. data/test/publish_subscribe_test.rb +0 -280
  74. data/test/remote_server_control_commands_test.rb +0 -175
  75. data/test/scanning_test.rb +0 -407
  76. data/test/scripting_test.rb +0 -76
  77. data/test/sentinel_command_test.rb +0 -78
  78. data/test/sentinel_test.rb +0 -253
  79. data/test/sorting_test.rb +0 -57
  80. data/test/ssl_test.rb +0 -69
  81. data/test/support/connection/hiredis.rb +0 -1
  82. data/test/support/connection/ruby.rb +0 -1
  83. data/test/support/connection/synchrony.rb +0 -17
  84. data/test/support/redis_mock.rb +0 -130
  85. data/test/support/ssl/gen_certs.sh +0 -31
  86. data/test/support/ssl/trusted-ca.crt +0 -25
  87. data/test/support/ssl/trusted-ca.key +0 -27
  88. data/test/support/ssl/trusted-cert.crt +0 -81
  89. data/test/support/ssl/trusted-cert.key +0 -28
  90. data/test/support/ssl/untrusted-ca.crt +0 -26
  91. data/test/support/ssl/untrusted-ca.key +0 -27
  92. data/test/support/ssl/untrusted-cert.crt +0 -82
  93. data/test/support/ssl/untrusted-cert.key +0 -28
  94. data/test/support/wire/synchrony.rb +0 -24
  95. data/test/support/wire/thread.rb +0 -5
  96. data/test/synchrony_driver.rb +0 -85
  97. data/test/test.conf.erb +0 -9
  98. data/test/thread_safety_test.rb +0 -60
  99. data/test/transactions_test.rb +0 -262
  100. data/test/unknown_commands_test.rb +0 -12
  101. data/test/url_param_test.rb +0 -136
@@ -0,0 +1,995 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "hash_ring"
4
+
5
+ class Redis
6
+ class Distributed
7
+ class CannotDistribute < RuntimeError
8
+ def initialize(command)
9
+ @command = command
10
+ end
11
+
12
+ def message
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."
15
+ end
16
+ end
17
+
18
+ attr_reader :ring
19
+
20
+ def initialize(node_configs, options = {})
21
+ @tag = options[:tag] || /^\{(.+?)\}/
22
+ @ring = options[:ring] || HashRing.new
23
+ @node_configs = node_configs.dup
24
+ @default_options = options.dup
25
+ node_configs.each { |node_config| add_node(node_config) }
26
+ @subscribed_node = nil
27
+ @watch_key = nil
28
+ end
29
+
30
+ def node_for(key)
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)
35
+ end
36
+
37
+ def nodes
38
+ @ring.nodes
39
+ end
40
+
41
+ def add_node(options)
42
+ options = { url: options } if options.is_a?(String)
43
+ options = @default_options.merge(options)
44
+ @ring.add_node Redis.new(options)
45
+ end
46
+
47
+ # Change the selected database for the current connection.
48
+ def select(db)
49
+ on_each_node :select, db
50
+ end
51
+
52
+ # Ping the server.
53
+ def ping
54
+ on_each_node :ping
55
+ end
56
+
57
+ # Echo the given string.
58
+ def echo(value)
59
+ on_each_node :echo, value
60
+ end
61
+
62
+ # Close the connection.
63
+ def quit
64
+ on_each_node :quit
65
+ end
66
+
67
+ # Asynchronously save the dataset to disk.
68
+ def bgsave
69
+ on_each_node :bgsave
70
+ end
71
+
72
+ # Return the number of keys in the selected database.
73
+ def dbsize
74
+ on_each_node :dbsize
75
+ end
76
+
77
+ # Remove all keys from all databases.
78
+ def flushall
79
+ on_each_node :flushall
80
+ end
81
+
82
+ # Remove all keys from the current database.
83
+ def flushdb
84
+ on_each_node :flushdb
85
+ end
86
+
87
+ # Get information and statistics about the server.
88
+ def info(cmd = nil)
89
+ on_each_node :info, cmd
90
+ end
91
+
92
+ # Get the UNIX time stamp of the last successful save to disk.
93
+ def lastsave
94
+ on_each_node :lastsave
95
+ end
96
+
97
+ # Listen for all requests received by the server in real time.
98
+ def monitor
99
+ raise NotImplementedError
100
+ end
101
+
102
+ # Synchronously save the dataset to disk.
103
+ def save
104
+ on_each_node :save
105
+ end
106
+
107
+ # Get server time: an UNIX timestamp and the elapsed microseconds in the current second.
108
+ def time
109
+ on_each_node :time
110
+ end
111
+
112
+ # Remove the expiration from a key.
113
+ def persist(key)
114
+ node_for(key).persist(key)
115
+ end
116
+
117
+ # Set a key's time to live in seconds.
118
+ def expire(key, seconds)
119
+ node_for(key).expire(key, seconds)
120
+ end
121
+
122
+ # Set the expiration for a key as a UNIX timestamp.
123
+ def expireat(key, unix_time)
124
+ node_for(key).expireat(key, unix_time)
125
+ end
126
+
127
+ # Get the time to live (in seconds) for a key.
128
+ def ttl(key)
129
+ node_for(key).ttl(key)
130
+ end
131
+
132
+ # Set a key's time to live in milliseconds.
133
+ def pexpire(key, milliseconds)
134
+ node_for(key).pexpire(key, milliseconds)
135
+ end
136
+
137
+ # 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)
140
+ end
141
+
142
+ # Get the time to live (in milliseconds) for a key.
143
+ def pttl(key)
144
+ node_for(key).pttl(key)
145
+ end
146
+
147
+ # Return a serialized version of the value stored at a key.
148
+ def dump(key)
149
+ node_for(key).dump(key)
150
+ end
151
+
152
+ # Create a key using the serialized value, previously obtained using DUMP.
153
+ def restore(key, ttl, serialized_value, **options)
154
+ node_for(key).restore(key, ttl, serialized_value, **options)
155
+ end
156
+
157
+ # Transfer a key from the connected instance to another instance.
158
+ def migrate(_key, _options)
159
+ raise CannotDistribute, :migrate
160
+ end
161
+
162
+ # Delete a key.
163
+ def del(*args)
164
+ keys_per_node = args.group_by { |key| node_for(key) }
165
+ keys_per_node.inject(0) do |sum, (node, keys)|
166
+ sum + node.del(*keys)
167
+ end
168
+ end
169
+
170
+ # Unlink keys.
171
+ def unlink(*args)
172
+ keys_per_node = args.group_by { |key| node_for(key) }
173
+ keys_per_node.inject(0) do |sum, (node, keys)|
174
+ sum + node.unlink(*keys)
175
+ end
176
+ end
177
+
178
+ # Determine if a key exists.
179
+ def exists(*args)
180
+ if !Redis.exists_returns_integer && args.size == 1
181
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
182
+ "use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
183
+ "(#{::Kernel.caller(1, 1).first})\n"
184
+
185
+ if defined?(::Warning)
186
+ ::Warning.warn(message)
187
+ else
188
+ warn(message)
189
+ end
190
+ exists?(*args)
191
+ else
192
+ keys_per_node = args.group_by { |key| node_for(key) }
193
+ keys_per_node.inject(0) do |sum, (node, keys)|
194
+ sum + node._exists(*keys)
195
+ end
196
+ end
197
+ end
198
+
199
+ # Determine if any of the keys exists.
200
+ def exists?(*args)
201
+ keys_per_node = args.group_by { |key| node_for(key) }
202
+ keys_per_node.each do |node, keys|
203
+ return true if node.exists?(*keys)
204
+ end
205
+ false
206
+ end
207
+
208
+ # Find all keys matching the given pattern.
209
+ def keys(glob = "*")
210
+ on_each_node(:keys, glob).flatten
211
+ end
212
+
213
+ # Move a key to another database.
214
+ def move(key, db)
215
+ node_for(key).move(key, db)
216
+ end
217
+
218
+ # Return a random key from the keyspace.
219
+ def randomkey
220
+ raise CannotDistribute, :randomkey
221
+ end
222
+
223
+ # Rename a key.
224
+ def rename(old_name, new_name)
225
+ ensure_same_node(:rename, [old_name, new_name]) do |node|
226
+ node.rename(old_name, new_name)
227
+ end
228
+ end
229
+
230
+ # Rename a key, only if the new key does not exist.
231
+ def renamenx(old_name, new_name)
232
+ ensure_same_node(:renamenx, [old_name, new_name]) do |node|
233
+ node.renamenx(old_name, new_name)
234
+ end
235
+ end
236
+
237
+ # Sort the elements in a list, set or sorted set.
238
+ def sort(key, **options)
239
+ keys = [key, options[:by], options[:store], *Array(options[:get])].compact
240
+
241
+ ensure_same_node(:sort, keys) do |node|
242
+ node.sort(key, **options)
243
+ end
244
+ end
245
+
246
+ # Determine the type stored at key.
247
+ def type(key)
248
+ node_for(key).type(key)
249
+ end
250
+
251
+ # Decrement the integer value of a key by one.
252
+ def decr(key)
253
+ node_for(key).decr(key)
254
+ end
255
+
256
+ # Decrement the integer value of a key by the given number.
257
+ def decrby(key, decrement)
258
+ node_for(key).decrby(key, decrement)
259
+ end
260
+
261
+ # Increment the integer value of a key by one.
262
+ def incr(key)
263
+ node_for(key).incr(key)
264
+ end
265
+
266
+ # Increment the integer value of a key by the given integer number.
267
+ def incrby(key, increment)
268
+ node_for(key).incrby(key, increment)
269
+ end
270
+
271
+ # Increment the numeric value of a key by the given float number.
272
+ def incrbyfloat(key, increment)
273
+ node_for(key).incrbyfloat(key, increment)
274
+ end
275
+
276
+ # Set the string value of a key.
277
+ def set(key, value, **options)
278
+ node_for(key).set(key, value, **options)
279
+ end
280
+
281
+ # Set the time to live in seconds of a key.
282
+ def setex(key, ttl, value)
283
+ node_for(key).setex(key, ttl, value)
284
+ end
285
+
286
+ # Set the time to live in milliseconds of a key.
287
+ def psetex(key, ttl, value)
288
+ node_for(key).psetex(key, ttl, value)
289
+ end
290
+
291
+ # Set the value of a key, only if the key does not exist.
292
+ def setnx(key, value)
293
+ node_for(key).setnx(key, value)
294
+ end
295
+
296
+ # Set multiple keys to multiple values.
297
+ def mset(*_args)
298
+ raise CannotDistribute, :mset
299
+ end
300
+
301
+ def mapped_mset(_hash)
302
+ raise CannotDistribute, :mapped_mset
303
+ end
304
+
305
+ # Set multiple keys to multiple values, only if none of the keys exist.
306
+ def msetnx(*_args)
307
+ raise CannotDistribute, :msetnx
308
+ end
309
+
310
+ def mapped_msetnx(_hash)
311
+ raise CannotDistribute, :mapped_msetnx
312
+ end
313
+
314
+ # Get the value of a key.
315
+ def get(key)
316
+ node_for(key).get(key)
317
+ end
318
+
319
+ # Get the value of a key and delete it.
320
+ def getdel(key)
321
+ node_for(key).getdel(key)
322
+ end
323
+
324
+ # Get the value of a key and sets its time to live based on options.
325
+ def getex(key, **options)
326
+ node_for(key).getex(key, **options)
327
+ end
328
+
329
+ # Get the values of all the given keys as an Array.
330
+ def mget(*keys)
331
+ mapped_mget(*keys).values_at(*keys)
332
+ end
333
+
334
+ # Get the values of all the given keys as a Hash.
335
+ def mapped_mget(*keys)
336
+ keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
337
+ results.merge! node.mapped_mget(*subkeys)
338
+ end
339
+ end
340
+
341
+ # Overwrite part of a string at key starting at the specified offset.
342
+ def setrange(key, offset, value)
343
+ node_for(key).setrange(key, offset, value)
344
+ end
345
+
346
+ # Get a substring of the string stored at a key.
347
+ def getrange(key, start, stop)
348
+ node_for(key).getrange(key, start, stop)
349
+ end
350
+
351
+ # Sets or clears the bit at offset in the string value stored at key.
352
+ def setbit(key, offset, value)
353
+ node_for(key).setbit(key, offset, value)
354
+ end
355
+
356
+ # Returns the bit value at offset in the string value stored at key.
357
+ def getbit(key, offset)
358
+ node_for(key).getbit(key, offset)
359
+ end
360
+
361
+ # Append a value to a key.
362
+ def append(key, value)
363
+ node_for(key).append(key, value)
364
+ end
365
+
366
+ # Count the number of set bits in a range of the string value stored at key.
367
+ def bitcount(key, start = 0, stop = -1)
368
+ node_for(key).bitcount(key, start, stop)
369
+ end
370
+
371
+ # Perform a bitwise operation between strings and store the resulting string in a key.
372
+ def bitop(operation, destkey, *keys)
373
+ ensure_same_node(:bitop, [destkey] + keys) do |node|
374
+ node.bitop(operation, destkey, *keys)
375
+ end
376
+ end
377
+
378
+ # Return the position of the first bit set to 1 or 0 in a string.
379
+ def bitpos(key, bit, start = nil, stop = nil)
380
+ node_for(key).bitpos(key, bit, start, stop)
381
+ end
382
+
383
+ # Set the string value of a key and return its old value.
384
+ def getset(key, value)
385
+ node_for(key).getset(key, value)
386
+ end
387
+
388
+ # Get the length of the value stored in a key.
389
+ def strlen(key)
390
+ node_for(key).strlen(key)
391
+ end
392
+
393
+ def [](key)
394
+ get(key)
395
+ end
396
+
397
+ def []=(key, value)
398
+ set(key, value)
399
+ end
400
+
401
+ # Get the length of a list.
402
+ def llen(key)
403
+ node_for(key).llen(key)
404
+ end
405
+
406
+ # Remove the first/last element in a list, append/prepend it to another list and return it.
407
+ def lmove(source, destination, where_source, where_destination)
408
+ ensure_same_node(:lmove, [source, destination]) do |node|
409
+ node.lmove(source, destination, where_source, where_destination)
410
+ end
411
+ end
412
+
413
+ # Remove the first/last element in a list and append/prepend it
414
+ # to another list and return it, or block until one is available.
415
+ def blmove(source, destination, where_source, where_destination, timeout: 0)
416
+ ensure_same_node(:lmove, [source, destination]) do |node|
417
+ node.blmove(source, destination, where_source, where_destination, timeout: timeout)
418
+ end
419
+ end
420
+
421
+ # Prepend one or more values to a list.
422
+ def lpush(key, value)
423
+ node_for(key).lpush(key, value)
424
+ end
425
+
426
+ # Prepend a value to a list, only if the list exists.
427
+ def lpushx(key, value)
428
+ node_for(key).lpushx(key, value)
429
+ end
430
+
431
+ # Append one or more values to a list.
432
+ def rpush(key, value)
433
+ node_for(key).rpush(key, value)
434
+ end
435
+
436
+ # Append a value to a list, only if the list exists.
437
+ def rpushx(key, value)
438
+ node_for(key).rpushx(key, value)
439
+ end
440
+
441
+ # Remove and get the first elements in a list.
442
+ def lpop(key, count = nil)
443
+ node_for(key).lpop(key, count)
444
+ end
445
+
446
+ # Remove and get the last elements in a list.
447
+ def rpop(key, count = nil)
448
+ node_for(key).rpop(key, count)
449
+ end
450
+
451
+ # Remove the last element in a list, append it to another list and return
452
+ # it.
453
+ def rpoplpush(source, destination)
454
+ ensure_same_node(:rpoplpush, [source, destination]) do |node|
455
+ node.rpoplpush(source, destination)
456
+ end
457
+ end
458
+
459
+ def _bpop(cmd, args)
460
+ timeout = if args.last.is_a?(Hash)
461
+ options = args.pop
462
+ options[:timeout]
463
+ elsif args.last.respond_to?(:to_int)
464
+ # Issue deprecation notice in obnoxious mode...
465
+ args.pop.to_int
466
+ end
467
+
468
+ if args.size > 1
469
+ # Issue deprecation notice in obnoxious mode...
470
+ end
471
+
472
+ keys = args.flatten
473
+
474
+ ensure_same_node(cmd, keys) do |node|
475
+ if timeout
476
+ node.__send__(cmd, keys, timeout: timeout)
477
+ else
478
+ node.__send__(cmd, keys)
479
+ end
480
+ end
481
+ end
482
+
483
+ # Remove and get the first element in a list, or block until one is
484
+ # available.
485
+ def blpop(*args)
486
+ _bpop(:blpop, args)
487
+ end
488
+
489
+ # Remove and get the last element in a list, or block until one is
490
+ # available.
491
+ def brpop(*args)
492
+ _bpop(:brpop, args)
493
+ end
494
+
495
+ # Pop a value from a list, push it to another list and return it; or block
496
+ # until one is available.
497
+ def brpoplpush(source, destination, deprecated_timeout = 0, **options)
498
+ ensure_same_node(:brpoplpush, [source, destination]) do |node|
499
+ node.brpoplpush(source, destination, deprecated_timeout, **options)
500
+ end
501
+ end
502
+
503
+ # Get an element from a list by its index.
504
+ def lindex(key, index)
505
+ node_for(key).lindex(key, index)
506
+ end
507
+
508
+ # Insert an element before or after another element in a list.
509
+ def linsert(key, where, pivot, value)
510
+ node_for(key).linsert(key, where, pivot, value)
511
+ end
512
+
513
+ # Get a range of elements from a list.
514
+ def lrange(key, start, stop)
515
+ node_for(key).lrange(key, start, stop)
516
+ end
517
+
518
+ # Remove elements from a list.
519
+ def lrem(key, count, value)
520
+ node_for(key).lrem(key, count, value)
521
+ end
522
+
523
+ # Set the value of an element in a list by its index.
524
+ def lset(key, index, value)
525
+ node_for(key).lset(key, index, value)
526
+ end
527
+
528
+ # Trim a list to the specified range.
529
+ def ltrim(key, start, stop)
530
+ node_for(key).ltrim(key, start, stop)
531
+ end
532
+
533
+ # Get the number of members in a set.
534
+ def scard(key)
535
+ node_for(key).scard(key)
536
+ end
537
+
538
+ # Add one or more members to a set.
539
+ def sadd(key, member)
540
+ node_for(key).sadd(key, member)
541
+ end
542
+
543
+ # Remove one or more members from a set.
544
+ def srem(key, member)
545
+ node_for(key).srem(key, member)
546
+ end
547
+
548
+ # Remove and return a random member from a set.
549
+ def spop(key, count = nil)
550
+ node_for(key).spop(key, count)
551
+ end
552
+
553
+ # Get a random member from a set.
554
+ def srandmember(key, count = nil)
555
+ node_for(key).srandmember(key, count)
556
+ end
557
+
558
+ # Move a member from one set to another.
559
+ def smove(source, destination, member)
560
+ ensure_same_node(:smove, [source, destination]) do |node|
561
+ node.smove(source, destination, member)
562
+ end
563
+ end
564
+
565
+ # Determine if a given value is a member of a set.
566
+ def sismember(key, member)
567
+ node_for(key).sismember(key, member)
568
+ end
569
+
570
+ # Determine if multiple values are members of a set.
571
+ def smismember(key, *members)
572
+ node_for(key).smismember(key, *members)
573
+ end
574
+
575
+ # Get all the members in a set.
576
+ def smembers(key)
577
+ node_for(key).smembers(key)
578
+ end
579
+
580
+ # Scan a set
581
+ def sscan(key, cursor, **options)
582
+ node_for(key).sscan(key, cursor, **options)
583
+ end
584
+
585
+ # Scan a set and return an enumerator
586
+ def sscan_each(key, **options, &block)
587
+ node_for(key).sscan_each(key, **options, &block)
588
+ end
589
+
590
+ # Subtract multiple sets.
591
+ def sdiff(*keys)
592
+ ensure_same_node(:sdiff, keys) do |node|
593
+ node.sdiff(*keys)
594
+ end
595
+ end
596
+
597
+ # Subtract multiple sets and store the resulting set in a key.
598
+ def sdiffstore(destination, *keys)
599
+ ensure_same_node(:sdiffstore, [destination] + keys) do |node|
600
+ node.sdiffstore(destination, *keys)
601
+ end
602
+ end
603
+
604
+ # Intersect multiple sets.
605
+ def sinter(*keys)
606
+ ensure_same_node(:sinter, keys) do |node|
607
+ node.sinter(*keys)
608
+ end
609
+ end
610
+
611
+ # Intersect multiple sets and store the resulting set in a key.
612
+ def sinterstore(destination, *keys)
613
+ ensure_same_node(:sinterstore, [destination] + keys) do |node|
614
+ node.sinterstore(destination, *keys)
615
+ end
616
+ end
617
+
618
+ # Add multiple sets.
619
+ def sunion(*keys)
620
+ ensure_same_node(:sunion, keys) do |node|
621
+ node.sunion(*keys)
622
+ end
623
+ end
624
+
625
+ # Add multiple sets and store the resulting set in a key.
626
+ def sunionstore(destination, *keys)
627
+ ensure_same_node(:sunionstore, [destination] + keys) do |node|
628
+ node.sunionstore(destination, *keys)
629
+ end
630
+ end
631
+
632
+ # Get the number of members in a sorted set.
633
+ def zcard(key)
634
+ node_for(key).zcard(key)
635
+ end
636
+
637
+ # Add one or more members to a sorted set, or update the score for members
638
+ # that already exist.
639
+ def zadd(key, *args)
640
+ node_for(key).zadd(key, *args)
641
+ end
642
+ ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
643
+
644
+ # Increment the score of a member in a sorted set.
645
+ def zincrby(key, increment, member)
646
+ node_for(key).zincrby(key, increment, member)
647
+ end
648
+
649
+ # Remove one or more members from a sorted set.
650
+ def zrem(key, member)
651
+ node_for(key).zrem(key, member)
652
+ end
653
+
654
+ # Get the score associated with the given member in a sorted set.
655
+ def zscore(key, member)
656
+ node_for(key).zscore(key, member)
657
+ end
658
+
659
+ # Get one or more random members from a sorted set.
660
+ def zrandmember(key, count = nil, **options)
661
+ node_for(key).zrandmember(key, count, **options)
662
+ end
663
+
664
+ # Get the scores associated with the given members in a sorted set.
665
+ def zmscore(key, *members)
666
+ node_for(key).zmscore(key, *members)
667
+ end
668
+
669
+ # Return a range of members in a sorted set, by index.
670
+ def zrange(key, start, stop, **options)
671
+ node_for(key).zrange(key, start, stop, **options)
672
+ end
673
+
674
+ # Return a range of members in a sorted set, by index, with scores ordered
675
+ # from high to low.
676
+ def zrevrange(key, start, stop, **options)
677
+ node_for(key).zrevrange(key, start, stop, **options)
678
+ end
679
+
680
+ # Determine the index of a member in a sorted set.
681
+ def zrank(key, member)
682
+ node_for(key).zrank(key, member)
683
+ end
684
+
685
+ # Determine the index of a member in a sorted set, with scores ordered from
686
+ # high to low.
687
+ def zrevrank(key, member)
688
+ node_for(key).zrevrank(key, member)
689
+ end
690
+
691
+ # Remove all members in a sorted set within the given indexes.
692
+ def zremrangebyrank(key, start, stop)
693
+ node_for(key).zremrangebyrank(key, start, stop)
694
+ end
695
+
696
+ # Return a range of members in a sorted set, by score.
697
+ def zrangebyscore(key, min, max, **options)
698
+ node_for(key).zrangebyscore(key, min, max, **options)
699
+ end
700
+
701
+ # Return a range of members in a sorted set, by score, with scores ordered
702
+ # from high to low.
703
+ def zrevrangebyscore(key, max, min, **options)
704
+ node_for(key).zrevrangebyscore(key, max, min, **options)
705
+ end
706
+
707
+ # Remove all members in a sorted set within the given scores.
708
+ def zremrangebyscore(key, min, max)
709
+ node_for(key).zremrangebyscore(key, min, max)
710
+ end
711
+
712
+ # Get the number of members in a particular score range.
713
+ def zcount(key, min, max)
714
+ node_for(key).zcount(key, min, max)
715
+ end
716
+
717
+ # Get the intersection of multiple sorted sets
718
+ def zinter(*keys, **options)
719
+ ensure_same_node(:zinter, keys) do |node|
720
+ node.zinter(*keys, **options)
721
+ end
722
+ end
723
+
724
+ # Intersect multiple sorted sets and store the resulting sorted set in a new
725
+ # key.
726
+ def zinterstore(destination, keys, **options)
727
+ ensure_same_node(:zinterstore, [destination] + keys) do |node|
728
+ node.zinterstore(destination, keys, **options)
729
+ end
730
+ end
731
+
732
+ # Add multiple sorted sets and store the resulting sorted set in a new key.
733
+ def zunionstore(destination, keys, **options)
734
+ ensure_same_node(:zunionstore, [destination] + keys) do |node|
735
+ node.zunionstore(destination, keys, **options)
736
+ end
737
+ end
738
+
739
+ # Get the number of fields in a hash.
740
+ def hlen(key)
741
+ node_for(key).hlen(key)
742
+ end
743
+
744
+ # Set multiple hash fields to multiple values.
745
+ def hset(key, *attrs)
746
+ node_for(key).hset(key, *attrs)
747
+ end
748
+
749
+ # Set the value of a hash field, only if the field does not exist.
750
+ def hsetnx(key, field, value)
751
+ node_for(key).hsetnx(key, field, value)
752
+ end
753
+
754
+ # Set multiple hash fields to multiple values.
755
+ def hmset(key, *attrs)
756
+ node_for(key).hmset(key, *attrs)
757
+ end
758
+
759
+ def mapped_hmset(key, hash)
760
+ node_for(key).hmset(key, *hash.to_a.flatten)
761
+ end
762
+
763
+ # Get the value of a hash field.
764
+ def hget(key, field)
765
+ node_for(key).hget(key, field)
766
+ end
767
+
768
+ # Get the values of all the given hash fields.
769
+ def hmget(key, *fields)
770
+ node_for(key).hmget(key, *fields)
771
+ end
772
+
773
+ def mapped_hmget(key, *fields)
774
+ Hash[*fields.zip(hmget(key, *fields)).flatten]
775
+ end
776
+
777
+ # Delete one or more hash fields.
778
+ def hdel(key, *fields)
779
+ node_for(key).hdel(key, *fields)
780
+ end
781
+
782
+ # Determine if a hash field exists.
783
+ def hexists(key, field)
784
+ node_for(key).hexists(key, field)
785
+ end
786
+
787
+ # Increment the integer value of a hash field by the given integer number.
788
+ def hincrby(key, field, increment)
789
+ node_for(key).hincrby(key, field, increment)
790
+ end
791
+
792
+ # Increment the numeric value of a hash field by the given float number.
793
+ def hincrbyfloat(key, field, increment)
794
+ node_for(key).hincrbyfloat(key, field, increment)
795
+ end
796
+
797
+ # Get all the fields in a hash.
798
+ def hkeys(key)
799
+ node_for(key).hkeys(key)
800
+ end
801
+
802
+ # Get all the values in a hash.
803
+ def hvals(key)
804
+ node_for(key).hvals(key)
805
+ end
806
+
807
+ # Get all the fields and values in a hash.
808
+ def hgetall(key)
809
+ node_for(key).hgetall(key)
810
+ end
811
+
812
+ # Post a message to a channel.
813
+ def publish(channel, message)
814
+ node_for(channel).publish(channel, message)
815
+ end
816
+
817
+ def subscribed?
818
+ !!@subscribed_node
819
+ end
820
+
821
+ # Listen for messages published to the given channels.
822
+ def subscribe(channel, *channels, &block)
823
+ if channels.empty?
824
+ @subscribed_node = node_for(channel)
825
+ @subscribed_node.subscribe(channel, &block)
826
+ else
827
+ ensure_same_node(:subscribe, [channel] + channels) do |node|
828
+ @subscribed_node = node
829
+ node.subscribe(channel, *channels, &block)
830
+ end
831
+ end
832
+ end
833
+
834
+ # Stop listening for messages posted to the given channels.
835
+ def unsubscribe(*channels)
836
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
837
+
838
+ @subscribed_node.unsubscribe(*channels)
839
+ end
840
+
841
+ # Listen for messages published to channels matching the given patterns.
842
+ def psubscribe(*channels, &block)
843
+ raise NotImplementedError
844
+ end
845
+
846
+ # Stop listening for messages posted to channels matching the given
847
+ # patterns.
848
+ def punsubscribe(*channels)
849
+ raise NotImplementedError
850
+ end
851
+
852
+ # Watch the given keys to determine execution of the MULTI/EXEC block.
853
+ def watch(*keys, &block)
854
+ ensure_same_node(:watch, keys) do |node|
855
+ @watch_key = key_tag(keys.first) || keys.first.to_s
856
+
857
+ begin
858
+ node.watch(*keys, &block)
859
+ rescue StandardError
860
+ @watch_key = nil
861
+ raise
862
+ end
863
+ end
864
+ end
865
+
866
+ # Forget about all watched keys.
867
+ def unwatch
868
+ raise CannotDistribute, :unwatch unless @watch_key
869
+
870
+ result = node_for(@watch_key).unwatch
871
+ @watch_key = nil
872
+ result
873
+ end
874
+
875
+ def pipelined
876
+ raise CannotDistribute, :pipelined
877
+ end
878
+
879
+ # Mark the start of a transaction block.
880
+ def multi(&block)
881
+ raise CannotDistribute, :multi unless @watch_key
882
+
883
+ result = node_for(@watch_key).multi(&block)
884
+ @watch_key = nil if block_given?
885
+ result
886
+ end
887
+
888
+ # Execute all commands issued after MULTI.
889
+ def exec
890
+ raise CannotDistribute, :exec unless @watch_key
891
+
892
+ result = node_for(@watch_key).exec
893
+ @watch_key = nil
894
+ result
895
+ end
896
+
897
+ # Discard all commands issued after MULTI.
898
+ def discard
899
+ raise CannotDistribute, :discard unless @watch_key
900
+
901
+ result = node_for(@watch_key).discard
902
+ @watch_key = nil
903
+ result
904
+ end
905
+
906
+ # Control remote script registry.
907
+ def script(subcommand, *args)
908
+ on_each_node(:script, subcommand, *args)
909
+ end
910
+
911
+ # Add one or more members to a HyperLogLog structure.
912
+ def pfadd(key, member)
913
+ node_for(key).pfadd(key, member)
914
+ end
915
+
916
+ # Get the approximate cardinality of members added to HyperLogLog structure.
917
+ def pfcount(*keys)
918
+ ensure_same_node(:pfcount, keys.flatten(1)) do |node|
919
+ node.pfcount(keys)
920
+ end
921
+ end
922
+
923
+ # Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
924
+ # the observed Sets of the source HyperLogLog structures.
925
+ def pfmerge(dest_key, *source_key)
926
+ ensure_same_node(:pfmerge, [dest_key, *source_key]) do |node|
927
+ node.pfmerge(dest_key, *source_key)
928
+ end
929
+ end
930
+
931
+ def _eval(cmd, args)
932
+ script = args.shift
933
+ options = args.pop if args.last.is_a?(Hash)
934
+ options ||= {}
935
+
936
+ keys = args.shift || options[:keys] || []
937
+ argv = args.shift || options[:argv] || []
938
+
939
+ ensure_same_node(cmd, keys) do |node|
940
+ node.send(cmd, script, keys, argv)
941
+ end
942
+ end
943
+
944
+ # Evaluate Lua script.
945
+ def eval(*args)
946
+ _eval(:eval, args)
947
+ end
948
+
949
+ # Evaluate Lua script by its SHA.
950
+ def evalsha(*args)
951
+ _eval(:evalsha, args)
952
+ end
953
+
954
+ def inspect
955
+ "#<Redis client v#{Redis::VERSION} for #{nodes.map(&:id).join(', ')}>"
956
+ end
957
+
958
+ def dup
959
+ self.class.new(@node_configs, @default_options)
960
+ end
961
+
962
+ protected
963
+
964
+ def on_each_node(command, *args)
965
+ nodes.map do |node|
966
+ node.send(command, *args)
967
+ end
968
+ end
969
+
970
+ def node_index_for(key)
971
+ nodes.index(node_for(key))
972
+ end
973
+
974
+ def key_tag(key)
975
+ key.to_s[@tag, 1] if @tag
976
+ end
977
+
978
+ def ensure_same_node(command, keys)
979
+ all = true
980
+
981
+ tags = keys.map do |key|
982
+ tag = key_tag(key)
983
+ all = false unless tag
984
+ tag
985
+ end
986
+
987
+ if (all && tags.uniq.size != 1) || (!all && keys.uniq.size != 1)
988
+ # Not 1 unique tag or not 1 unique key
989
+ raise CannotDistribute, command
990
+ end
991
+
992
+ yield(node_for(keys.first))
993
+ end
994
+ end
995
+ end