finsync_redis 3.3.5

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