redis 3.3.5 → 5.0.7
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 +290 -2
- data/README.md +146 -146
- data/lib/redis/client.rb +79 -541
- 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 +339 -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 +884 -0
- data/lib/redis/commands/streams.rb +402 -0
- data/lib/redis/commands/strings.rb +314 -0
- data/lib/redis/commands/transactions.rb +115 -0
- data/lib/redis/commands.rb +237 -0
- data/lib/redis/distributed.rb +328 -108
- data/lib/redis/errors.rb +23 -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 +115 -2695
- metadata +38 -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/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
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
|
401
|
-
end
|
402
|
-
|
403
|
-
if args.size > 1
|
404
|
-
# Issue deprecation notice in obnoxious mode...
|
469
|
+
options[:timeout]
|
405
470
|
end
|
406
471
|
|
407
|
-
|
472
|
+
args.flatten!(1)
|
408
473
|
|
409
|
-
ensure_same_node(cmd,
|
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
|
|
@@ -467,19 +542,43 @@ class Redis
|
|
467
542
|
node_for(key).ltrim(key, start, stop)
|
468
543
|
end
|
469
544
|
|
545
|
+
# Iterate over keys, blocking and removing elements from the first non empty liist found.
|
546
|
+
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
|
547
|
+
ensure_same_node(:blmpop, keys) do |node|
|
548
|
+
node.blmpop(timeout, *keys, modifier: modifier, count: count)
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
# Iterate over keys, removing elements from the first non list found.
|
553
|
+
def lmpop(*keys, modifier: "LEFT", count: nil)
|
554
|
+
ensure_same_node(:lmpop, keys) do |node|
|
555
|
+
node.lmpop(*keys, modifier: modifier, count: count)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
470
559
|
# Get the number of members in a set.
|
471
560
|
def scard(key)
|
472
561
|
node_for(key).scard(key)
|
473
562
|
end
|
474
563
|
|
475
564
|
# Add one or more members to a set.
|
476
|
-
def sadd(key,
|
477
|
-
node_for(key).sadd(key,
|
565
|
+
def sadd(key, *members)
|
566
|
+
node_for(key).sadd(key, *members)
|
567
|
+
end
|
568
|
+
|
569
|
+
# Add one or more members to a set.
|
570
|
+
def sadd?(key, *members)
|
571
|
+
node_for(key).sadd?(key, *members)
|
572
|
+
end
|
573
|
+
|
574
|
+
# Remove one or more members from a set.
|
575
|
+
def srem(key, *members)
|
576
|
+
node_for(key).srem(key, *members)
|
478
577
|
end
|
479
578
|
|
480
579
|
# Remove one or more members from a set.
|
481
|
-
def srem(key,
|
482
|
-
node_for(key).srem(key,
|
580
|
+
def srem?(key, *members)
|
581
|
+
node_for(key).srem?(key, *members)
|
483
582
|
end
|
484
583
|
|
485
584
|
# Remove and return a random member from a set.
|
@@ -504,50 +603,71 @@ class Redis
|
|
504
603
|
node_for(key).sismember(key, member)
|
505
604
|
end
|
506
605
|
|
606
|
+
# Determine if multiple values are members of a set.
|
607
|
+
def smismember(key, *members)
|
608
|
+
node_for(key).smismember(key, *members)
|
609
|
+
end
|
610
|
+
|
507
611
|
# Get all the members in a set.
|
508
612
|
def smembers(key)
|
509
613
|
node_for(key).smembers(key)
|
510
614
|
end
|
511
615
|
|
616
|
+
# Scan a set
|
617
|
+
def sscan(key, cursor, **options)
|
618
|
+
node_for(key).sscan(key, cursor, **options)
|
619
|
+
end
|
620
|
+
|
621
|
+
# Scan a set and return an enumerator
|
622
|
+
def sscan_each(key, **options, &block)
|
623
|
+
node_for(key).sscan_each(key, **options, &block)
|
624
|
+
end
|
625
|
+
|
512
626
|
# Subtract multiple sets.
|
513
627
|
def sdiff(*keys)
|
628
|
+
keys.flatten!(1)
|
514
629
|
ensure_same_node(:sdiff, keys) do |node|
|
515
|
-
node.sdiff(
|
630
|
+
node.sdiff(keys)
|
516
631
|
end
|
517
632
|
end
|
518
633
|
|
519
634
|
# Subtract multiple sets and store the resulting set in a key.
|
520
635
|
def sdiffstore(destination, *keys)
|
521
|
-
|
522
|
-
|
636
|
+
keys.flatten!(1)
|
637
|
+
ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
|
638
|
+
node.sdiffstore(destination, keys)
|
523
639
|
end
|
524
640
|
end
|
525
641
|
|
526
642
|
# Intersect multiple sets.
|
527
643
|
def sinter(*keys)
|
644
|
+
keys.flatten!(1)
|
528
645
|
ensure_same_node(:sinter, keys) do |node|
|
529
|
-
node.sinter(
|
646
|
+
node.sinter(keys)
|
530
647
|
end
|
531
648
|
end
|
532
649
|
|
533
650
|
# Intersect multiple sets and store the resulting set in a key.
|
534
651
|
def sinterstore(destination, *keys)
|
535
|
-
|
536
|
-
|
652
|
+
keys.flatten!(1)
|
653
|
+
ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
|
654
|
+
node.sinterstore(destination, keys)
|
537
655
|
end
|
538
656
|
end
|
539
657
|
|
540
658
|
# Add multiple sets.
|
541
659
|
def sunion(*keys)
|
660
|
+
keys.flatten!(1)
|
542
661
|
ensure_same_node(:sunion, keys) do |node|
|
543
|
-
node.sunion(
|
662
|
+
node.sunion(keys)
|
544
663
|
end
|
545
664
|
end
|
546
665
|
|
547
666
|
# Add multiple sets and store the resulting set in a key.
|
548
667
|
def sunionstore(destination, *keys)
|
549
|
-
|
550
|
-
|
668
|
+
keys.flatten!(1)
|
669
|
+
ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
|
670
|
+
node.sunionstore(destination, keys)
|
551
671
|
end
|
552
672
|
end
|
553
673
|
|
@@ -561,6 +681,7 @@ class Redis
|
|
561
681
|
def zadd(key, *args)
|
562
682
|
node_for(key).zadd(key, *args)
|
563
683
|
end
|
684
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
564
685
|
|
565
686
|
# Increment the score of a member in a sorted set.
|
566
687
|
def zincrby(key, increment, member)
|
@@ -577,15 +698,47 @@ class Redis
|
|
577
698
|
node_for(key).zscore(key, member)
|
578
699
|
end
|
579
700
|
|
580
|
-
#
|
581
|
-
def
|
582
|
-
node_for(key).
|
701
|
+
# Get one or more random members from a sorted set.
|
702
|
+
def zrandmember(key, count = nil, **options)
|
703
|
+
node_for(key).zrandmember(key, count, **options)
|
704
|
+
end
|
705
|
+
|
706
|
+
# Get the scores associated with the given members in a sorted set.
|
707
|
+
def zmscore(key, *members)
|
708
|
+
node_for(key).zmscore(key, *members)
|
709
|
+
end
|
710
|
+
|
711
|
+
# Iterate over keys, blocking and removing members from the first non empty sorted set found.
|
712
|
+
def bzmpop(timeout, *keys, modifier: "MIN", count: nil)
|
713
|
+
ensure_same_node(:bzmpop, keys) do |node|
|
714
|
+
node.bzmpop(timeout, *keys, modifier: modifier, count: count)
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
# Iterate over keys, removing members from the first non empty sorted set found.
|
719
|
+
def zmpop(*keys, modifier: "MIN", count: nil)
|
720
|
+
ensure_same_node(:zmpop, keys) do |node|
|
721
|
+
node.zmpop(*keys, modifier: modifier, count: count)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
726
|
+
def zrange(key, start, stop, **options)
|
727
|
+
node_for(key).zrange(key, start, stop, **options)
|
728
|
+
end
|
729
|
+
|
730
|
+
# Select a range of members in a sorted set, by index, score or lexicographical ordering
|
731
|
+
# and store the resulting sorted set in a new key.
|
732
|
+
def zrangestore(dest_key, src_key, start, stop, **options)
|
733
|
+
ensure_same_node(:zrangestore, [dest_key, src_key]) do |node|
|
734
|
+
node.zrangestore(dest_key, src_key, start, stop, **options)
|
735
|
+
end
|
583
736
|
end
|
584
737
|
|
585
738
|
# Return a range of members in a sorted set, by index, with scores ordered
|
586
739
|
# from high to low.
|
587
|
-
def zrevrange(key, start, stop, options
|
588
|
-
node_for(key).zrevrange(key, start, stop, options)
|
740
|
+
def zrevrange(key, start, stop, **options)
|
741
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
589
742
|
end
|
590
743
|
|
591
744
|
# Determine the index of a member in a sorted set.
|
@@ -605,14 +758,14 @@ class Redis
|
|
605
758
|
end
|
606
759
|
|
607
760
|
# 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)
|
761
|
+
def zrangebyscore(key, min, max, **options)
|
762
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
610
763
|
end
|
611
764
|
|
612
765
|
# Return a range of members in a sorted set, by score, with scores ordered
|
613
766
|
# from high to low.
|
614
|
-
def zrevrangebyscore(key, max, min, options
|
615
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
767
|
+
def zrevrangebyscore(key, max, min, **options)
|
768
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
616
769
|
end
|
617
770
|
|
618
771
|
# Remove all members in a sorted set within the given scores.
|
@@ -625,18 +778,53 @@ class Redis
|
|
625
778
|
node_for(key).zcount(key, min, max)
|
626
779
|
end
|
627
780
|
|
781
|
+
# Get the intersection of multiple sorted sets
|
782
|
+
def zinter(*keys, **options)
|
783
|
+
keys.flatten!(1)
|
784
|
+
ensure_same_node(:zinter, keys) do |node|
|
785
|
+
node.zinter(keys, **options)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
628
789
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
629
790
|
# key.
|
630
|
-
def zinterstore(destination, keys, options
|
631
|
-
|
632
|
-
|
791
|
+
def zinterstore(destination, *keys, **options)
|
792
|
+
keys.flatten!(1)
|
793
|
+
ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
|
794
|
+
node.zinterstore(destination, keys, **options)
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
# Return the union of multiple sorted sets.
|
799
|
+
def zunion(*keys, **options)
|
800
|
+
keys.flatten!(1)
|
801
|
+
ensure_same_node(:zunion, keys) do |node|
|
802
|
+
node.zunion(keys, **options)
|
633
803
|
end
|
634
804
|
end
|
635
805
|
|
636
806
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
637
|
-
def zunionstore(destination, keys, options
|
638
|
-
|
639
|
-
|
807
|
+
def zunionstore(destination, *keys, **options)
|
808
|
+
keys.flatten!(1)
|
809
|
+
ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
|
810
|
+
node.zunionstore(destination, keys, **options)
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
# Return the difference between the first and all successive input sorted sets.
|
815
|
+
def zdiff(*keys, **options)
|
816
|
+
keys.flatten!(1)
|
817
|
+
ensure_same_node(:zdiff, keys) do |node|
|
818
|
+
node.zdiff(keys, **options)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
# Compute the difference between the first and all successive input sorted sets
|
823
|
+
# and store the resulting sorted set in a new key.
|
824
|
+
def zdiffstore(destination, *keys, **options)
|
825
|
+
keys.flatten!(1)
|
826
|
+
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
827
|
+
node.zdiffstore(destination, keys, **options)
|
640
828
|
end
|
641
829
|
end
|
642
830
|
|
@@ -645,9 +833,9 @@ class Redis
|
|
645
833
|
node_for(key).hlen(key)
|
646
834
|
end
|
647
835
|
|
648
|
-
# Set
|
649
|
-
def hset(key,
|
650
|
-
node_for(key).hset(key,
|
836
|
+
# Set multiple hash fields to multiple values.
|
837
|
+
def hset(key, *attrs)
|
838
|
+
node_for(key).hset(key, *attrs)
|
651
839
|
end
|
652
840
|
|
653
841
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -661,7 +849,7 @@ class Redis
|
|
661
849
|
end
|
662
850
|
|
663
851
|
def mapped_hmset(key, hash)
|
664
|
-
node_for(key).hmset(key,
|
852
|
+
node_for(key).hmset(key, hash)
|
665
853
|
end
|
666
854
|
|
667
855
|
# Get the value of a hash field.
|
@@ -671,16 +859,23 @@ class Redis
|
|
671
859
|
|
672
860
|
# Get the values of all the given hash fields.
|
673
861
|
def hmget(key, *fields)
|
674
|
-
|
862
|
+
fields.flatten!(1)
|
863
|
+
node_for(key).hmget(key, fields)
|
675
864
|
end
|
676
865
|
|
677
866
|
def mapped_hmget(key, *fields)
|
678
|
-
|
867
|
+
fields.flatten!(1)
|
868
|
+
node_for(key).mapped_hmget(key, fields)
|
869
|
+
end
|
870
|
+
|
871
|
+
def hrandfield(key, count = nil, **options)
|
872
|
+
node_for(key).hrandfield(key, count, **options)
|
679
873
|
end
|
680
874
|
|
681
875
|
# Delete one or more hash fields.
|
682
|
-
def hdel(key,
|
683
|
-
|
876
|
+
def hdel(key, *fields)
|
877
|
+
fields.flatten!(1)
|
878
|
+
node_for(key).hdel(key, fields)
|
684
879
|
end
|
685
880
|
|
686
881
|
# Determine if a hash field exists.
|
@@ -719,7 +914,7 @@ class Redis
|
|
719
914
|
end
|
720
915
|
|
721
916
|
def subscribed?
|
722
|
-
|
917
|
+
!!@subscribed_node
|
723
918
|
end
|
724
919
|
|
725
920
|
# Listen for messages published to the given channels.
|
@@ -737,7 +932,8 @@ class Redis
|
|
737
932
|
|
738
933
|
# Stop listening for messages posted to the given channels.
|
739
934
|
def unsubscribe(*channels)
|
740
|
-
raise
|
935
|
+
raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
|
936
|
+
|
741
937
|
@subscribed_node.unsubscribe(*channels)
|
742
938
|
end
|
743
939
|
|
@@ -753,13 +949,26 @@ class Redis
|
|
753
949
|
end
|
754
950
|
|
755
951
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
756
|
-
def watch(*keys)
|
757
|
-
|
952
|
+
def watch(*keys, &block)
|
953
|
+
ensure_same_node(:watch, keys) do |node|
|
954
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
955
|
+
|
956
|
+
begin
|
957
|
+
node.watch(*keys, &block)
|
958
|
+
rescue StandardError
|
959
|
+
@watch_key = nil
|
960
|
+
raise
|
961
|
+
end
|
962
|
+
end
|
758
963
|
end
|
759
964
|
|
760
965
|
# Forget about all watched keys.
|
761
966
|
def unwatch
|
762
|
-
raise CannotDistribute, :unwatch
|
967
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
968
|
+
|
969
|
+
result = node_for(@watch_key).unwatch
|
970
|
+
@watch_key = nil
|
971
|
+
result
|
763
972
|
end
|
764
973
|
|
765
974
|
def pipelined
|
@@ -767,18 +976,28 @@ class Redis
|
|
767
976
|
end
|
768
977
|
|
769
978
|
# Mark the start of a transaction block.
|
770
|
-
def multi
|
771
|
-
raise CannotDistribute, :multi
|
979
|
+
def multi(&block)
|
980
|
+
raise CannotDistribute, :multi unless @watch_key
|
981
|
+
|
982
|
+
node_for(@watch_key).multi(&block)
|
772
983
|
end
|
773
984
|
|
774
985
|
# Execute all commands issued after MULTI.
|
775
986
|
def exec
|
776
|
-
raise CannotDistribute, :exec
|
987
|
+
raise CannotDistribute, :exec unless @watch_key
|
988
|
+
|
989
|
+
result = node_for(@watch_key).exec
|
990
|
+
@watch_key = nil
|
991
|
+
result
|
777
992
|
end
|
778
993
|
|
779
994
|
# Discard all commands issued after MULTI.
|
780
995
|
def discard
|
781
|
-
raise CannotDistribute, :discard
|
996
|
+
raise CannotDistribute, :discard unless @watch_key
|
997
|
+
|
998
|
+
result = node_for(@watch_key).discard
|
999
|
+
@watch_key = nil
|
1000
|
+
result
|
782
1001
|
end
|
783
1002
|
|
784
1003
|
# Control remote script registry.
|
@@ -837,7 +1056,7 @@ class Redis
|
|
837
1056
|
self.class.new(@node_configs, @default_options)
|
838
1057
|
end
|
839
1058
|
|
840
|
-
|
1059
|
+
protected
|
841
1060
|
|
842
1061
|
def on_each_node(command, *args)
|
843
1062
|
nodes.map do |node|
|
@@ -850,7 +1069,8 @@ class Redis
|
|
850
1069
|
end
|
851
1070
|
|
852
1071
|
def key_tag(key)
|
853
|
-
key.to_s
|
1072
|
+
key = key.to_s
|
1073
|
+
key[@tag, 1] if key.match?(@tag)
|
854
1074
|
end
|
855
1075
|
|
856
1076
|
def ensure_same_node(command, keys)
|