redis 3.3.5 → 4.3.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +132 -2
- data/README.md +144 -79
- data/lib/redis.rb +1174 -405
- data/lib/redis/client.rb +150 -90
- data/lib/redis/cluster.rb +295 -0
- data/lib/redis/cluster/command.rb +81 -0
- data/lib/redis/cluster/command_loader.rb +34 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +107 -0
- data/lib/redis/cluster/node_key.rb +31 -0
- data/lib/redis/cluster/node_loader.rb +37 -0
- data/lib/redis/cluster/option.rb +93 -0
- data/lib/redis/cluster/slot.rb +86 -0
- data/lib/redis/cluster/slot_loader.rb +49 -0
- data/lib/redis/connection.rb +4 -2
- data/lib/redis/connection/command_helper.rb +5 -10
- data/lib/redis/connection/hiredis.rb +6 -5
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +126 -128
- data/lib/redis/connection/synchrony.rb +21 -8
- data/lib/redis/distributed.rb +147 -72
- data/lib/redis/errors.rb +48 -0
- data/lib/redis/hash_ring.rb +30 -73
- data/lib/redis/pipeline.rb +55 -15
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- metadata +49 -202
- data/.gitignore +0 -16
- data/.travis.yml +0 -89
- data/.travis/Gemfile +0 -11
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -87
- data/benchmarking/logging.rb +0 -71
- data/benchmarking/pipeline.rb +0 -51
- data/benchmarking/speed.rb +0 -21
- data/benchmarking/suite.rb +0 -24
- data/benchmarking/worker.rb +0 -71
- data/examples/basic.rb +0 -15
- data/examples/consistency.rb +0 -114
- data/examples/dist_redis.rb +0 -43
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel.rb +0 -41
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/redis.gemspec +0 -44
- data/test/bitpos_test.rb +0 -69
- data/test/blocking_commands_test.rb +0 -42
- data/test/client_test.rb +0 -59
- data/test/command_map_test.rb +0 -30
- data/test/commands_on_hashes_test.rb +0 -21
- data/test/commands_on_hyper_log_log_test.rb +0 -21
- data/test/commands_on_lists_test.rb +0 -20
- data/test/commands_on_sets_test.rb +0 -77
- data/test/commands_on_sorted_sets_test.rb +0 -137
- data/test/commands_on_strings_test.rb +0 -101
- data/test/commands_on_value_types_test.rb +0 -133
- data/test/connection_handling_test.rb +0 -277
- data/test/connection_test.rb +0 -57
- data/test/db/.gitkeep +0 -0
- data/test/distributed_blocking_commands_test.rb +0 -46
- data/test/distributed_commands_on_hashes_test.rb +0 -10
- data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
- data/test/distributed_commands_on_lists_test.rb +0 -22
- data/test/distributed_commands_on_sets_test.rb +0 -83
- data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
- data/test/distributed_commands_on_strings_test.rb +0 -59
- data/test/distributed_commands_on_value_types_test.rb +0 -95
- data/test/distributed_commands_requiring_clustering_test.rb +0 -164
- data/test/distributed_connection_handling_test.rb +0 -23
- data/test/distributed_internals_test.rb +0 -79
- data/test/distributed_key_tags_test.rb +0 -52
- data/test/distributed_persistence_control_commands_test.rb +0 -26
- data/test/distributed_publish_subscribe_test.rb +0 -92
- data/test/distributed_remote_server_control_commands_test.rb +0 -66
- data/test/distributed_scripting_test.rb +0 -102
- data/test/distributed_sorting_test.rb +0 -20
- data/test/distributed_test.rb +0 -58
- data/test/distributed_transactions_test.rb +0 -32
- data/test/encoding_test.rb +0 -18
- data/test/error_replies_test.rb +0 -59
- data/test/fork_safety_test.rb +0 -65
- data/test/helper.rb +0 -232
- data/test/helper_test.rb +0 -24
- data/test/internals_test.rb +0 -417
- data/test/lint/blocking_commands.rb +0 -150
- data/test/lint/hashes.rb +0 -162
- data/test/lint/hyper_log_log.rb +0 -60
- data/test/lint/lists.rb +0 -143
- data/test/lint/sets.rb +0 -140
- data/test/lint/sorted_sets.rb +0 -316
- data/test/lint/strings.rb +0 -260
- data/test/lint/value_types.rb +0 -122
- data/test/persistence_control_commands_test.rb +0 -26
- data/test/pipelining_commands_test.rb +0 -242
- data/test/publish_subscribe_test.rb +0 -282
- data/test/remote_server_control_commands_test.rb +0 -118
- data/test/scanning_test.rb +0 -413
- data/test/scripting_test.rb +0 -78
- data/test/sentinel_command_test.rb +0 -80
- data/test/sentinel_test.rb +0 -255
- data/test/sorting_test.rb +0 -59
- data/test/ssl_test.rb +0 -73
- data/test/support/connection/hiredis.rb +0 -1
- data/test/support/connection/ruby.rb +0 -1
- data/test/support/connection/synchrony.rb +0 -17
- data/test/support/redis_mock.rb +0 -130
- data/test/support/ssl/gen_certs.sh +0 -31
- data/test/support/ssl/trusted-ca.crt +0 -25
- data/test/support/ssl/trusted-ca.key +0 -27
- data/test/support/ssl/trusted-cert.crt +0 -81
- data/test/support/ssl/trusted-cert.key +0 -28
- data/test/support/ssl/untrusted-ca.crt +0 -26
- data/test/support/ssl/untrusted-ca.key +0 -27
- data/test/support/ssl/untrusted-cert.crt +0 -82
- data/test/support/ssl/untrusted-cert.key +0 -28
- data/test/support/wire/synchrony.rb +0 -24
- data/test/support/wire/thread.rb +0 -5
- data/test/synchrony_driver.rb +0 -88
- data/test/test.conf.erb +0 -9
- data/test/thread_safety_test.rb +0 -62
- data/test/transactions_test.rb +0 -264
- data/test/unknown_commands_test.rb +0 -14
- data/test/url_param_test.rb +0 -138
@@ -1,9 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "command_helper"
|
4
|
+
require_relative "registry"
|
5
|
+
require_relative "../errors"
|
4
6
|
require "em-synchrony"
|
5
7
|
require "hiredis/reader"
|
6
8
|
|
9
|
+
Kernel.warn(
|
10
|
+
"The redis synchrony driver is deprecated and will be removed in redis-rb 5.0. " \
|
11
|
+
"We're looking for people to maintain it as a separate gem, see https://github.com/redis/redis-rb/issues/915"
|
12
|
+
)
|
13
|
+
|
7
14
|
class Redis
|
8
15
|
module Connection
|
9
16
|
class RedisClient < EventMachine::Connection
|
@@ -46,9 +53,7 @@ class Redis
|
|
46
53
|
|
47
54
|
def read
|
48
55
|
@req = EventMachine::DefaultDeferrable.new
|
49
|
-
if @timeout > 0
|
50
|
-
@req.timeout(@timeout, :timeout)
|
51
|
-
end
|
56
|
+
@req.timeout(@timeout, :timeout) if @timeout > 0
|
52
57
|
EventMachine::Synchrony.sync @req
|
53
58
|
end
|
54
59
|
|
@@ -72,7 +77,15 @@ class Redis
|
|
72
77
|
|
73
78
|
def self.connect(config)
|
74
79
|
if config[:scheme] == "unix"
|
75
|
-
|
80
|
+
begin
|
81
|
+
conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
|
82
|
+
rescue RuntimeError => e
|
83
|
+
if e.message == "no connection"
|
84
|
+
raise Errno::ECONNREFUSED
|
85
|
+
else
|
86
|
+
raise e
|
87
|
+
end
|
88
|
+
end
|
76
89
|
elsif config[:scheme] == "rediss" || config[:ssl]
|
77
90
|
raise NotImplementedError, "SSL not supported by synchrony driver"
|
78
91
|
else
|
@@ -97,7 +110,7 @@ class Redis
|
|
97
110
|
end
|
98
111
|
|
99
112
|
def connected?
|
100
|
-
@connection
|
113
|
+
@connection&.connected?
|
101
114
|
end
|
102
115
|
|
103
116
|
def timeout=(timeout)
|
data/lib/redis/distributed.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "hash_ring"
|
2
4
|
|
3
5
|
class Redis
|
4
6
|
class Distributed
|
5
|
-
|
6
7
|
class CannotDistribute < RuntimeError
|
7
8
|
def initialize(command)
|
8
9
|
@command = command
|
9
10
|
end
|
10
11
|
|
11
12
|
def message
|
12
|
-
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need
|
13
|
+
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
|
14
|
+
"to be on the same server or because we cannot guarantee that the operation will be atomic."
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -22,10 +24,14 @@ class Redis
|
|
22
24
|
@default_options = options.dup
|
23
25
|
node_configs.each { |node_config| add_node(node_config) }
|
24
26
|
@subscribed_node = nil
|
27
|
+
@watch_key = nil
|
25
28
|
end
|
26
29
|
|
27
30
|
def node_for(key)
|
28
|
-
|
31
|
+
key = key_tag(key.to_s) || key.to_s
|
32
|
+
raise CannotDistribute, :watch if @watch_key && @watch_key != key
|
33
|
+
|
34
|
+
@ring.get_node(key)
|
29
35
|
end
|
30
36
|
|
31
37
|
def nodes
|
@@ -33,9 +39,9 @@ class Redis
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def add_node(options)
|
36
|
-
options = { :
|
42
|
+
options = { url: options } if options.is_a?(String)
|
37
43
|
options = @default_options.merge(options)
|
38
|
-
@ring.add_node Redis.new(
|
44
|
+
@ring.add_node Redis.new(options)
|
39
45
|
end
|
40
46
|
|
41
47
|
# Change the selected database for the current connection.
|
@@ -144,12 +150,12 @@ class Redis
|
|
144
150
|
end
|
145
151
|
|
146
152
|
# 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)
|
153
|
+
def restore(key, ttl, serialized_value, **options)
|
154
|
+
node_for(key).restore(key, ttl, serialized_value, **options)
|
149
155
|
end
|
150
156
|
|
151
157
|
# Transfer a key from the connected instance to another instance.
|
152
|
-
def migrate(
|
158
|
+
def migrate(_key, _options)
|
153
159
|
raise CannotDistribute, :migrate
|
154
160
|
end
|
155
161
|
|
@@ -161,9 +167,42 @@ class Redis
|
|
161
167
|
end
|
162
168
|
end
|
163
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
|
+
|
164
178
|
# Determine if a key exists.
|
165
|
-
def exists(
|
166
|
-
|
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
|
167
206
|
end
|
168
207
|
|
169
208
|
# Find all keys matching the given pattern.
|
@@ -196,11 +235,11 @@ class Redis
|
|
196
235
|
end
|
197
236
|
|
198
237
|
# Sort the elements in a list, set or sorted set.
|
199
|
-
def sort(key, options
|
238
|
+
def sort(key, **options)
|
200
239
|
keys = [key, options[:by], options[:store], *Array(options[:get])].compact
|
201
240
|
|
202
241
|
ensure_same_node(:sort, keys) do |node|
|
203
|
-
node.sort(key, options)
|
242
|
+
node.sort(key, **options)
|
204
243
|
end
|
205
244
|
end
|
206
245
|
|
@@ -235,8 +274,8 @@ class Redis
|
|
235
274
|
end
|
236
275
|
|
237
276
|
# Set the string value of a key.
|
238
|
-
def set(key, value, options
|
239
|
-
node_for(key).set(key, value, options)
|
277
|
+
def set(key, value, **options)
|
278
|
+
node_for(key).set(key, value, **options)
|
240
279
|
end
|
241
280
|
|
242
281
|
# Set the time to live in seconds of a key.
|
@@ -255,20 +294,20 @@ class Redis
|
|
255
294
|
end
|
256
295
|
|
257
296
|
# Set multiple keys to multiple values.
|
258
|
-
def mset(*
|
297
|
+
def mset(*_args)
|
259
298
|
raise CannotDistribute, :mset
|
260
299
|
end
|
261
300
|
|
262
|
-
def mapped_mset(
|
301
|
+
def mapped_mset(_hash)
|
263
302
|
raise CannotDistribute, :mapped_mset
|
264
303
|
end
|
265
304
|
|
266
305
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
267
|
-
def msetnx(*
|
306
|
+
def msetnx(*_args)
|
268
307
|
raise CannotDistribute, :msetnx
|
269
308
|
end
|
270
309
|
|
271
|
-
def mapped_msetnx(
|
310
|
+
def mapped_msetnx(_hash)
|
272
311
|
raise CannotDistribute, :mapped_msetnx
|
273
312
|
end
|
274
313
|
|
@@ -277,13 +316,16 @@ class Redis
|
|
277
316
|
node_for(key).get(key)
|
278
317
|
end
|
279
318
|
|
280
|
-
# Get the values of all the given keys.
|
319
|
+
# Get the values of all the given keys as an Array.
|
281
320
|
def mget(*keys)
|
282
|
-
|
321
|
+
mapped_mget(*keys).values_at(*keys)
|
283
322
|
end
|
284
323
|
|
324
|
+
# Get the values of all the given keys as a Hash.
|
285
325
|
def mapped_mget(*keys)
|
286
|
-
|
326
|
+
keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
|
327
|
+
results.merge! node.mapped_mget(*subkeys)
|
328
|
+
end
|
287
329
|
end
|
288
330
|
|
289
331
|
# Overwrite part of a string at key starting at the specified offset.
|
@@ -324,7 +366,7 @@ class Redis
|
|
324
366
|
end
|
325
367
|
|
326
368
|
# Return the position of the first bit set to 1 or 0 in a string.
|
327
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
369
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
328
370
|
node_for(key).bitpos(key, bit, start, stop)
|
329
371
|
end
|
330
372
|
|
@@ -342,7 +384,7 @@ class Redis
|
|
342
384
|
get(key)
|
343
385
|
end
|
344
386
|
|
345
|
-
def []=(key,value)
|
387
|
+
def []=(key, value)
|
346
388
|
set(key, value)
|
347
389
|
end
|
348
390
|
|
@@ -371,14 +413,14 @@ class Redis
|
|
371
413
|
node_for(key).rpushx(key, value)
|
372
414
|
end
|
373
415
|
|
374
|
-
# Remove and get the first
|
375
|
-
def lpop(key)
|
376
|
-
node_for(key).lpop(key)
|
416
|
+
# Remove and get the first elements in a list.
|
417
|
+
def lpop(key, count = nil)
|
418
|
+
node_for(key).lpop(key, count)
|
377
419
|
end
|
378
420
|
|
379
|
-
# Remove and get the last
|
380
|
-
def rpop(key)
|
381
|
-
node_for(key).rpop(key)
|
421
|
+
# Remove and get the last elements in a list.
|
422
|
+
def rpop(key, count = nil)
|
423
|
+
node_for(key).rpop(key, count)
|
382
424
|
end
|
383
425
|
|
384
426
|
# Remove the last element in a list, append it to another list and return
|
@@ -390,14 +432,12 @@ class Redis
|
|
390
432
|
end
|
391
433
|
|
392
434
|
def _bpop(cmd, args)
|
393
|
-
|
394
|
-
|
395
|
-
case args.last
|
396
|
-
when Hash
|
435
|
+
timeout = if args.last.is_a?(Hash)
|
397
436
|
options = args.pop
|
398
|
-
|
437
|
+
options[:timeout]
|
438
|
+
elsif args.last.respond_to?(:to_int)
|
399
439
|
# Issue deprecation notice in obnoxious mode...
|
400
|
-
|
440
|
+
args.pop.to_int
|
401
441
|
end
|
402
442
|
|
403
443
|
if args.size > 1
|
@@ -407,7 +447,11 @@ class Redis
|
|
407
447
|
keys = args.flatten
|
408
448
|
|
409
449
|
ensure_same_node(cmd, keys) do |node|
|
410
|
-
|
450
|
+
if timeout
|
451
|
+
node.__send__(cmd, keys, timeout: timeout)
|
452
|
+
else
|
453
|
+
node.__send__(cmd, keys)
|
454
|
+
end
|
411
455
|
end
|
412
456
|
end
|
413
457
|
|
@@ -425,15 +469,9 @@ class Redis
|
|
425
469
|
|
426
470
|
# Pop a value from a list, push it to another list and return it; or block
|
427
471
|
# until one is available.
|
428
|
-
def brpoplpush(source, destination,
|
429
|
-
case options
|
430
|
-
when Integer
|
431
|
-
# Issue deprecation notice in obnoxious mode...
|
432
|
-
options = { :timeout => options }
|
433
|
-
end
|
434
|
-
|
472
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, **options)
|
435
473
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
436
|
-
node.brpoplpush(source, destination, options)
|
474
|
+
node.brpoplpush(source, destination, deprecated_timeout, **options)
|
437
475
|
end
|
438
476
|
end
|
439
477
|
|
@@ -509,6 +547,16 @@ class Redis
|
|
509
547
|
node_for(key).smembers(key)
|
510
548
|
end
|
511
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
|
+
|
512
560
|
# Subtract multiple sets.
|
513
561
|
def sdiff(*keys)
|
514
562
|
ensure_same_node(:sdiff, keys) do |node|
|
@@ -561,6 +609,7 @@ class Redis
|
|
561
609
|
def zadd(key, *args)
|
562
610
|
node_for(key).zadd(key, *args)
|
563
611
|
end
|
612
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
564
613
|
|
565
614
|
# Increment the score of a member in a sorted set.
|
566
615
|
def zincrby(key, increment, member)
|
@@ -578,14 +627,14 @@ class Redis
|
|
578
627
|
end
|
579
628
|
|
580
629
|
# 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)
|
630
|
+
def zrange(key, start, stop, **options)
|
631
|
+
node_for(key).zrange(key, start, stop, **options)
|
583
632
|
end
|
584
633
|
|
585
634
|
# Return a range of members in a sorted set, by index, with scores ordered
|
586
635
|
# from high to low.
|
587
|
-
def zrevrange(key, start, stop, options
|
588
|
-
node_for(key).zrevrange(key, start, stop, options)
|
636
|
+
def zrevrange(key, start, stop, **options)
|
637
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
589
638
|
end
|
590
639
|
|
591
640
|
# Determine the index of a member in a sorted set.
|
@@ -605,14 +654,14 @@ class Redis
|
|
605
654
|
end
|
606
655
|
|
607
656
|
# 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)
|
657
|
+
def zrangebyscore(key, min, max, **options)
|
658
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
610
659
|
end
|
611
660
|
|
612
661
|
# Return a range of members in a sorted set, by score, with scores ordered
|
613
662
|
# from high to low.
|
614
|
-
def zrevrangebyscore(key, max, min, options
|
615
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
663
|
+
def zrevrangebyscore(key, max, min, **options)
|
664
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
616
665
|
end
|
617
666
|
|
618
667
|
# Remove all members in a sorted set within the given scores.
|
@@ -627,16 +676,16 @@ class Redis
|
|
627
676
|
|
628
677
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
629
678
|
# key.
|
630
|
-
def zinterstore(destination, keys, options
|
679
|
+
def zinterstore(destination, keys, **options)
|
631
680
|
ensure_same_node(:zinterstore, [destination] + keys) do |node|
|
632
|
-
node.zinterstore(destination, keys, options)
|
681
|
+
node.zinterstore(destination, keys, **options)
|
633
682
|
end
|
634
683
|
end
|
635
684
|
|
636
685
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
637
|
-
def zunionstore(destination, keys, options
|
686
|
+
def zunionstore(destination, keys, **options)
|
638
687
|
ensure_same_node(:zunionstore, [destination] + keys) do |node|
|
639
|
-
node.zunionstore(destination, keys, options)
|
688
|
+
node.zunionstore(destination, keys, **options)
|
640
689
|
end
|
641
690
|
end
|
642
691
|
|
@@ -645,9 +694,9 @@ class Redis
|
|
645
694
|
node_for(key).hlen(key)
|
646
695
|
end
|
647
696
|
|
648
|
-
# Set
|
649
|
-
def hset(key,
|
650
|
-
node_for(key).hset(key,
|
697
|
+
# Set multiple hash fields to multiple values.
|
698
|
+
def hset(key, *attrs)
|
699
|
+
node_for(key).hset(key, *attrs)
|
651
700
|
end
|
652
701
|
|
653
702
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -679,8 +728,8 @@ class Redis
|
|
679
728
|
end
|
680
729
|
|
681
730
|
# Delete one or more hash fields.
|
682
|
-
def hdel(key,
|
683
|
-
node_for(key).hdel(key,
|
731
|
+
def hdel(key, *fields)
|
732
|
+
node_for(key).hdel(key, *fields)
|
684
733
|
end
|
685
734
|
|
686
735
|
# Determine if a hash field exists.
|
@@ -719,7 +768,7 @@ class Redis
|
|
719
768
|
end
|
720
769
|
|
721
770
|
def subscribed?
|
722
|
-
|
771
|
+
!!@subscribed_node
|
723
772
|
end
|
724
773
|
|
725
774
|
# Listen for messages published to the given channels.
|
@@ -737,7 +786,8 @@ class Redis
|
|
737
786
|
|
738
787
|
# Stop listening for messages posted to the given channels.
|
739
788
|
def unsubscribe(*channels)
|
740
|
-
raise
|
789
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
790
|
+
|
741
791
|
@subscribed_node.unsubscribe(*channels)
|
742
792
|
end
|
743
793
|
|
@@ -753,13 +803,26 @@ class Redis
|
|
753
803
|
end
|
754
804
|
|
755
805
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
756
|
-
def watch(*keys)
|
757
|
-
|
806
|
+
def watch(*keys, &block)
|
807
|
+
ensure_same_node(:watch, keys) do |node|
|
808
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
809
|
+
|
810
|
+
begin
|
811
|
+
node.watch(*keys, &block)
|
812
|
+
rescue StandardError
|
813
|
+
@watch_key = nil
|
814
|
+
raise
|
815
|
+
end
|
816
|
+
end
|
758
817
|
end
|
759
818
|
|
760
819
|
# Forget about all watched keys.
|
761
820
|
def unwatch
|
762
|
-
raise CannotDistribute, :unwatch
|
821
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
822
|
+
|
823
|
+
result = node_for(@watch_key).unwatch
|
824
|
+
@watch_key = nil
|
825
|
+
result
|
763
826
|
end
|
764
827
|
|
765
828
|
def pipelined
|
@@ -767,18 +830,30 @@ class Redis
|
|
767
830
|
end
|
768
831
|
|
769
832
|
# Mark the start of a transaction block.
|
770
|
-
def multi
|
771
|
-
raise CannotDistribute, :multi
|
833
|
+
def multi(&block)
|
834
|
+
raise CannotDistribute, :multi unless @watch_key
|
835
|
+
|
836
|
+
result = node_for(@watch_key).multi(&block)
|
837
|
+
@watch_key = nil if block_given?
|
838
|
+
result
|
772
839
|
end
|
773
840
|
|
774
841
|
# Execute all commands issued after MULTI.
|
775
842
|
def exec
|
776
|
-
raise CannotDistribute, :exec
|
843
|
+
raise CannotDistribute, :exec unless @watch_key
|
844
|
+
|
845
|
+
result = node_for(@watch_key).exec
|
846
|
+
@watch_key = nil
|
847
|
+
result
|
777
848
|
end
|
778
849
|
|
779
850
|
# Discard all commands issued after MULTI.
|
780
851
|
def discard
|
781
|
-
raise CannotDistribute, :discard
|
852
|
+
raise CannotDistribute, :discard unless @watch_key
|
853
|
+
|
854
|
+
result = node_for(@watch_key).discard
|
855
|
+
@watch_key = nil
|
856
|
+
result
|
782
857
|
end
|
783
858
|
|
784
859
|
# Control remote script registry.
|
@@ -837,7 +912,7 @@ class Redis
|
|
837
912
|
self.class.new(@node_configs, @default_options)
|
838
913
|
end
|
839
914
|
|
840
|
-
|
915
|
+
protected
|
841
916
|
|
842
917
|
def on_each_node(command, *args)
|
843
918
|
nodes.map do |node|
|