redis 4.0.0.rc1 → 4.4.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.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +143 -3
  3. data/README.md +127 -18
  4. data/lib/redis/client.rb +150 -93
  5. data/lib/redis/cluster/command.rb +81 -0
  6. data/lib/redis/cluster/command_loader.rb +34 -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 +3 -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 +123 -105
  19. data/lib/redis/connection/synchrony.rb +18 -5
  20. data/lib/redis/connection.rb +2 -0
  21. data/lib/redis/distributed.rb +955 -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 +1242 -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,955 @@
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 values of all the given keys as an Array.
320
+ def mget(*keys)
321
+ mapped_mget(*keys).values_at(*keys)
322
+ end
323
+
324
+ # Get the values of all the given keys as a Hash.
325
+ def mapped_mget(*keys)
326
+ keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
327
+ results.merge! node.mapped_mget(*subkeys)
328
+ end
329
+ end
330
+
331
+ # Overwrite part of a string at key starting at the specified offset.
332
+ def setrange(key, offset, value)
333
+ node_for(key).setrange(key, offset, value)
334
+ end
335
+
336
+ # Get a substring of the string stored at a key.
337
+ def getrange(key, start, stop)
338
+ node_for(key).getrange(key, start, stop)
339
+ end
340
+
341
+ # Sets or clears the bit at offset in the string value stored at key.
342
+ def setbit(key, offset, value)
343
+ node_for(key).setbit(key, offset, value)
344
+ end
345
+
346
+ # Returns the bit value at offset in the string value stored at key.
347
+ def getbit(key, offset)
348
+ node_for(key).getbit(key, offset)
349
+ end
350
+
351
+ # Append a value to a key.
352
+ def append(key, value)
353
+ node_for(key).append(key, value)
354
+ end
355
+
356
+ # Count the number of set bits in a range of the string value stored at key.
357
+ def bitcount(key, start = 0, stop = -1)
358
+ node_for(key).bitcount(key, start, stop)
359
+ end
360
+
361
+ # Perform a bitwise operation between strings and store the resulting string in a key.
362
+ def bitop(operation, destkey, *keys)
363
+ ensure_same_node(:bitop, [destkey] + keys) do |node|
364
+ node.bitop(operation, destkey, *keys)
365
+ end
366
+ end
367
+
368
+ # Return the position of the first bit set to 1 or 0 in a string.
369
+ def bitpos(key, bit, start = nil, stop = nil)
370
+ node_for(key).bitpos(key, bit, start, stop)
371
+ end
372
+
373
+ # Set the string value of a key and return its old value.
374
+ def getset(key, value)
375
+ node_for(key).getset(key, value)
376
+ end
377
+
378
+ # Get the length of the value stored in a key.
379
+ def strlen(key)
380
+ node_for(key).strlen(key)
381
+ end
382
+
383
+ def [](key)
384
+ get(key)
385
+ end
386
+
387
+ def []=(key, value)
388
+ set(key, value)
389
+ end
390
+
391
+ # Get the length of a list.
392
+ def llen(key)
393
+ node_for(key).llen(key)
394
+ end
395
+
396
+ # Prepend one or more values to a list.
397
+ def lpush(key, value)
398
+ node_for(key).lpush(key, value)
399
+ end
400
+
401
+ # Prepend a value to a list, only if the list exists.
402
+ def lpushx(key, value)
403
+ node_for(key).lpushx(key, value)
404
+ end
405
+
406
+ # Append one or more values to a list.
407
+ def rpush(key, value)
408
+ node_for(key).rpush(key, value)
409
+ end
410
+
411
+ # Append a value to a list, only if the list exists.
412
+ def rpushx(key, value)
413
+ node_for(key).rpushx(key, value)
414
+ end
415
+
416
+ # Remove and get the first elements in a list.
417
+ def lpop(key, count = nil)
418
+ node_for(key).lpop(key, count)
419
+ end
420
+
421
+ # Remove and get the last elements in a list.
422
+ def rpop(key, count = nil)
423
+ node_for(key).rpop(key, count)
424
+ end
425
+
426
+ # Remove the last element in a list, append it to another list and return
427
+ # it.
428
+ def rpoplpush(source, destination)
429
+ ensure_same_node(:rpoplpush, [source, destination]) do |node|
430
+ node.rpoplpush(source, destination)
431
+ end
432
+ end
433
+
434
+ def _bpop(cmd, args)
435
+ timeout = if args.last.is_a?(Hash)
436
+ options = args.pop
437
+ 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
+ end
446
+
447
+ keys = args.flatten
448
+
449
+ ensure_same_node(cmd, keys) do |node|
450
+ if timeout
451
+ node.__send__(cmd, keys, timeout: timeout)
452
+ else
453
+ node.__send__(cmd, keys)
454
+ end
455
+ end
456
+ end
457
+
458
+ # Remove and get the first element in a list, or block until one is
459
+ # available.
460
+ def blpop(*args)
461
+ _bpop(:blpop, args)
462
+ end
463
+
464
+ # Remove and get the last element in a list, or block until one is
465
+ # available.
466
+ def brpop(*args)
467
+ _bpop(:brpop, args)
468
+ end
469
+
470
+ # Pop a value from a list, push it to another list and return it; or block
471
+ # until one is available.
472
+ def brpoplpush(source, destination, deprecated_timeout = 0, **options)
473
+ ensure_same_node(:brpoplpush, [source, destination]) do |node|
474
+ node.brpoplpush(source, destination, deprecated_timeout, **options)
475
+ end
476
+ end
477
+
478
+ # Get an element from a list by its index.
479
+ def lindex(key, index)
480
+ node_for(key).lindex(key, index)
481
+ end
482
+
483
+ # Insert an element before or after another element in a list.
484
+ def linsert(key, where, pivot, value)
485
+ node_for(key).linsert(key, where, pivot, value)
486
+ end
487
+
488
+ # Get a range of elements from a list.
489
+ def lrange(key, start, stop)
490
+ node_for(key).lrange(key, start, stop)
491
+ end
492
+
493
+ # Remove elements from a list.
494
+ def lrem(key, count, value)
495
+ node_for(key).lrem(key, count, value)
496
+ end
497
+
498
+ # Set the value of an element in a list by its index.
499
+ def lset(key, index, value)
500
+ node_for(key).lset(key, index, value)
501
+ end
502
+
503
+ # Trim a list to the specified range.
504
+ def ltrim(key, start, stop)
505
+ node_for(key).ltrim(key, start, stop)
506
+ end
507
+
508
+ # Get the number of members in a set.
509
+ def scard(key)
510
+ node_for(key).scard(key)
511
+ end
512
+
513
+ # Add one or more members to a set.
514
+ def sadd(key, member)
515
+ node_for(key).sadd(key, member)
516
+ end
517
+
518
+ # Remove one or more members from a set.
519
+ def srem(key, member)
520
+ node_for(key).srem(key, member)
521
+ end
522
+
523
+ # Remove and return a random member from a set.
524
+ def spop(key, count = nil)
525
+ node_for(key).spop(key, count)
526
+ end
527
+
528
+ # Get a random member from a set.
529
+ def srandmember(key, count = nil)
530
+ node_for(key).srandmember(key, count)
531
+ end
532
+
533
+ # Move a member from one set to another.
534
+ def smove(source, destination, member)
535
+ ensure_same_node(:smove, [source, destination]) do |node|
536
+ node.smove(source, destination, member)
537
+ end
538
+ end
539
+
540
+ # Determine if a given value is a member of a set.
541
+ def sismember(key, member)
542
+ node_for(key).sismember(key, member)
543
+ end
544
+
545
+ # Get all the members in a set.
546
+ def smembers(key)
547
+ node_for(key).smembers(key)
548
+ end
549
+
550
+ # Scan a set
551
+ def sscan(key, cursor, **options)
552
+ node_for(key).sscan(key, cursor, **options)
553
+ end
554
+
555
+ # Scan a set and return an enumerator
556
+ def sscan_each(key, **options, &block)
557
+ node_for(key).sscan_each(key, **options, &block)
558
+ end
559
+
560
+ # Subtract multiple sets.
561
+ def sdiff(*keys)
562
+ ensure_same_node(:sdiff, keys) do |node|
563
+ node.sdiff(*keys)
564
+ end
565
+ end
566
+
567
+ # Subtract multiple sets and store the resulting set in a key.
568
+ def sdiffstore(destination, *keys)
569
+ ensure_same_node(:sdiffstore, [destination] + keys) do |node|
570
+ node.sdiffstore(destination, *keys)
571
+ end
572
+ end
573
+
574
+ # Intersect multiple sets.
575
+ def sinter(*keys)
576
+ ensure_same_node(:sinter, keys) do |node|
577
+ node.sinter(*keys)
578
+ end
579
+ end
580
+
581
+ # Intersect multiple sets and store the resulting set in a key.
582
+ def sinterstore(destination, *keys)
583
+ ensure_same_node(:sinterstore, [destination] + keys) do |node|
584
+ node.sinterstore(destination, *keys)
585
+ end
586
+ end
587
+
588
+ # Add multiple sets.
589
+ def sunion(*keys)
590
+ ensure_same_node(:sunion, keys) do |node|
591
+ node.sunion(*keys)
592
+ end
593
+ end
594
+
595
+ # Add multiple sets and store the resulting set in a key.
596
+ def sunionstore(destination, *keys)
597
+ ensure_same_node(:sunionstore, [destination] + keys) do |node|
598
+ node.sunionstore(destination, *keys)
599
+ end
600
+ end
601
+
602
+ # Get the number of members in a sorted set.
603
+ def zcard(key)
604
+ node_for(key).zcard(key)
605
+ end
606
+
607
+ # Add one or more members to a sorted set, or update the score for members
608
+ # that already exist.
609
+ def zadd(key, *args)
610
+ node_for(key).zadd(key, *args)
611
+ end
612
+ ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
613
+
614
+ # Increment the score of a member in a sorted set.
615
+ def zincrby(key, increment, member)
616
+ node_for(key).zincrby(key, increment, member)
617
+ end
618
+
619
+ # Remove one or more members from a sorted set.
620
+ def zrem(key, member)
621
+ node_for(key).zrem(key, member)
622
+ end
623
+
624
+ # Get the score associated with the given member in a sorted set.
625
+ def zscore(key, member)
626
+ node_for(key).zscore(key, member)
627
+ end
628
+
629
+ # Return a range of members in a sorted set, by index.
630
+ def zrange(key, start, stop, **options)
631
+ node_for(key).zrange(key, start, stop, **options)
632
+ end
633
+
634
+ # Return a range of members in a sorted set, by index, with scores ordered
635
+ # from high to low.
636
+ def zrevrange(key, start, stop, **options)
637
+ node_for(key).zrevrange(key, start, stop, **options)
638
+ end
639
+
640
+ # Determine the index of a member in a sorted set.
641
+ def zrank(key, member)
642
+ node_for(key).zrank(key, member)
643
+ end
644
+
645
+ # Determine the index of a member in a sorted set, with scores ordered from
646
+ # high to low.
647
+ def zrevrank(key, member)
648
+ node_for(key).zrevrank(key, member)
649
+ end
650
+
651
+ # Remove all members in a sorted set within the given indexes.
652
+ def zremrangebyrank(key, start, stop)
653
+ node_for(key).zremrangebyrank(key, start, stop)
654
+ end
655
+
656
+ # Return a range of members in a sorted set, by score.
657
+ def zrangebyscore(key, min, max, **options)
658
+ node_for(key).zrangebyscore(key, min, max, **options)
659
+ end
660
+
661
+ # Return a range of members in a sorted set, by score, with scores ordered
662
+ # from high to low.
663
+ def zrevrangebyscore(key, max, min, **options)
664
+ node_for(key).zrevrangebyscore(key, max, min, **options)
665
+ end
666
+
667
+ # Remove all members in a sorted set within the given scores.
668
+ def zremrangebyscore(key, min, max)
669
+ node_for(key).zremrangebyscore(key, min, max)
670
+ end
671
+
672
+ # Get the number of members in a particular score range.
673
+ def zcount(key, min, max)
674
+ node_for(key).zcount(key, min, max)
675
+ end
676
+
677
+ # Get the intersection of multiple sorted sets
678
+ def zinter(*keys, **options)
679
+ ensure_same_node(:zinter, keys) do |node|
680
+ node.zinter(*keys, **options)
681
+ end
682
+ end
683
+
684
+ # Intersect multiple sorted sets and store the resulting sorted set in a new
685
+ # key.
686
+ def zinterstore(destination, keys, **options)
687
+ ensure_same_node(:zinterstore, [destination] + keys) do |node|
688
+ node.zinterstore(destination, keys, **options)
689
+ end
690
+ end
691
+
692
+ # Add multiple sorted sets and store the resulting sorted set in a new key.
693
+ def zunionstore(destination, keys, **options)
694
+ ensure_same_node(:zunionstore, [destination] + keys) do |node|
695
+ node.zunionstore(destination, keys, **options)
696
+ end
697
+ end
698
+
699
+ # Get the number of fields in a hash.
700
+ def hlen(key)
701
+ node_for(key).hlen(key)
702
+ end
703
+
704
+ # Set multiple hash fields to multiple values.
705
+ def hset(key, *attrs)
706
+ node_for(key).hset(key, *attrs)
707
+ end
708
+
709
+ # Set the value of a hash field, only if the field does not exist.
710
+ def hsetnx(key, field, value)
711
+ node_for(key).hsetnx(key, field, value)
712
+ end
713
+
714
+ # Set multiple hash fields to multiple values.
715
+ def hmset(key, *attrs)
716
+ node_for(key).hmset(key, *attrs)
717
+ end
718
+
719
+ def mapped_hmset(key, hash)
720
+ node_for(key).hmset(key, *hash.to_a.flatten)
721
+ end
722
+
723
+ # Get the value of a hash field.
724
+ def hget(key, field)
725
+ node_for(key).hget(key, field)
726
+ end
727
+
728
+ # Get the values of all the given hash fields.
729
+ def hmget(key, *fields)
730
+ node_for(key).hmget(key, *fields)
731
+ end
732
+
733
+ def mapped_hmget(key, *fields)
734
+ Hash[*fields.zip(hmget(key, *fields)).flatten]
735
+ end
736
+
737
+ # Delete one or more hash fields.
738
+ def hdel(key, *fields)
739
+ node_for(key).hdel(key, *fields)
740
+ end
741
+
742
+ # Determine if a hash field exists.
743
+ def hexists(key, field)
744
+ node_for(key).hexists(key, field)
745
+ end
746
+
747
+ # Increment the integer value of a hash field by the given integer number.
748
+ def hincrby(key, field, increment)
749
+ node_for(key).hincrby(key, field, increment)
750
+ end
751
+
752
+ # Increment the numeric value of a hash field by the given float number.
753
+ def hincrbyfloat(key, field, increment)
754
+ node_for(key).hincrbyfloat(key, field, increment)
755
+ end
756
+
757
+ # Get all the fields in a hash.
758
+ def hkeys(key)
759
+ node_for(key).hkeys(key)
760
+ end
761
+
762
+ # Get all the values in a hash.
763
+ def hvals(key)
764
+ node_for(key).hvals(key)
765
+ end
766
+
767
+ # Get all the fields and values in a hash.
768
+ def hgetall(key)
769
+ node_for(key).hgetall(key)
770
+ end
771
+
772
+ # Post a message to a channel.
773
+ def publish(channel, message)
774
+ node_for(channel).publish(channel, message)
775
+ end
776
+
777
+ def subscribed?
778
+ !!@subscribed_node
779
+ end
780
+
781
+ # Listen for messages published to the given channels.
782
+ def subscribe(channel, *channels, &block)
783
+ if channels.empty?
784
+ @subscribed_node = node_for(channel)
785
+ @subscribed_node.subscribe(channel, &block)
786
+ else
787
+ ensure_same_node(:subscribe, [channel] + channels) do |node|
788
+ @subscribed_node = node
789
+ node.subscribe(channel, *channels, &block)
790
+ end
791
+ end
792
+ end
793
+
794
+ # Stop listening for messages posted to the given channels.
795
+ def unsubscribe(*channels)
796
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
797
+
798
+ @subscribed_node.unsubscribe(*channels)
799
+ end
800
+
801
+ # Listen for messages published to channels matching the given patterns.
802
+ def psubscribe(*channels, &block)
803
+ raise NotImplementedError
804
+ end
805
+
806
+ # Stop listening for messages posted to channels matching the given
807
+ # patterns.
808
+ def punsubscribe(*channels)
809
+ raise NotImplementedError
810
+ end
811
+
812
+ # Watch the given keys to determine execution of the MULTI/EXEC block.
813
+ def watch(*keys, &block)
814
+ ensure_same_node(:watch, keys) do |node|
815
+ @watch_key = key_tag(keys.first) || keys.first.to_s
816
+
817
+ begin
818
+ node.watch(*keys, &block)
819
+ rescue StandardError
820
+ @watch_key = nil
821
+ raise
822
+ end
823
+ end
824
+ end
825
+
826
+ # Forget about all watched keys.
827
+ def unwatch
828
+ raise CannotDistribute, :unwatch unless @watch_key
829
+
830
+ result = node_for(@watch_key).unwatch
831
+ @watch_key = nil
832
+ result
833
+ end
834
+
835
+ def pipelined
836
+ raise CannotDistribute, :pipelined
837
+ end
838
+
839
+ # Mark the start of a transaction block.
840
+ def multi(&block)
841
+ raise CannotDistribute, :multi unless @watch_key
842
+
843
+ result = node_for(@watch_key).multi(&block)
844
+ @watch_key = nil if block_given?
845
+ result
846
+ end
847
+
848
+ # Execute all commands issued after MULTI.
849
+ def exec
850
+ raise CannotDistribute, :exec unless @watch_key
851
+
852
+ result = node_for(@watch_key).exec
853
+ @watch_key = nil
854
+ result
855
+ end
856
+
857
+ # Discard all commands issued after MULTI.
858
+ def discard
859
+ raise CannotDistribute, :discard unless @watch_key
860
+
861
+ result = node_for(@watch_key).discard
862
+ @watch_key = nil
863
+ result
864
+ end
865
+
866
+ # Control remote script registry.
867
+ def script(subcommand, *args)
868
+ on_each_node(:script, subcommand, *args)
869
+ end
870
+
871
+ # Add one or more members to a HyperLogLog structure.
872
+ def pfadd(key, member)
873
+ node_for(key).pfadd(key, member)
874
+ end
875
+
876
+ # Get the approximate cardinality of members added to HyperLogLog structure.
877
+ def pfcount(*keys)
878
+ ensure_same_node(:pfcount, keys.flatten(1)) do |node|
879
+ node.pfcount(keys)
880
+ end
881
+ end
882
+
883
+ # Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
884
+ # the observed Sets of the source HyperLogLog structures.
885
+ def pfmerge(dest_key, *source_key)
886
+ ensure_same_node(:pfmerge, [dest_key, *source_key]) do |node|
887
+ node.pfmerge(dest_key, *source_key)
888
+ end
889
+ end
890
+
891
+ def _eval(cmd, args)
892
+ script = args.shift
893
+ options = args.pop if args.last.is_a?(Hash)
894
+ options ||= {}
895
+
896
+ keys = args.shift || options[:keys] || []
897
+ argv = args.shift || options[:argv] || []
898
+
899
+ ensure_same_node(cmd, keys) do |node|
900
+ node.send(cmd, script, keys, argv)
901
+ end
902
+ end
903
+
904
+ # Evaluate Lua script.
905
+ def eval(*args)
906
+ _eval(:eval, args)
907
+ end
908
+
909
+ # Evaluate Lua script by its SHA.
910
+ def evalsha(*args)
911
+ _eval(:evalsha, args)
912
+ end
913
+
914
+ def inspect
915
+ "#<Redis client v#{Redis::VERSION} for #{nodes.map(&:id).join(', ')}>"
916
+ end
917
+
918
+ def dup
919
+ self.class.new(@node_configs, @default_options)
920
+ end
921
+
922
+ protected
923
+
924
+ def on_each_node(command, *args)
925
+ nodes.map do |node|
926
+ node.send(command, *args)
927
+ end
928
+ end
929
+
930
+ def node_index_for(key)
931
+ nodes.index(node_for(key))
932
+ end
933
+
934
+ def key_tag(key)
935
+ key.to_s[@tag, 1] if @tag
936
+ end
937
+
938
+ def ensure_same_node(command, keys)
939
+ all = true
940
+
941
+ tags = keys.map do |key|
942
+ tag = key_tag(key)
943
+ all = false unless tag
944
+ tag
945
+ end
946
+
947
+ if (all && tags.uniq.size != 1) || (!all && keys.uniq.size != 1)
948
+ # Not 1 unique tag or not 1 unique key
949
+ raise CannotDistribute, command
950
+ end
951
+
952
+ yield(node_for(keys.first))
953
+ end
954
+ end
955
+ end