redis 3.3.3 → 5.0.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +280 -12
- data/README.md +141 -147
- data/lib/redis/client.rb +77 -539
- data/lib/redis/commands/bitmaps.rb +66 -0
- data/lib/redis/commands/cluster.rb +28 -0
- data/lib/redis/commands/connection.rb +53 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +254 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +437 -0
- data/lib/redis/commands/lists.rb +285 -0
- data/lib/redis/commands/pubsub.rb +54 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +214 -0
- data/lib/redis/commands/sorted_sets.rb +818 -0
- data/lib/redis/commands/streams.rb +384 -0
- data/lib/redis/commands/strings.rb +314 -0
- data/lib/redis/commands/transactions.rb +115 -0
- data/lib/redis/commands.rb +235 -0
- data/lib/redis/distributed.rb +300 -108
- data/lib/redis/errors.rb +22 -1
- data/lib/redis/hash_ring.rb +36 -79
- data/lib/redis/pipeline.rb +69 -83
- data/lib/redis/subscribe.rb +26 -19
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +113 -2685
- metadata +40 -218
- data/.gitignore +0 -16
- data/.travis/Gemfile +0 -11
- data/.travis.yml +0 -89
- 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/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sentinel.rb +0 -41
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/lib/redis/connection/command_helper.rb +0 -44
- data/lib/redis/connection/hiredis.rb +0 -66
- data/lib/redis/connection/registry.rb +0 -12
- data/lib/redis/connection/ruby.rb +0 -429
- data/lib/redis/connection/synchrony.rb +0 -133
- data/lib/redis/connection.rb +0 -9
- 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/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 -457
- 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
data/lib/redis/distributed.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "redis/hash_ring"
|
2
4
|
|
3
5
|
class Redis
|
4
6
|
class Distributed
|
5
|
-
|
6
7
|
class CannotDistribute < RuntimeError
|
7
8
|
def initialize(command)
|
8
9
|
@command = command
|
9
10
|
end
|
10
11
|
|
11
12
|
def message
|
12
|
-
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need
|
13
|
+
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
|
14
|
+
"to be on the same server or because we cannot guarantee that the operation will be atomic."
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -18,14 +20,18 @@ class Redis
|
|
18
20
|
def initialize(node_configs, options = {})
|
19
21
|
@tag = options[:tag] || /^\{(.+?)\}/
|
20
22
|
@ring = options[:ring] || HashRing.new
|
21
|
-
@node_configs = node_configs.dup
|
23
|
+
@node_configs = node_configs.map(&:dup)
|
22
24
|
@default_options = options.dup
|
23
25
|
node_configs.each { |node_config| add_node(node_config) }
|
24
26
|
@subscribed_node = nil
|
27
|
+
@watch_key = nil
|
25
28
|
end
|
26
29
|
|
27
30
|
def node_for(key)
|
28
|
-
|
31
|
+
key = key_tag(key.to_s) || key.to_s
|
32
|
+
raise CannotDistribute, :watch if @watch_key && @watch_key != key
|
33
|
+
|
34
|
+
@ring.get_node(key)
|
29
35
|
end
|
30
36
|
|
31
37
|
def nodes
|
@@ -33,9 +39,11 @@ class Redis
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def add_node(options)
|
36
|
-
options = { :
|
42
|
+
options = { url: options } if options.is_a?(String)
|
37
43
|
options = @default_options.merge(options)
|
38
|
-
|
44
|
+
options.delete(:tag)
|
45
|
+
options.delete(:ring)
|
46
|
+
@ring.add_node Redis.new(options)
|
39
47
|
end
|
40
48
|
|
41
49
|
# Change the selected database for the current connection.
|
@@ -58,6 +66,10 @@ class Redis
|
|
58
66
|
on_each_node :quit
|
59
67
|
end
|
60
68
|
|
69
|
+
def close
|
70
|
+
on_each_node :close
|
71
|
+
end
|
72
|
+
|
61
73
|
# Asynchronously save the dataset to disk.
|
62
74
|
def bgsave
|
63
75
|
on_each_node :bgsave
|
@@ -109,13 +121,13 @@ class Redis
|
|
109
121
|
end
|
110
122
|
|
111
123
|
# Set a key's time to live in seconds.
|
112
|
-
def expire(key, seconds)
|
113
|
-
node_for(key).expire(key, seconds)
|
124
|
+
def expire(key, seconds, **kwargs)
|
125
|
+
node_for(key).expire(key, seconds, **kwargs)
|
114
126
|
end
|
115
127
|
|
116
128
|
# Set the expiration for a key as a UNIX timestamp.
|
117
|
-
def expireat(key, unix_time)
|
118
|
-
node_for(key).expireat(key, unix_time)
|
129
|
+
def expireat(key, unix_time, **kwargs)
|
130
|
+
node_for(key).expireat(key, unix_time, **kwargs)
|
119
131
|
end
|
120
132
|
|
121
133
|
# Get the time to live (in seconds) for a key.
|
@@ -124,13 +136,13 @@ class Redis
|
|
124
136
|
end
|
125
137
|
|
126
138
|
# Set a key's time to live in milliseconds.
|
127
|
-
def pexpire(key, milliseconds)
|
128
|
-
node_for(key).pexpire(key, milliseconds)
|
139
|
+
def pexpire(key, milliseconds, **kwarg)
|
140
|
+
node_for(key).pexpire(key, milliseconds, **kwarg)
|
129
141
|
end
|
130
142
|
|
131
143
|
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
|
132
|
-
def pexpireat(key, ms_unix_time)
|
133
|
-
node_for(key).pexpireat(key, ms_unix_time)
|
144
|
+
def pexpireat(key, ms_unix_time, **kwarg)
|
145
|
+
node_for(key).pexpireat(key, ms_unix_time, **kwarg)
|
134
146
|
end
|
135
147
|
|
136
148
|
# Get the time to live (in milliseconds) for a key.
|
@@ -144,26 +156,50 @@ class Redis
|
|
144
156
|
end
|
145
157
|
|
146
158
|
# Create a key using the serialized value, previously obtained using DUMP.
|
147
|
-
def restore(key, ttl, serialized_value)
|
148
|
-
node_for(key).restore(key, ttl, serialized_value)
|
159
|
+
def restore(key, ttl, serialized_value, **options)
|
160
|
+
node_for(key).restore(key, ttl, serialized_value, **options)
|
149
161
|
end
|
150
162
|
|
151
163
|
# Transfer a key from the connected instance to another instance.
|
152
|
-
def migrate(
|
164
|
+
def migrate(_key, _options)
|
153
165
|
raise CannotDistribute, :migrate
|
154
166
|
end
|
155
167
|
|
156
168
|
# Delete a key.
|
157
169
|
def del(*args)
|
170
|
+
args.flatten!(1)
|
158
171
|
keys_per_node = args.group_by { |key| node_for(key) }
|
159
172
|
keys_per_node.inject(0) do |sum, (node, keys)|
|
160
173
|
sum + node.del(*keys)
|
161
174
|
end
|
162
175
|
end
|
163
176
|
|
177
|
+
# Unlink keys.
|
178
|
+
def unlink(*args)
|
179
|
+
args.flatten!(1)
|
180
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
181
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
182
|
+
sum + node.unlink(*keys)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
164
186
|
# Determine if a key exists.
|
165
|
-
def exists(
|
166
|
-
|
187
|
+
def exists(*args)
|
188
|
+
args.flatten!(1)
|
189
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
190
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
191
|
+
sum + node.exists(*keys)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Determine if any of the keys exists.
|
196
|
+
def exists?(*args)
|
197
|
+
args.flatten!(1)
|
198
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
199
|
+
keys_per_node.each do |node, keys|
|
200
|
+
return true if node.exists?(*keys)
|
201
|
+
end
|
202
|
+
false
|
167
203
|
end
|
168
204
|
|
169
205
|
# Find all keys matching the given pattern.
|
@@ -176,6 +212,13 @@ class Redis
|
|
176
212
|
node_for(key).move(key, db)
|
177
213
|
end
|
178
214
|
|
215
|
+
# Copy a value from one key to another.
|
216
|
+
def copy(source, destination, **options)
|
217
|
+
ensure_same_node(:copy, [source, destination]) do |node|
|
218
|
+
node.copy(source, destination, **options)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
179
222
|
# Return a random key from the keyspace.
|
180
223
|
def randomkey
|
181
224
|
raise CannotDistribute, :randomkey
|
@@ -196,11 +239,11 @@ class Redis
|
|
196
239
|
end
|
197
240
|
|
198
241
|
# Sort the elements in a list, set or sorted set.
|
199
|
-
def sort(key, options
|
242
|
+
def sort(key, **options)
|
200
243
|
keys = [key, options[:by], options[:store], *Array(options[:get])].compact
|
201
244
|
|
202
245
|
ensure_same_node(:sort, keys) do |node|
|
203
|
-
node.sort(key, options)
|
246
|
+
node.sort(key, **options)
|
204
247
|
end
|
205
248
|
end
|
206
249
|
|
@@ -235,8 +278,8 @@ class Redis
|
|
235
278
|
end
|
236
279
|
|
237
280
|
# Set the string value of a key.
|
238
|
-
def set(key, value, options
|
239
|
-
node_for(key).set(key, value, options)
|
281
|
+
def set(key, value, **options)
|
282
|
+
node_for(key).set(key, value, **options)
|
240
283
|
end
|
241
284
|
|
242
285
|
# Set the time to live in seconds of a key.
|
@@ -255,20 +298,20 @@ class Redis
|
|
255
298
|
end
|
256
299
|
|
257
300
|
# Set multiple keys to multiple values.
|
258
|
-
def mset(*
|
301
|
+
def mset(*)
|
259
302
|
raise CannotDistribute, :mset
|
260
303
|
end
|
261
304
|
|
262
|
-
def mapped_mset(
|
305
|
+
def mapped_mset(_hash)
|
263
306
|
raise CannotDistribute, :mapped_mset
|
264
307
|
end
|
265
308
|
|
266
309
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
267
|
-
def msetnx(*
|
310
|
+
def msetnx(*)
|
268
311
|
raise CannotDistribute, :msetnx
|
269
312
|
end
|
270
313
|
|
271
|
-
def mapped_msetnx(
|
314
|
+
def mapped_msetnx(_hash)
|
272
315
|
raise CannotDistribute, :mapped_msetnx
|
273
316
|
end
|
274
317
|
|
@@ -277,13 +320,28 @@ class Redis
|
|
277
320
|
node_for(key).get(key)
|
278
321
|
end
|
279
322
|
|
280
|
-
# Get the
|
323
|
+
# Get the value of a key and delete it.
|
324
|
+
def getdel(key)
|
325
|
+
node_for(key).getdel(key)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Get the value of a key and sets its time to live based on options.
|
329
|
+
def getex(key, **options)
|
330
|
+
node_for(key).getex(key, **options)
|
331
|
+
end
|
332
|
+
|
333
|
+
# Get the values of all the given keys as an Array.
|
281
334
|
def mget(*keys)
|
282
|
-
|
335
|
+
keys.flatten!(1)
|
336
|
+
mapped_mget(*keys).values_at(*keys)
|
283
337
|
end
|
284
338
|
|
339
|
+
# Get the values of all the given keys as a Hash.
|
285
340
|
def mapped_mget(*keys)
|
286
|
-
|
341
|
+
keys.flatten!(1)
|
342
|
+
keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
|
343
|
+
results.merge! node.mapped_mget(*subkeys)
|
344
|
+
end
|
287
345
|
end
|
288
346
|
|
289
347
|
# Overwrite part of a string at key starting at the specified offset.
|
@@ -318,13 +376,14 @@ class Redis
|
|
318
376
|
|
319
377
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
320
378
|
def bitop(operation, destkey, *keys)
|
379
|
+
keys.flatten!(1)
|
321
380
|
ensure_same_node(:bitop, [destkey] + keys) do |node|
|
322
|
-
node.bitop(operation, destkey,
|
381
|
+
node.bitop(operation, destkey, keys)
|
323
382
|
end
|
324
383
|
end
|
325
384
|
|
326
385
|
# Return the position of the first bit set to 1 or 0 in a string.
|
327
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
386
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
328
387
|
node_for(key).bitpos(key, bit, start, stop)
|
329
388
|
end
|
330
389
|
|
@@ -342,7 +401,7 @@ class Redis
|
|
342
401
|
get(key)
|
343
402
|
end
|
344
403
|
|
345
|
-
def []=(key,value)
|
404
|
+
def []=(key, value)
|
346
405
|
set(key, value)
|
347
406
|
end
|
348
407
|
|
@@ -351,6 +410,21 @@ class Redis
|
|
351
410
|
node_for(key).llen(key)
|
352
411
|
end
|
353
412
|
|
413
|
+
# Remove the first/last element in a list, append/prepend it to another list and return it.
|
414
|
+
def lmove(source, destination, where_source, where_destination)
|
415
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
416
|
+
node.lmove(source, destination, where_source, where_destination)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
# Remove the first/last element in a list and append/prepend it
|
421
|
+
# to another list and return it, or block until one is available.
|
422
|
+
def blmove(source, destination, where_source, where_destination, timeout: 0)
|
423
|
+
ensure_same_node(:lmove, [source, destination]) do |node|
|
424
|
+
node.blmove(source, destination, where_source, where_destination, timeout: timeout)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
354
428
|
# Prepend one or more values to a list.
|
355
429
|
def lpush(key, value)
|
356
430
|
node_for(key).lpush(key, value)
|
@@ -371,14 +445,14 @@ class Redis
|
|
371
445
|
node_for(key).rpushx(key, value)
|
372
446
|
end
|
373
447
|
|
374
|
-
# Remove and get the first
|
375
|
-
def lpop(key)
|
376
|
-
node_for(key).lpop(key)
|
448
|
+
# Remove and get the first elements in a list.
|
449
|
+
def lpop(key, count = nil)
|
450
|
+
node_for(key).lpop(key, count)
|
377
451
|
end
|
378
452
|
|
379
|
-
# Remove and get the last
|
380
|
-
def rpop(key)
|
381
|
-
node_for(key).rpop(key)
|
453
|
+
# Remove and get the last elements in a list.
|
454
|
+
def rpop(key, count = nil)
|
455
|
+
node_for(key).rpop(key, count)
|
382
456
|
end
|
383
457
|
|
384
458
|
# Remove the last element in a list, append it to another list and return
|
@@ -390,24 +464,19 @@ class Redis
|
|
390
464
|
end
|
391
465
|
|
392
466
|
def _bpop(cmd, args)
|
393
|
-
|
394
|
-
|
395
|
-
case args.last
|
396
|
-
when Hash
|
467
|
+
timeout = if args.last.is_a?(Hash)
|
397
468
|
options = args.pop
|
398
|
-
|
399
|
-
# Issue deprecation notice in obnoxious mode...
|
400
|
-
options[:timeout] = args.pop
|
469
|
+
options[:timeout]
|
401
470
|
end
|
402
471
|
|
403
|
-
|
404
|
-
# Issue deprecation notice in obnoxious mode...
|
405
|
-
end
|
472
|
+
args.flatten!(1)
|
406
473
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
474
|
+
ensure_same_node(cmd, args) do |node|
|
475
|
+
if timeout
|
476
|
+
node.__send__(cmd, args, timeout: timeout)
|
477
|
+
else
|
478
|
+
node.__send__(cmd, args)
|
479
|
+
end
|
411
480
|
end
|
412
481
|
end
|
413
482
|
|
@@ -417,6 +486,18 @@ class Redis
|
|
417
486
|
_bpop(:blpop, args)
|
418
487
|
end
|
419
488
|
|
489
|
+
def bzpopmax(*args)
|
490
|
+
_bpop(:bzpopmax, args) do |reply|
|
491
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def bzpopmin(*args)
|
496
|
+
_bpop(:bzpopmin, args) do |reply|
|
497
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
420
501
|
# Remove and get the last element in a list, or block until one is
|
421
502
|
# available.
|
422
503
|
def brpop(*args)
|
@@ -425,15 +506,9 @@ class Redis
|
|
425
506
|
|
426
507
|
# Pop a value from a list, push it to another list and return it; or block
|
427
508
|
# until one is available.
|
428
|
-
def brpoplpush(source, destination, options
|
429
|
-
case options
|
430
|
-
when Integer
|
431
|
-
# Issue deprecation notice in obnoxious mode...
|
432
|
-
options = { :timeout => options }
|
433
|
-
end
|
434
|
-
|
509
|
+
def brpoplpush(source, destination, **options)
|
435
510
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
436
|
-
node.brpoplpush(source, destination, options)
|
511
|
+
node.brpoplpush(source, destination, **options)
|
437
512
|
end
|
438
513
|
end
|
439
514
|
|
@@ -473,13 +548,23 @@ class Redis
|
|
473
548
|
end
|
474
549
|
|
475
550
|
# Add one or more members to a set.
|
476
|
-
def sadd(key,
|
477
|
-
node_for(key).sadd(key,
|
551
|
+
def sadd(key, *members)
|
552
|
+
node_for(key).sadd(key, *members)
|
553
|
+
end
|
554
|
+
|
555
|
+
# Add one or more members to a set.
|
556
|
+
def sadd?(key, *members)
|
557
|
+
node_for(key).sadd?(key, *members)
|
478
558
|
end
|
479
559
|
|
480
560
|
# Remove one or more members from a set.
|
481
|
-
def srem(key,
|
482
|
-
node_for(key).srem(key,
|
561
|
+
def srem(key, *members)
|
562
|
+
node_for(key).srem(key, *members)
|
563
|
+
end
|
564
|
+
|
565
|
+
# Remove one or more members from a set.
|
566
|
+
def srem?(key, *members)
|
567
|
+
node_for(key).srem?(key, *members)
|
483
568
|
end
|
484
569
|
|
485
570
|
# Remove and return a random member from a set.
|
@@ -504,50 +589,71 @@ class Redis
|
|
504
589
|
node_for(key).sismember(key, member)
|
505
590
|
end
|
506
591
|
|
592
|
+
# Determine if multiple values are members of a set.
|
593
|
+
def smismember(key, *members)
|
594
|
+
node_for(key).smismember(key, *members)
|
595
|
+
end
|
596
|
+
|
507
597
|
# Get all the members in a set.
|
508
598
|
def smembers(key)
|
509
599
|
node_for(key).smembers(key)
|
510
600
|
end
|
511
601
|
|
602
|
+
# Scan a set
|
603
|
+
def sscan(key, cursor, **options)
|
604
|
+
node_for(key).sscan(key, cursor, **options)
|
605
|
+
end
|
606
|
+
|
607
|
+
# Scan a set and return an enumerator
|
608
|
+
def sscan_each(key, **options, &block)
|
609
|
+
node_for(key).sscan_each(key, **options, &block)
|
610
|
+
end
|
611
|
+
|
512
612
|
# Subtract multiple sets.
|
513
613
|
def sdiff(*keys)
|
614
|
+
keys.flatten!(1)
|
514
615
|
ensure_same_node(:sdiff, keys) do |node|
|
515
|
-
node.sdiff(
|
616
|
+
node.sdiff(keys)
|
516
617
|
end
|
517
618
|
end
|
518
619
|
|
519
620
|
# Subtract multiple sets and store the resulting set in a key.
|
520
621
|
def sdiffstore(destination, *keys)
|
521
|
-
|
522
|
-
|
622
|
+
keys.flatten!(1)
|
623
|
+
ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
|
624
|
+
node.sdiffstore(destination, keys)
|
523
625
|
end
|
524
626
|
end
|
525
627
|
|
526
628
|
# Intersect multiple sets.
|
527
629
|
def sinter(*keys)
|
630
|
+
keys.flatten!(1)
|
528
631
|
ensure_same_node(:sinter, keys) do |node|
|
529
|
-
node.sinter(
|
632
|
+
node.sinter(keys)
|
530
633
|
end
|
531
634
|
end
|
532
635
|
|
533
636
|
# Intersect multiple sets and store the resulting set in a key.
|
534
637
|
def sinterstore(destination, *keys)
|
535
|
-
|
536
|
-
|
638
|
+
keys.flatten!(1)
|
639
|
+
ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
|
640
|
+
node.sinterstore(destination, keys)
|
537
641
|
end
|
538
642
|
end
|
539
643
|
|
540
644
|
# Add multiple sets.
|
541
645
|
def sunion(*keys)
|
646
|
+
keys.flatten!(1)
|
542
647
|
ensure_same_node(:sunion, keys) do |node|
|
543
|
-
node.sunion(
|
648
|
+
node.sunion(keys)
|
544
649
|
end
|
545
650
|
end
|
546
651
|
|
547
652
|
# Add multiple sets and store the resulting set in a key.
|
548
653
|
def sunionstore(destination, *keys)
|
549
|
-
|
550
|
-
|
654
|
+
keys.flatten!(1)
|
655
|
+
ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
|
656
|
+
node.sunionstore(destination, keys)
|
551
657
|
end
|
552
658
|
end
|
553
659
|
|
@@ -561,6 +667,7 @@ class Redis
|
|
561
667
|
def zadd(key, *args)
|
562
668
|
node_for(key).zadd(key, *args)
|
563
669
|
end
|
670
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
564
671
|
|
565
672
|
# Increment the score of a member in a sorted set.
|
566
673
|
def zincrby(key, increment, member)
|
@@ -577,15 +684,33 @@ class Redis
|
|
577
684
|
node_for(key).zscore(key, member)
|
578
685
|
end
|
579
686
|
|
580
|
-
#
|
581
|
-
def
|
582
|
-
node_for(key).
|
687
|
+
# Get one or more random members from a sorted set.
|
688
|
+
def zrandmember(key, count = nil, **options)
|
689
|
+
node_for(key).zrandmember(key, count, **options)
|
690
|
+
end
|
691
|
+
|
692
|
+
# Get the scores associated with the given members in a sorted set.
|
693
|
+
def zmscore(key, *members)
|
694
|
+
node_for(key).zmscore(key, *members)
|
695
|
+
end
|
696
|
+
|
697
|
+
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
698
|
+
def zrange(key, start, stop, **options)
|
699
|
+
node_for(key).zrange(key, start, stop, **options)
|
700
|
+
end
|
701
|
+
|
702
|
+
# Select a range of members in a sorted set, by index, score or lexicographical ordering
|
703
|
+
# and store the resulting sorted set in a new key.
|
704
|
+
def zrangestore(dest_key, src_key, start, stop, **options)
|
705
|
+
ensure_same_node(:zrangestore, [dest_key, src_key]) do |node|
|
706
|
+
node.zrangestore(dest_key, src_key, start, stop, **options)
|
707
|
+
end
|
583
708
|
end
|
584
709
|
|
585
710
|
# Return a range of members in a sorted set, by index, with scores ordered
|
586
711
|
# from high to low.
|
587
|
-
def zrevrange(key, start, stop, options
|
588
|
-
node_for(key).zrevrange(key, start, stop, options)
|
712
|
+
def zrevrange(key, start, stop, **options)
|
713
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
589
714
|
end
|
590
715
|
|
591
716
|
# Determine the index of a member in a sorted set.
|
@@ -605,14 +730,14 @@ class Redis
|
|
605
730
|
end
|
606
731
|
|
607
732
|
# 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)
|
733
|
+
def zrangebyscore(key, min, max, **options)
|
734
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
610
735
|
end
|
611
736
|
|
612
737
|
# Return a range of members in a sorted set, by score, with scores ordered
|
613
738
|
# from high to low.
|
614
|
-
def zrevrangebyscore(key, max, min, options
|
615
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
739
|
+
def zrevrangebyscore(key, max, min, **options)
|
740
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
616
741
|
end
|
617
742
|
|
618
743
|
# Remove all members in a sorted set within the given scores.
|
@@ -625,18 +750,53 @@ class Redis
|
|
625
750
|
node_for(key).zcount(key, min, max)
|
626
751
|
end
|
627
752
|
|
753
|
+
# Get the intersection of multiple sorted sets
|
754
|
+
def zinter(*keys, **options)
|
755
|
+
keys.flatten!(1)
|
756
|
+
ensure_same_node(:zinter, keys) do |node|
|
757
|
+
node.zinter(keys, **options)
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
628
761
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
629
762
|
# key.
|
630
|
-
def zinterstore(destination, keys, options
|
631
|
-
|
632
|
-
|
763
|
+
def zinterstore(destination, *keys, **options)
|
764
|
+
keys.flatten!(1)
|
765
|
+
ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
|
766
|
+
node.zinterstore(destination, keys, **options)
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
# Return the union of multiple sorted sets.
|
771
|
+
def zunion(*keys, **options)
|
772
|
+
keys.flatten!(1)
|
773
|
+
ensure_same_node(:zunion, keys) do |node|
|
774
|
+
node.zunion(keys, **options)
|
633
775
|
end
|
634
776
|
end
|
635
777
|
|
636
778
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
637
|
-
def zunionstore(destination, keys, options
|
638
|
-
|
639
|
-
|
779
|
+
def zunionstore(destination, *keys, **options)
|
780
|
+
keys.flatten!(1)
|
781
|
+
ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
|
782
|
+
node.zunionstore(destination, keys, **options)
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
# Return the difference between the first and all successive input sorted sets.
|
787
|
+
def zdiff(*keys, **options)
|
788
|
+
keys.flatten!(1)
|
789
|
+
ensure_same_node(:zdiff, keys) do |node|
|
790
|
+
node.zdiff(keys, **options)
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
# Compute the difference between the first and all successive input sorted sets
|
795
|
+
# and store the resulting sorted set in a new key.
|
796
|
+
def zdiffstore(destination, *keys, **options)
|
797
|
+
keys.flatten!(1)
|
798
|
+
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
799
|
+
node.zdiffstore(destination, keys, **options)
|
640
800
|
end
|
641
801
|
end
|
642
802
|
|
@@ -645,9 +805,9 @@ class Redis
|
|
645
805
|
node_for(key).hlen(key)
|
646
806
|
end
|
647
807
|
|
648
|
-
# Set
|
649
|
-
def hset(key,
|
650
|
-
node_for(key).hset(key,
|
808
|
+
# Set multiple hash fields to multiple values.
|
809
|
+
def hset(key, *attrs)
|
810
|
+
node_for(key).hset(key, *attrs)
|
651
811
|
end
|
652
812
|
|
653
813
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -661,7 +821,7 @@ class Redis
|
|
661
821
|
end
|
662
822
|
|
663
823
|
def mapped_hmset(key, hash)
|
664
|
-
node_for(key).hmset(key,
|
824
|
+
node_for(key).hmset(key, hash)
|
665
825
|
end
|
666
826
|
|
667
827
|
# Get the value of a hash field.
|
@@ -671,16 +831,23 @@ class Redis
|
|
671
831
|
|
672
832
|
# Get the values of all the given hash fields.
|
673
833
|
def hmget(key, *fields)
|
674
|
-
|
834
|
+
fields.flatten!(1)
|
835
|
+
node_for(key).hmget(key, fields)
|
675
836
|
end
|
676
837
|
|
677
838
|
def mapped_hmget(key, *fields)
|
678
|
-
|
839
|
+
fields.flatten!(1)
|
840
|
+
node_for(key).mapped_hmget(key, fields)
|
841
|
+
end
|
842
|
+
|
843
|
+
def hrandfield(key, count = nil, **options)
|
844
|
+
node_for(key).hrandfield(key, count, **options)
|
679
845
|
end
|
680
846
|
|
681
847
|
# Delete one or more hash fields.
|
682
|
-
def hdel(key,
|
683
|
-
|
848
|
+
def hdel(key, *fields)
|
849
|
+
fields.flatten!(1)
|
850
|
+
node_for(key).hdel(key, fields)
|
684
851
|
end
|
685
852
|
|
686
853
|
# Determine if a hash field exists.
|
@@ -719,7 +886,7 @@ class Redis
|
|
719
886
|
end
|
720
887
|
|
721
888
|
def subscribed?
|
722
|
-
|
889
|
+
!!@subscribed_node
|
723
890
|
end
|
724
891
|
|
725
892
|
# Listen for messages published to the given channels.
|
@@ -737,7 +904,8 @@ class Redis
|
|
737
904
|
|
738
905
|
# Stop listening for messages posted to the given channels.
|
739
906
|
def unsubscribe(*channels)
|
740
|
-
raise
|
907
|
+
raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
|
908
|
+
|
741
909
|
@subscribed_node.unsubscribe(*channels)
|
742
910
|
end
|
743
911
|
|
@@ -753,13 +921,26 @@ class Redis
|
|
753
921
|
end
|
754
922
|
|
755
923
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
756
|
-
def watch(*keys)
|
757
|
-
|
924
|
+
def watch(*keys, &block)
|
925
|
+
ensure_same_node(:watch, keys) do |node|
|
926
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
927
|
+
|
928
|
+
begin
|
929
|
+
node.watch(*keys, &block)
|
930
|
+
rescue StandardError
|
931
|
+
@watch_key = nil
|
932
|
+
raise
|
933
|
+
end
|
934
|
+
end
|
758
935
|
end
|
759
936
|
|
760
937
|
# Forget about all watched keys.
|
761
938
|
def unwatch
|
762
|
-
raise CannotDistribute, :unwatch
|
939
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
940
|
+
|
941
|
+
result = node_for(@watch_key).unwatch
|
942
|
+
@watch_key = nil
|
943
|
+
result
|
763
944
|
end
|
764
945
|
|
765
946
|
def pipelined
|
@@ -767,18 +948,28 @@ class Redis
|
|
767
948
|
end
|
768
949
|
|
769
950
|
# Mark the start of a transaction block.
|
770
|
-
def multi
|
771
|
-
raise CannotDistribute, :multi
|
951
|
+
def multi(&block)
|
952
|
+
raise CannotDistribute, :multi unless @watch_key
|
953
|
+
|
954
|
+
node_for(@watch_key).multi(&block)
|
772
955
|
end
|
773
956
|
|
774
957
|
# Execute all commands issued after MULTI.
|
775
958
|
def exec
|
776
|
-
raise CannotDistribute, :exec
|
959
|
+
raise CannotDistribute, :exec unless @watch_key
|
960
|
+
|
961
|
+
result = node_for(@watch_key).exec
|
962
|
+
@watch_key = nil
|
963
|
+
result
|
777
964
|
end
|
778
965
|
|
779
966
|
# Discard all commands issued after MULTI.
|
780
967
|
def discard
|
781
|
-
raise CannotDistribute, :discard
|
968
|
+
raise CannotDistribute, :discard unless @watch_key
|
969
|
+
|
970
|
+
result = node_for(@watch_key).discard
|
971
|
+
@watch_key = nil
|
972
|
+
result
|
782
973
|
end
|
783
974
|
|
784
975
|
# Control remote script registry.
|
@@ -837,7 +1028,7 @@ class Redis
|
|
837
1028
|
self.class.new(@node_configs, @default_options)
|
838
1029
|
end
|
839
1030
|
|
840
|
-
|
1031
|
+
protected
|
841
1032
|
|
842
1033
|
def on_each_node(command, *args)
|
843
1034
|
nodes.map do |node|
|
@@ -850,7 +1041,8 @@ class Redis
|
|
850
1041
|
end
|
851
1042
|
|
852
1043
|
def key_tag(key)
|
853
|
-
key.to_s
|
1044
|
+
key = key.to_s
|
1045
|
+
key[@tag, 1] if key.match?(@tag)
|
854
1046
|
end
|
855
1047
|
|
856
1048
|
def ensure_same_node(command, keys)
|