redis 4.1.4 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -0
- data/README.md +27 -17
- data/lib/redis.rb +405 -260
- data/lib/redis/client.rb +94 -74
- data/lib/redis/cluster.rb +13 -13
- data/lib/redis/cluster/node.rb +5 -1
- data/lib/redis/cluster/option.rb +9 -3
- data/lib/redis/cluster/slot.rb +28 -14
- data/lib/redis/cluster/slot_loader.rb +2 -3
- data/lib/redis/connection.rb +1 -0
- data/lib/redis/connection/command_helper.rb +2 -2
- data/lib/redis/connection/hiredis.rb +3 -3
- data/lib/redis/connection/registry.rb +1 -1
- data/lib/redis/connection/ruby.rb +89 -107
- data/lib/redis/connection/synchrony.rb +8 -4
- data/lib/redis/distributed.rb +121 -63
- data/lib/redis/errors.rb +1 -0
- data/lib/redis/hash_ring.rb +14 -14
- data/lib/redis/pipeline.rb +6 -8
- data/lib/redis/subscribe.rb +10 -12
- data/lib/redis/version.rb +2 -1
- metadata +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5ff2ee4b6a6f2b087ac26bf96a3c1769cf42f70ea90008361157f7ef04cdb14
|
4
|
+
data.tar.gz: f2c24654294c4fa81a5cff4ddb545bc59e6f85b64ee61273278cb1e286a4edb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d88c6621659a178dca04d3ca62f25520f5f1a846b6300f93fb008966551fb4795a3e6c37810f99ea18f77a6292b955fa180ae3e06f8c90df7e6a3ca27087ae1
|
7
|
+
data.tar.gz: 1427cc268e867872388f214184d23a5c6062104fcb9d1e50d6026dd9daf6e51b9833866fee9fcf80c7a64e4de705295de8399d8e8ac22fa890bf358bd63ff707
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,60 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.4.0
|
4
|
+
|
5
|
+
* Redis cluster: fix cross-slot validation in pipelines. Fix ##1019.
|
6
|
+
* Add support for `XAUTOCLAIM`. See #1018.
|
7
|
+
* Properly issue `READONLY` when reconnecting to replicas. Fix #1017.
|
8
|
+
* Make `del` a noop if passed an empty list of keys. See #998.
|
9
|
+
* Add support for `ZINTER`. See #995.
|
10
|
+
|
11
|
+
# 4.3.1
|
12
|
+
|
13
|
+
* Fix password authentication against redis server 5 and older.
|
14
|
+
|
15
|
+
# 4.3.0
|
16
|
+
|
17
|
+
* Add the TYPE argument to scan and scan_each. See #985.
|
18
|
+
* Support AUTH command for ACL. See #967.
|
19
|
+
|
20
|
+
# 4.2.5
|
21
|
+
|
22
|
+
* Optimize the ruby connector write buffering. See #964.
|
23
|
+
|
24
|
+
# 4.2.4
|
25
|
+
|
26
|
+
* Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
|
27
|
+
|
28
|
+
# 4.2.3
|
29
|
+
|
30
|
+
* Use io/wait instead of IO.select in the ruby connector. See #960.
|
31
|
+
* Use exception free non blocking IOs in the ruby connector. See #926.
|
32
|
+
* Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
|
33
|
+
|
34
|
+
# 4.2.2
|
35
|
+
|
36
|
+
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
37
|
+
* Fix handling of empty stream responses. See #905, #929.
|
38
|
+
|
39
|
+
# 4.2.1
|
40
|
+
|
41
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
42
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
43
|
+
|
44
|
+
# 4.2.0
|
45
|
+
|
46
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
47
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
48
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
49
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
50
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
51
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
52
|
+
* Support `keepttl` ooption in `set`. See #913.
|
53
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
54
|
+
* Accept sentinel options even with string key. See #599.
|
55
|
+
* Verify TLS connections by default. See #900.
|
56
|
+
* Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
|
57
|
+
|
3
58
|
# 4.1.4
|
4
59
|
|
5
60
|
* Alias `Redis#disconnect` as `#close`. See #901.
|
@@ -9,6 +64,7 @@
|
|
9
64
|
* Increase buffer size in the ruby connector. See #880.
|
10
65
|
* Fix thread safety of `Redis.queue`. See #878.
|
11
66
|
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
67
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
12
68
|
|
13
69
|
# 4.1.3
|
14
70
|
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
# redis-rb [![Build Status][
|
1
|
+
# redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
|
2
2
|
|
3
3
|
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
|
4
4
|
providing an idiomatic interface.
|
5
5
|
|
6
|
+
See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
|
6
7
|
|
7
8
|
## Getting started
|
8
9
|
|
@@ -34,6 +35,9 @@ You can also specify connection options as a [`redis://` URL][redis-url]:
|
|
34
35
|
redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
35
36
|
```
|
36
37
|
|
38
|
+
The client expects passwords with special chracters to be URL-encoded (i.e.
|
39
|
+
`CGI.escape(password)`).
|
40
|
+
|
37
41
|
By default, the client will try to read the `REDIS_URL` environment variable
|
38
42
|
and use that as URL to connect to. The above statement is therefore equivalent
|
39
43
|
to setting this environment variable and calling `Redis.new` without arguments.
|
@@ -50,6 +54,12 @@ To connect to a password protected Redis instance, use:
|
|
50
54
|
redis = Redis.new(password: "mysecret")
|
51
55
|
```
|
52
56
|
|
57
|
+
To connect a Redis instance using [ACL](https://redis.io/topics/acl), use:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
redis = Redis.new(username: 'myname', password: 'mysecret')
|
61
|
+
```
|
62
|
+
|
53
63
|
The Redis class exports methods that are named identical to the commands
|
54
64
|
they execute. The arguments these methods accept are often identical to
|
55
65
|
the arguments specified on the [Redis website][redis-commands]. For
|
@@ -147,8 +157,8 @@ redis.mget('{key}1', '{key}2')
|
|
147
157
|
|
148
158
|
## Storing objects
|
149
159
|
|
150
|
-
Redis
|
151
|
-
|
160
|
+
Redis "string" types can be used to store serialized Ruby objects, for
|
161
|
+
example with JSON:
|
152
162
|
|
153
163
|
```ruby
|
154
164
|
require "json"
|
@@ -261,6 +271,7 @@ All timeout values are specified in seconds.
|
|
261
271
|
When using pub/sub, you can subscribe to a channel using a timeout as well:
|
262
272
|
|
263
273
|
```ruby
|
274
|
+
redis = Redis.new(reconnect_attempts: 0)
|
264
275
|
redis.subscribe_with_timeout(5, "news") do |on|
|
265
276
|
on.message do |channel, message|
|
266
277
|
# ...
|
@@ -322,7 +333,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
322
333
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
323
334
|
or [ghostunnel].
|
324
335
|
|
325
|
-
To enable SSL support, pass the `:ssl =>
|
336
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
326
337
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
327
338
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
328
339
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -435,7 +446,7 @@ redis = Redis.new(:driver => :synchrony)
|
|
435
446
|
## Testing
|
436
447
|
|
437
448
|
This library is tested against recent Ruby and Redis versions.
|
438
|
-
Check [
|
449
|
+
Check [Github Actions][gh-actions-link] for the exact versions supported.
|
439
450
|
|
440
451
|
## See Also
|
441
452
|
|
@@ -451,15 +462,14 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
451
462
|
## Contributing
|
452
463
|
|
453
464
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
454
|
-
requests.
|
455
|
-
|
456
|
-
|
457
|
-
[inchpages-image]:
|
458
|
-
[inchpages-link]:
|
459
|
-
[redis-commands]:
|
460
|
-
[redis-home]:
|
461
|
-
[redis-url]:
|
462
|
-
[
|
463
|
-
[
|
464
|
-
[
|
465
|
-
[rubydoc]: http://www.rubydoc.info/gems/redis
|
465
|
+
requests.
|
466
|
+
|
467
|
+
|
468
|
+
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
469
|
+
[inchpages-link]: https://inch-ci.org/github/redis/redis-rb
|
470
|
+
[redis-commands]: https://redis.io/commands
|
471
|
+
[redis-home]: https://redis.io
|
472
|
+
[redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
|
473
|
+
[gh-actions-image]: https://github.com/redis/redis-rb/workflows/Test/badge.svg
|
474
|
+
[gh-actions-link]: https://github.com/redis/redis-rb/actions
|
475
|
+
[rubydoc]: http://www.rubydoc.info/gems/redis
|
data/lib/redis.rb
CHANGED
@@ -4,12 +4,26 @@ require "monitor"
|
|
4
4
|
require_relative "redis/errors"
|
5
5
|
|
6
6
|
class Redis
|
7
|
-
|
8
|
-
|
7
|
+
class << self
|
8
|
+
attr_reader :exists_returns_integer
|
9
|
+
|
10
|
+
def exists_returns_integer=(value)
|
11
|
+
unless value
|
12
|
+
message = "`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
|
13
|
+
"disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
|
14
|
+
"`exists?` instead."
|
15
|
+
|
16
|
+
::Kernel.warn(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
@exists_returns_integer = value
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_writer :current
|
9
23
|
end
|
10
24
|
|
11
|
-
def self.current
|
12
|
-
@current
|
25
|
+
def self.current
|
26
|
+
@current ||= Redis.new
|
13
27
|
end
|
14
28
|
|
15
29
|
include MonitorMixin
|
@@ -17,17 +31,22 @@ class Redis
|
|
17
31
|
# Create a new client instance
|
18
32
|
#
|
19
33
|
# @param [Hash] options
|
20
|
-
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
34
|
+
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
35
|
+
# `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
|
36
|
+
# connection: `unix://[path to Redis socket]`. This overrides all other options.
|
21
37
|
# @option options [String] :host ("127.0.0.1") server hostname
|
22
38
|
# @option options [Integer] :port (6379) server port
|
23
39
|
# @option options [String] :path path to server socket (overrides host and port)
|
24
40
|
# @option options [Float] :timeout (5.0) timeout in seconds
|
25
41
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
42
|
+
# @option options [String] :username Username to authenticate against server
|
26
43
|
# @option options [String] :password Password to authenticate against server
|
27
44
|
# @option options [Integer] :db (0) Database to select after initial connect
|
28
45
|
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
29
|
-
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
30
|
-
#
|
46
|
+
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
47
|
+
# `CLIENT SETNAME`
|
48
|
+
# @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
|
49
|
+
# based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
|
31
50
|
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
32
51
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
33
52
|
# @option options [Array] :sentinels List of sentinels to contact
|
@@ -52,7 +71,7 @@ class Redis
|
|
52
71
|
end
|
53
72
|
|
54
73
|
# Run code with the client reconnecting
|
55
|
-
def with_reconnect(val=true, &blk)
|
74
|
+
def with_reconnect(val = true, &blk)
|
56
75
|
synchronize do |client|
|
57
76
|
client.with_reconnect(val, &blk)
|
58
77
|
end
|
@@ -125,12 +144,13 @@ class Redis
|
|
125
144
|
|
126
145
|
# Authenticate to the server.
|
127
146
|
#
|
128
|
-
# @param [String]
|
129
|
-
#
|
147
|
+
# @param [Array<String>] args includes both username and password
|
148
|
+
# or only password
|
130
149
|
# @return [String] `OK`
|
131
|
-
|
150
|
+
# @see https://redis.io/commands/auth AUTH command
|
151
|
+
def auth(*args)
|
132
152
|
synchronize do |client|
|
133
|
-
client.call([:auth,
|
153
|
+
client.call([:auth, *args])
|
134
154
|
end
|
135
155
|
end
|
136
156
|
|
@@ -205,7 +225,7 @@ class Redis
|
|
205
225
|
def config(action, *args)
|
206
226
|
synchronize do |client|
|
207
227
|
client.call([:config, action] + args) do |reply|
|
208
|
-
if reply.
|
228
|
+
if reply.is_a?(Array) && action == :get
|
209
229
|
Hashify.call(reply)
|
210
230
|
else
|
211
231
|
reply
|
@@ -256,7 +276,7 @@ class Redis
|
|
256
276
|
def flushall(options = nil)
|
257
277
|
synchronize do |client|
|
258
278
|
if options && options[:async]
|
259
|
-
client.call([
|
279
|
+
client.call(%i[flushall async])
|
260
280
|
else
|
261
281
|
client.call([:flushall])
|
262
282
|
end
|
@@ -271,7 +291,7 @@ class Redis
|
|
271
291
|
def flushdb(options = nil)
|
272
292
|
synchronize do |client|
|
273
293
|
if options && options[:async]
|
274
|
-
client.call([
|
294
|
+
client.call(%i[flushdb async])
|
275
295
|
else
|
276
296
|
client.call([:flushdb])
|
277
297
|
end
|
@@ -285,7 +305,7 @@ class Redis
|
|
285
305
|
def info(cmd = nil)
|
286
306
|
synchronize do |client|
|
287
307
|
client.call([:info, cmd].compact) do |reply|
|
288
|
-
if reply.
|
308
|
+
if reply.is_a?(String)
|
289
309
|
reply = HashifyInfo.call(reply)
|
290
310
|
|
291
311
|
if cmd && cmd.to_s == "commandstats"
|
@@ -358,7 +378,7 @@ class Redis
|
|
358
378
|
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
359
379
|
# @param [Integer] length maximum number of entries to return
|
360
380
|
# @return [Array<String>, Integer, String] depends on subcommand
|
361
|
-
def slowlog(subcommand, length=nil)
|
381
|
+
def slowlog(subcommand, length = nil)
|
362
382
|
synchronize do |client|
|
363
383
|
args = [:slowlog, subcommand]
|
364
384
|
args << length if length
|
@@ -383,7 +403,7 @@ class Redis
|
|
383
403
|
def time
|
384
404
|
synchronize do |client|
|
385
405
|
client.call([:time]) do |reply|
|
386
|
-
reply
|
406
|
+
reply&.map(&:to_i)
|
387
407
|
end
|
388
408
|
end
|
389
409
|
end
|
@@ -496,9 +516,9 @@ class Redis
|
|
496
516
|
# - `:replace => Boolean`: if false, raises an error if key already exists
|
497
517
|
# @raise [Redis::CommandError]
|
498
518
|
# @return [String] `"OK"`
|
499
|
-
def restore(key, ttl, serialized_value,
|
519
|
+
def restore(key, ttl, serialized_value, replace: nil)
|
500
520
|
args = [:restore, key, ttl, serialized_value]
|
501
|
-
args << 'REPLACE' if
|
521
|
+
args << 'REPLACE' if replace
|
502
522
|
|
503
523
|
synchronize do |client|
|
504
524
|
client.call(args)
|
@@ -535,6 +555,9 @@ class Redis
|
|
535
555
|
# @param [String, Array<String>] keys
|
536
556
|
# @return [Integer] number of keys that were deleted
|
537
557
|
def del(*keys)
|
558
|
+
keys.flatten!(1)
|
559
|
+
return 0 if keys.empty?
|
560
|
+
|
538
561
|
synchronize do |client|
|
539
562
|
client.call([:del] + keys)
|
540
563
|
end
|
@@ -550,13 +573,43 @@ class Redis
|
|
550
573
|
end
|
551
574
|
end
|
552
575
|
|
553
|
-
# Determine
|
576
|
+
# Determine how many of the keys exists.
|
554
577
|
#
|
555
|
-
# @param [String]
|
578
|
+
# @param [String, Array<String>] keys
|
579
|
+
# @return [Integer]
|
580
|
+
def exists(*keys)
|
581
|
+
if !Redis.exists_returns_integer && keys.size == 1
|
582
|
+
if Redis.exists_returns_integer.nil?
|
583
|
+
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
|
584
|
+
"should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
|
585
|
+
"true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
|
586
|
+
"`Redis.exists_returns_integer = false`, but this option will be removed in 5.0. " \
|
587
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
588
|
+
|
589
|
+
::Kernel.warn(message)
|
590
|
+
end
|
591
|
+
|
592
|
+
exists?(*keys)
|
593
|
+
else
|
594
|
+
_exists(*keys)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
def _exists(*keys)
|
599
|
+
synchronize do |client|
|
600
|
+
client.call([:exists, *keys])
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
# Determine if any of the keys exists.
|
605
|
+
#
|
606
|
+
# @param [String, Array<String>] keys
|
556
607
|
# @return [Boolean]
|
557
|
-
def exists(
|
608
|
+
def exists?(*keys)
|
558
609
|
synchronize do |client|
|
559
|
-
client.call([:exists,
|
610
|
+
client.call([:exists, *keys]) do |value|
|
611
|
+
value > 0
|
612
|
+
end
|
560
613
|
end
|
561
614
|
end
|
562
615
|
|
@@ -567,7 +620,7 @@ class Redis
|
|
567
620
|
def keys(pattern = "*")
|
568
621
|
synchronize do |client|
|
569
622
|
client.call([:keys, pattern]) do |reply|
|
570
|
-
if reply.
|
623
|
+
if reply.is_a?(String)
|
571
624
|
reply.split(" ")
|
572
625
|
else
|
573
626
|
reply
|
@@ -663,30 +716,27 @@ class Redis
|
|
663
716
|
# elements where every element is an array with the result for every
|
664
717
|
# element specified in `:get`
|
665
718
|
# - when `:store` is specified, the number of elements in the stored result
|
666
|
-
def sort(key,
|
667
|
-
args = []
|
719
|
+
def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
|
720
|
+
args = [:sort, key]
|
721
|
+
args << "BY" << by if by
|
668
722
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
args.concat(["LIMIT"] + limit) if limit
|
723
|
+
if limit
|
724
|
+
args << "LIMIT"
|
725
|
+
args.concat(limit)
|
726
|
+
end
|
674
727
|
|
675
|
-
get = Array(
|
676
|
-
|
728
|
+
get = Array(get)
|
729
|
+
get.each do |item|
|
730
|
+
args << "GET" << item
|
731
|
+
end
|
677
732
|
|
678
|
-
order = options[:order]
|
679
733
|
args.concat(order.split(" ")) if order
|
680
|
-
|
681
|
-
store = options[:store]
|
682
|
-
args.concat(["STORE", store]) if store
|
734
|
+
args << "STORE" << store if store
|
683
735
|
|
684
736
|
synchronize do |client|
|
685
|
-
client.call(
|
737
|
+
client.call(args) do |reply|
|
686
738
|
if get.size > 1 && !store
|
687
|
-
if reply
|
688
|
-
reply.each_slice(get.size).to_a
|
689
|
-
end
|
739
|
+
reply.each_slice(get.size).to_a if reply
|
690
740
|
else
|
691
741
|
reply
|
692
742
|
end
|
@@ -786,27 +836,21 @@ class Redis
|
|
786
836
|
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
787
837
|
# - `:nx => true`: Only set the key if it does not already exist.
|
788
838
|
# - `:xx => true`: Only set the key if it already exist.
|
839
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
789
840
|
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
790
|
-
def set(key, value,
|
791
|
-
args = []
|
792
|
-
|
793
|
-
|
794
|
-
args
|
795
|
-
|
796
|
-
|
797
|
-
args.concat(["PX", px]) if px
|
798
|
-
|
799
|
-
nx = options[:nx]
|
800
|
-
args.concat(["NX"]) if nx
|
801
|
-
|
802
|
-
xx = options[:xx]
|
803
|
-
args.concat(["XX"]) if xx
|
841
|
+
def set(key, value, ex: nil, px: nil, nx: nil, xx: nil, keepttl: nil)
|
842
|
+
args = [:set, key, value.to_s]
|
843
|
+
args << "EX" << ex if ex
|
844
|
+
args << "PX" << px if px
|
845
|
+
args << "NX" if nx
|
846
|
+
args << "XX" if xx
|
847
|
+
args << "KEEPTTL" if keepttl
|
804
848
|
|
805
849
|
synchronize do |client|
|
806
850
|
if nx || xx
|
807
|
-
client.call(
|
851
|
+
client.call(args, &BoolifySet)
|
808
852
|
else
|
809
|
-
client.call(
|
853
|
+
client.call(args)
|
810
854
|
end
|
811
855
|
end
|
812
856
|
end
|
@@ -888,7 +932,7 @@ class Redis
|
|
888
932
|
# @see #mapped_msetnx
|
889
933
|
def msetnx(*args)
|
890
934
|
synchronize do |client|
|
891
|
-
client.call([:msetnx
|
935
|
+
client.call([:msetnx, *args], &Boolify)
|
892
936
|
end
|
893
937
|
end
|
894
938
|
|
@@ -928,7 +972,7 @@ class Redis
|
|
928
972
|
# @see #mapped_mget
|
929
973
|
def mget(*keys, &blk)
|
930
974
|
synchronize do |client|
|
931
|
-
client.call([:mget
|
975
|
+
client.call([:mget, *keys], &blk)
|
932
976
|
end
|
933
977
|
end
|
934
978
|
|
@@ -944,7 +988,7 @@ class Redis
|
|
944
988
|
# @see #mget
|
945
989
|
def mapped_mget(*keys)
|
946
990
|
mget(*keys) do |reply|
|
947
|
-
if reply.
|
991
|
+
if reply.is_a?(Array)
|
948
992
|
Hash[keys.zip(reply)]
|
949
993
|
else
|
950
994
|
reply
|
@@ -1031,7 +1075,7 @@ class Redis
|
|
1031
1075
|
# @return [Integer] the length of the string stored in `destkey`
|
1032
1076
|
def bitop(operation, destkey, *keys)
|
1033
1077
|
synchronize do |client|
|
1034
|
-
client.call([:bitop, operation, destkey
|
1078
|
+
client.call([:bitop, operation, destkey, *keys])
|
1035
1079
|
end
|
1036
1080
|
end
|
1037
1081
|
|
@@ -1043,10 +1087,8 @@ class Redis
|
|
1043
1087
|
# @param [Integer] stop stop index
|
1044
1088
|
# @return [Integer] the position of the first 1/0 bit.
|
1045
1089
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
1046
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
1047
|
-
|
1048
|
-
raise(ArgumentError, 'stop parameter specified without start parameter')
|
1049
|
-
end
|
1090
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
1091
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
1050
1092
|
|
1051
1093
|
synchronize do |client|
|
1052
1094
|
command = [:bitpos, key, bit]
|
@@ -1133,23 +1175,29 @@ class Redis
|
|
1133
1175
|
end
|
1134
1176
|
end
|
1135
1177
|
|
1136
|
-
# Remove and get the first
|
1178
|
+
# Remove and get the first elements in a list.
|
1137
1179
|
#
|
1138
1180
|
# @param [String] key
|
1139
|
-
# @
|
1140
|
-
|
1181
|
+
# @param [Integer] count number of elements to remove
|
1182
|
+
# @return [String, Array<String>] the values of the first elements
|
1183
|
+
def lpop(key, count = nil)
|
1141
1184
|
synchronize do |client|
|
1142
|
-
|
1185
|
+
command = [:lpop, key]
|
1186
|
+
command << count if count
|
1187
|
+
client.call(command)
|
1143
1188
|
end
|
1144
1189
|
end
|
1145
1190
|
|
1146
|
-
# Remove and get the last
|
1191
|
+
# Remove and get the last elements in a list.
|
1147
1192
|
#
|
1148
1193
|
# @param [String] key
|
1149
|
-
# @
|
1150
|
-
|
1194
|
+
# @param [Integer] count number of elements to remove
|
1195
|
+
# @return [String, Array<String>] the values of the last elements
|
1196
|
+
def rpop(key, count = nil)
|
1151
1197
|
synchronize do |client|
|
1152
|
-
|
1198
|
+
command = [:rpop, key]
|
1199
|
+
command << count if count
|
1200
|
+
client.call(command)
|
1153
1201
|
end
|
1154
1202
|
end
|
1155
1203
|
|
@@ -1240,15 +1288,7 @@ class Redis
|
|
1240
1288
|
# @return [nil, String]
|
1241
1289
|
# - `nil` when the operation timed out
|
1242
1290
|
# - the element was popped and pushed otherwise
|
1243
|
-
def brpoplpush(source, destination,
|
1244
|
-
case options
|
1245
|
-
when Integer
|
1246
|
-
# Issue deprecation notice in obnoxious mode...
|
1247
|
-
options = { :timeout => options }
|
1248
|
-
end
|
1249
|
-
|
1250
|
-
timeout = options[:timeout] || 0
|
1251
|
-
|
1291
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
|
1252
1292
|
synchronize do |client|
|
1253
1293
|
command = [:brpoplpush, source, destination, timeout]
|
1254
1294
|
timeout += client.timeout if timeout > 0
|
@@ -1455,7 +1495,7 @@ class Redis
|
|
1455
1495
|
# @return [Array<String>] members in the difference
|
1456
1496
|
def sdiff(*keys)
|
1457
1497
|
synchronize do |client|
|
1458
|
-
client.call([:sdiff
|
1498
|
+
client.call([:sdiff, *keys])
|
1459
1499
|
end
|
1460
1500
|
end
|
1461
1501
|
|
@@ -1466,7 +1506,7 @@ class Redis
|
|
1466
1506
|
# @return [Integer] number of elements in the resulting set
|
1467
1507
|
def sdiffstore(destination, *keys)
|
1468
1508
|
synchronize do |client|
|
1469
|
-
client.call([:sdiffstore, destination
|
1509
|
+
client.call([:sdiffstore, destination, *keys])
|
1470
1510
|
end
|
1471
1511
|
end
|
1472
1512
|
|
@@ -1476,7 +1516,7 @@ class Redis
|
|
1476
1516
|
# @return [Array<String>] members in the intersection
|
1477
1517
|
def sinter(*keys)
|
1478
1518
|
synchronize do |client|
|
1479
|
-
client.call([:sinter
|
1519
|
+
client.call([:sinter, *keys])
|
1480
1520
|
end
|
1481
1521
|
end
|
1482
1522
|
|
@@ -1487,7 +1527,7 @@ class Redis
|
|
1487
1527
|
# @return [Integer] number of elements in the resulting set
|
1488
1528
|
def sinterstore(destination, *keys)
|
1489
1529
|
synchronize do |client|
|
1490
|
-
client.call([:sinterstore, destination
|
1530
|
+
client.call([:sinterstore, destination, *keys])
|
1491
1531
|
end
|
1492
1532
|
end
|
1493
1533
|
|
@@ -1497,7 +1537,7 @@ class Redis
|
|
1497
1537
|
# @return [Array<String>] members in the union
|
1498
1538
|
def sunion(*keys)
|
1499
1539
|
synchronize do |client|
|
1500
|
-
client.call([:sunion
|
1540
|
+
client.call([:sunion, *keys])
|
1501
1541
|
end
|
1502
1542
|
end
|
1503
1543
|
|
@@ -1508,7 +1548,7 @@ class Redis
|
|
1508
1548
|
# @return [Integer] number of elements in the resulting set
|
1509
1549
|
def sunionstore(destination, *keys)
|
1510
1550
|
synchronize do |client|
|
1511
|
-
client.call([:sunionstore, destination
|
1551
|
+
client.call([:sunionstore, destination, *keys])
|
1512
1552
|
end
|
1513
1553
|
end
|
1514
1554
|
|
@@ -1557,31 +1597,20 @@ class Redis
|
|
1557
1597
|
# pairs that were **added** to the sorted set.
|
1558
1598
|
# - `Float` when option :incr is specified, holding the score of the member
|
1559
1599
|
# after incrementing it.
|
1560
|
-
def zadd(key, *args
|
1561
|
-
|
1562
|
-
if
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
zadd_options << "NX" if nx
|
1567
|
-
|
1568
|
-
xx = options[:xx]
|
1569
|
-
zadd_options << "XX" if xx
|
1570
|
-
|
1571
|
-
ch = options[:ch]
|
1572
|
-
zadd_options << "CH" if ch
|
1573
|
-
|
1574
|
-
incr = options[:incr]
|
1575
|
-
zadd_options << "INCR" if incr
|
1576
|
-
end
|
1600
|
+
def zadd(key, *args, nx: nil, xx: nil, ch: nil, incr: nil)
|
1601
|
+
command = [:zadd, key]
|
1602
|
+
command << "NX" if nx
|
1603
|
+
command << "XX" if xx
|
1604
|
+
command << "CH" if ch
|
1605
|
+
command << "INCR" if incr
|
1577
1606
|
|
1578
1607
|
synchronize do |client|
|
1579
1608
|
if args.size == 1 && args[0].is_a?(Array)
|
1580
1609
|
# Variadic: return float if INCR, integer if !INCR
|
1581
|
-
client.call(
|
1610
|
+
client.call(command + args[0], &(incr ? Floatify : nil))
|
1582
1611
|
elsif args.size == 2
|
1583
1612
|
# Single pair: return float if INCR, boolean if !INCR
|
1584
|
-
client.call(
|
1613
|
+
client.call(command + args, &(incr ? Floatify : Boolify))
|
1585
1614
|
else
|
1586
1615
|
raise ArgumentError, "wrong number of arguments"
|
1587
1616
|
end
|
@@ -1752,10 +1781,8 @@ class Redis
|
|
1752
1781
|
# @return [Array<String>, Array<[String, Float]>]
|
1753
1782
|
# - when `:with_scores` is not specified, an array of members
|
1754
1783
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1755
|
-
def zrange(key, start, stop,
|
1756
|
-
args = []
|
1757
|
-
|
1758
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1784
|
+
def zrange(key, start, stop, withscores: false, with_scores: withscores)
|
1785
|
+
args = [:zrange, key, start, stop]
|
1759
1786
|
|
1760
1787
|
if with_scores
|
1761
1788
|
args << "WITHSCORES"
|
@@ -1763,7 +1790,7 @@ class Redis
|
|
1763
1790
|
end
|
1764
1791
|
|
1765
1792
|
synchronize do |client|
|
1766
|
-
client.call(
|
1793
|
+
client.call(args, &block)
|
1767
1794
|
end
|
1768
1795
|
end
|
1769
1796
|
|
@@ -1778,10 +1805,8 @@ class Redis
|
|
1778
1805
|
# # => [["b", 64.0], ["a", 32.0]]
|
1779
1806
|
#
|
1780
1807
|
# @see #zrange
|
1781
|
-
def zrevrange(key, start, stop,
|
1782
|
-
args = []
|
1783
|
-
|
1784
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1808
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
1809
|
+
args = [:zrevrange, key, start, stop]
|
1785
1810
|
|
1786
1811
|
if with_scores
|
1787
1812
|
args << "WITHSCORES"
|
@@ -1789,7 +1814,7 @@ class Redis
|
|
1789
1814
|
end
|
1790
1815
|
|
1791
1816
|
synchronize do |client|
|
1792
|
-
client.call(
|
1817
|
+
client.call(args, &block)
|
1793
1818
|
end
|
1794
1819
|
end
|
1795
1820
|
|
@@ -1880,14 +1905,16 @@ class Redis
|
|
1880
1905
|
# `count` members
|
1881
1906
|
#
|
1882
1907
|
# @return [Array<String>, Array<[String, Float]>]
|
1883
|
-
def zrangebylex(key, min, max,
|
1884
|
-
args = []
|
1908
|
+
def zrangebylex(key, min, max, limit: nil)
|
1909
|
+
args = [:zrangebylex, key, min, max]
|
1885
1910
|
|
1886
|
-
|
1887
|
-
|
1911
|
+
if limit
|
1912
|
+
args << "LIMIT"
|
1913
|
+
args.concat(limit)
|
1914
|
+
end
|
1888
1915
|
|
1889
1916
|
synchronize do |client|
|
1890
|
-
client.call(
|
1917
|
+
client.call(args)
|
1891
1918
|
end
|
1892
1919
|
end
|
1893
1920
|
|
@@ -1902,14 +1929,16 @@ class Redis
|
|
1902
1929
|
# # => ["abbygail", "abby"]
|
1903
1930
|
#
|
1904
1931
|
# @see #zrangebylex
|
1905
|
-
def zrevrangebylex(key, max, min,
|
1906
|
-
args = []
|
1932
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
1933
|
+
args = [:zrevrangebylex, key, max, min]
|
1907
1934
|
|
1908
|
-
|
1909
|
-
|
1935
|
+
if limit
|
1936
|
+
args << "LIMIT"
|
1937
|
+
args.concat(limit)
|
1938
|
+
end
|
1910
1939
|
|
1911
1940
|
synchronize do |client|
|
1912
|
-
client.call(
|
1941
|
+
client.call(args)
|
1913
1942
|
end
|
1914
1943
|
end
|
1915
1944
|
|
@@ -1940,21 +1969,21 @@ class Redis
|
|
1940
1969
|
# @return [Array<String>, Array<[String, Float]>]
|
1941
1970
|
# - when `:with_scores` is not specified, an array of members
|
1942
1971
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1943
|
-
def zrangebyscore(key, min, max,
|
1944
|
-
args = []
|
1945
|
-
|
1946
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1972
|
+
def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
|
1973
|
+
args = [:zrangebyscore, key, min, max]
|
1947
1974
|
|
1948
1975
|
if with_scores
|
1949
1976
|
args << "WITHSCORES"
|
1950
1977
|
block = FloatifyPairs
|
1951
1978
|
end
|
1952
1979
|
|
1953
|
-
|
1954
|
-
|
1980
|
+
if limit
|
1981
|
+
args << "LIMIT"
|
1982
|
+
args.concat(limit)
|
1983
|
+
end
|
1955
1984
|
|
1956
1985
|
synchronize do |client|
|
1957
|
-
client.call(
|
1986
|
+
client.call(args, &block)
|
1958
1987
|
end
|
1959
1988
|
end
|
1960
1989
|
|
@@ -1972,21 +2001,21 @@ class Redis
|
|
1972
2001
|
# # => [["b", 64.0], ["a", 32.0]]
|
1973
2002
|
#
|
1974
2003
|
# @see #zrangebyscore
|
1975
|
-
def zrevrangebyscore(key, max, min,
|
1976
|
-
args = []
|
1977
|
-
|
1978
|
-
with_scores = options[:with_scores] || options[:withscores]
|
2004
|
+
def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
|
2005
|
+
args = [:zrevrangebyscore, key, max, min]
|
1979
2006
|
|
1980
2007
|
if with_scores
|
1981
|
-
args <<
|
2008
|
+
args << "WITHSCORES"
|
1982
2009
|
block = FloatifyPairs
|
1983
2010
|
end
|
1984
2011
|
|
1985
|
-
|
1986
|
-
|
2012
|
+
if limit
|
2013
|
+
args << "LIMIT"
|
2014
|
+
args.concat(limit)
|
2015
|
+
end
|
1987
2016
|
|
1988
2017
|
synchronize do |client|
|
1989
|
-
client.call(
|
2018
|
+
client.call(args, &block)
|
1990
2019
|
end
|
1991
2020
|
end
|
1992
2021
|
|
@@ -2036,6 +2065,45 @@ class Redis
|
|
2036
2065
|
end
|
2037
2066
|
end
|
2038
2067
|
|
2068
|
+
# Return the intersection of multiple sorted sets
|
2069
|
+
#
|
2070
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`
|
2071
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0])
|
2072
|
+
# # => ["v1", "v2"]
|
2073
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`, and their scores
|
2074
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0], :with_scores => true)
|
2075
|
+
# # => [["v1", 3.0], ["v2", 6.0]]
|
2076
|
+
#
|
2077
|
+
# @param [String, Array<String>] keys one or more keys to intersect
|
2078
|
+
# @param [Hash] options
|
2079
|
+
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2080
|
+
# sorted sets
|
2081
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2082
|
+
# - `:with_scores => true`: include scores in output
|
2083
|
+
#
|
2084
|
+
# @return [Array<String>, Array<[String, Float]>]
|
2085
|
+
# - when `:with_scores` is not specified, an array of members
|
2086
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
2087
|
+
def zinter(*keys, weights: nil, aggregate: nil, with_scores: false)
|
2088
|
+
args = [:zinter, keys.size, *keys]
|
2089
|
+
|
2090
|
+
if weights
|
2091
|
+
args << "WEIGHTS"
|
2092
|
+
args.concat(weights)
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2096
|
+
|
2097
|
+
if with_scores
|
2098
|
+
args << "WITHSCORES"
|
2099
|
+
block = FloatifyPairs
|
2100
|
+
end
|
2101
|
+
|
2102
|
+
synchronize do |client|
|
2103
|
+
client.call(args, &block)
|
2104
|
+
end
|
2105
|
+
end
|
2106
|
+
|
2039
2107
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
2040
2108
|
# key.
|
2041
2109
|
#
|
@@ -2050,17 +2118,18 @@ class Redis
|
|
2050
2118
|
# sorted sets
|
2051
2119
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2052
2120
|
# @return [Integer] number of elements in the resulting sorted set
|
2053
|
-
def zinterstore(destination, keys,
|
2054
|
-
args = []
|
2121
|
+
def zinterstore(destination, keys, weights: nil, aggregate: nil)
|
2122
|
+
args = [:zinterstore, destination, keys.size, *keys]
|
2055
2123
|
|
2056
|
-
|
2057
|
-
|
2124
|
+
if weights
|
2125
|
+
args << "WEIGHTS"
|
2126
|
+
args.concat(weights)
|
2127
|
+
end
|
2058
2128
|
|
2059
|
-
aggregate
|
2060
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2129
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2061
2130
|
|
2062
2131
|
synchronize do |client|
|
2063
|
-
client.call(
|
2132
|
+
client.call(args)
|
2064
2133
|
end
|
2065
2134
|
end
|
2066
2135
|
|
@@ -2077,17 +2146,18 @@ class Redis
|
|
2077
2146
|
# sorted sets
|
2078
2147
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2079
2148
|
# @return [Integer] number of elements in the resulting sorted set
|
2080
|
-
def zunionstore(destination, keys,
|
2081
|
-
args = []
|
2149
|
+
def zunionstore(destination, keys, weights: nil, aggregate: nil)
|
2150
|
+
args = [:zunionstore, destination, keys.size, *keys]
|
2082
2151
|
|
2083
|
-
|
2084
|
-
|
2152
|
+
if weights
|
2153
|
+
args << "WEIGHTS"
|
2154
|
+
args.concat(weights)
|
2155
|
+
end
|
2085
2156
|
|
2086
|
-
aggregate
|
2087
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2157
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2088
2158
|
|
2089
2159
|
synchronize do |client|
|
2090
|
-
client.call(
|
2160
|
+
client.call(args)
|
2091
2161
|
end
|
2092
2162
|
end
|
2093
2163
|
|
@@ -2101,15 +2171,20 @@ class Redis
|
|
2101
2171
|
end
|
2102
2172
|
end
|
2103
2173
|
|
2104
|
-
# Set
|
2174
|
+
# Set one or more hash values.
|
2175
|
+
#
|
2176
|
+
# @example
|
2177
|
+
# redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
|
2178
|
+
# redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
|
2105
2179
|
#
|
2106
2180
|
# @param [String] key
|
2107
|
-
# @param [String]
|
2108
|
-
# @
|
2109
|
-
|
2110
|
-
|
2181
|
+
# @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
|
2182
|
+
# @return [Integer] The number of fields that were added to the hash
|
2183
|
+
def hset(key, *attrs)
|
2184
|
+
attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
|
2185
|
+
|
2111
2186
|
synchronize do |client|
|
2112
|
-
client.call([:hset, key,
|
2187
|
+
client.call([:hset, key, *attrs])
|
2113
2188
|
end
|
2114
2189
|
end
|
2115
2190
|
|
@@ -2198,7 +2273,7 @@ class Redis
|
|
2198
2273
|
# @see #hmget
|
2199
2274
|
def mapped_hmget(key, *fields)
|
2200
2275
|
hmget(key, *fields) do |reply|
|
2201
|
-
if reply.
|
2276
|
+
if reply.is_a?(Array)
|
2202
2277
|
Hash[fields.zip(reply)]
|
2203
2278
|
else
|
2204
2279
|
reply
|
@@ -2291,20 +2366,21 @@ class Redis
|
|
2291
2366
|
|
2292
2367
|
def subscribed?
|
2293
2368
|
synchronize do |client|
|
2294
|
-
client.
|
2369
|
+
client.is_a? SubscribedClient
|
2295
2370
|
end
|
2296
2371
|
end
|
2297
2372
|
|
2298
2373
|
# Listen for messages published to the given channels.
|
2299
2374
|
def subscribe(*channels, &block)
|
2300
|
-
synchronize do |
|
2375
|
+
synchronize do |_client|
|
2301
2376
|
_subscription(:subscribe, 0, channels, block)
|
2302
2377
|
end
|
2303
2378
|
end
|
2304
2379
|
|
2305
|
-
# Listen for messages published to the given channels. Throw a timeout error
|
2380
|
+
# Listen for messages published to the given channels. Throw a timeout error
|
2381
|
+
# if there is no messages for a timeout period.
|
2306
2382
|
def subscribe_with_timeout(timeout, *channels, &block)
|
2307
|
-
synchronize do |
|
2383
|
+
synchronize do |_client|
|
2308
2384
|
_subscription(:subscribe_with_timeout, timeout, channels, block)
|
2309
2385
|
end
|
2310
2386
|
end
|
@@ -2312,21 +2388,23 @@ class Redis
|
|
2312
2388
|
# Stop listening for messages posted to the given channels.
|
2313
2389
|
def unsubscribe(*channels)
|
2314
2390
|
synchronize do |client|
|
2315
|
-
raise
|
2391
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2392
|
+
|
2316
2393
|
client.unsubscribe(*channels)
|
2317
2394
|
end
|
2318
2395
|
end
|
2319
2396
|
|
2320
2397
|
# Listen for messages published to channels matching the given patterns.
|
2321
2398
|
def psubscribe(*channels, &block)
|
2322
|
-
synchronize do |
|
2399
|
+
synchronize do |_client|
|
2323
2400
|
_subscription(:psubscribe, 0, channels, block)
|
2324
2401
|
end
|
2325
2402
|
end
|
2326
2403
|
|
2327
|
-
# Listen for messages published to channels matching the given patterns.
|
2404
|
+
# Listen for messages published to channels matching the given patterns.
|
2405
|
+
# Throw a timeout error if there is no messages for a timeout period.
|
2328
2406
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
2329
|
-
synchronize do |
|
2407
|
+
synchronize do |_client|
|
2330
2408
|
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
2331
2409
|
end
|
2332
2410
|
end
|
@@ -2334,7 +2412,8 @@ class Redis
|
|
2334
2412
|
# Stop listening for messages posted to channels matching the given patterns.
|
2335
2413
|
def punsubscribe(*channels)
|
2336
2414
|
synchronize do |client|
|
2337
|
-
raise
|
2415
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2416
|
+
|
2338
2417
|
client.punsubscribe(*channels)
|
2339
2418
|
end
|
2340
2419
|
end
|
@@ -2379,7 +2458,7 @@ class Redis
|
|
2379
2458
|
# @see #multi
|
2380
2459
|
def watch(*keys)
|
2381
2460
|
synchronize do |client|
|
2382
|
-
res = client.call([:watch
|
2461
|
+
res = client.call([:watch, *keys])
|
2383
2462
|
|
2384
2463
|
if block_given?
|
2385
2464
|
begin
|
@@ -2409,14 +2488,13 @@ class Redis
|
|
2409
2488
|
end
|
2410
2489
|
|
2411
2490
|
def pipelined
|
2412
|
-
synchronize do |
|
2491
|
+
synchronize do |prior_client|
|
2413
2492
|
begin
|
2414
|
-
|
2415
|
-
original, @client = @client, pipeline
|
2493
|
+
@client = Pipeline.new(prior_client)
|
2416
2494
|
yield(self)
|
2417
|
-
|
2495
|
+
prior_client.call_pipeline(@client)
|
2418
2496
|
ensure
|
2419
|
-
@client =
|
2497
|
+
@client = prior_client
|
2420
2498
|
end
|
2421
2499
|
end
|
2422
2500
|
end
|
@@ -2452,17 +2530,16 @@ class Redis
|
|
2452
2530
|
# @see #watch
|
2453
2531
|
# @see #unwatch
|
2454
2532
|
def multi
|
2455
|
-
synchronize do |
|
2533
|
+
synchronize do |prior_client|
|
2456
2534
|
if !block_given?
|
2457
|
-
|
2535
|
+
prior_client.call([:multi])
|
2458
2536
|
else
|
2459
2537
|
begin
|
2460
|
-
|
2461
|
-
original, @client = @client, pipeline
|
2538
|
+
@client = Pipeline::Multi.new(prior_client)
|
2462
2539
|
yield(self)
|
2463
|
-
|
2540
|
+
prior_client.call_pipeline(@client)
|
2464
2541
|
ensure
|
2465
|
-
@client =
|
2542
|
+
@client = prior_client
|
2466
2543
|
end
|
2467
2544
|
end
|
2468
2545
|
end
|
@@ -2609,18 +2686,13 @@ class Redis
|
|
2609
2686
|
_eval(:evalsha, args)
|
2610
2687
|
end
|
2611
2688
|
|
2612
|
-
def _scan(command, cursor, args,
|
2689
|
+
def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
|
2613
2690
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2614
2691
|
|
2615
2692
|
args << cursor
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
end
|
2620
|
-
|
2621
|
-
if count = options[:count]
|
2622
|
-
args.concat(["COUNT", count])
|
2623
|
-
end
|
2693
|
+
args << "MATCH" << match if match
|
2694
|
+
args << "COUNT" << count if count
|
2695
|
+
args << "TYPE" << type if type
|
2624
2696
|
|
2625
2697
|
synchronize do |client|
|
2626
2698
|
client.call([command] + args, &block)
|
@@ -2635,15 +2707,19 @@ class Redis
|
|
2635
2707
|
# @example Retrieve a batch of keys matching a pattern
|
2636
2708
|
# redis.scan(4, :match => "key:1?")
|
2637
2709
|
# # => ["92", ["key:13", "key:18"]]
|
2710
|
+
# @example Retrieve a batch of keys of a certain type
|
2711
|
+
# redis.scan(92, :type => "zset")
|
2712
|
+
# # => ["173", ["sortedset:14", "sortedset:78"]]
|
2638
2713
|
#
|
2639
2714
|
# @param [String, Integer] cursor the cursor of the iteration
|
2640
2715
|
# @param [Hash] options
|
2641
2716
|
# - `:match => String`: only return keys matching the pattern
|
2642
2717
|
# - `:count => Integer`: return count keys at most per iteration
|
2718
|
+
# - `:type => String`: return keys only of the given type
|
2643
2719
|
#
|
2644
2720
|
# @return [String, Array<String>] the next cursor and all found keys
|
2645
|
-
def scan(cursor, options
|
2646
|
-
_scan(:scan, cursor, [], options)
|
2721
|
+
def scan(cursor, **options)
|
2722
|
+
_scan(:scan, cursor, [], **options)
|
2647
2723
|
end
|
2648
2724
|
|
2649
2725
|
# Scan the keyspace
|
@@ -2655,17 +2731,23 @@ class Redis
|
|
2655
2731
|
# redis.scan_each(:match => "key:1?") {|key| puts key}
|
2656
2732
|
# # => key:13
|
2657
2733
|
# # => key:18
|
2734
|
+
# @example Execute block for each key of a type
|
2735
|
+
# redis.scan_each(:type => "hash") {|key| puts redis.type(key)}
|
2736
|
+
# # => "hash"
|
2737
|
+
# # => "hash"
|
2658
2738
|
#
|
2659
2739
|
# @param [Hash] options
|
2660
2740
|
# - `:match => String`: only return keys matching the pattern
|
2661
2741
|
# - `:count => Integer`: return count keys at most per iteration
|
2742
|
+
# - `:type => String`: return keys only of the given type
|
2662
2743
|
#
|
2663
2744
|
# @return [Enumerator] an enumerator for all found keys
|
2664
|
-
def scan_each(options
|
2665
|
-
return to_enum(:scan_each, options) unless block_given?
|
2745
|
+
def scan_each(**options, &block)
|
2746
|
+
return to_enum(:scan_each, **options) unless block_given?
|
2747
|
+
|
2666
2748
|
cursor = 0
|
2667
2749
|
loop do
|
2668
|
-
cursor, keys = scan(cursor, options)
|
2750
|
+
cursor, keys = scan(cursor, **options)
|
2669
2751
|
keys.each(&block)
|
2670
2752
|
break if cursor == "0"
|
2671
2753
|
end
|
@@ -2682,8 +2764,8 @@ class Redis
|
|
2682
2764
|
# - `:count => Integer`: return count keys at most per iteration
|
2683
2765
|
#
|
2684
2766
|
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
2685
|
-
def hscan(key, cursor, options
|
2686
|
-
_scan(:hscan, cursor, [key], options) do |reply|
|
2767
|
+
def hscan(key, cursor, **options)
|
2768
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2687
2769
|
[reply[0], reply[1].each_slice(2).to_a]
|
2688
2770
|
end
|
2689
2771
|
end
|
@@ -2699,11 +2781,12 @@ class Redis
|
|
2699
2781
|
# - `:count => Integer`: return count keys at most per iteration
|
2700
2782
|
#
|
2701
2783
|
# @return [Enumerator] an enumerator for all found keys
|
2702
|
-
def hscan_each(key, options
|
2703
|
-
return to_enum(:hscan_each, key, options) unless block_given?
|
2784
|
+
def hscan_each(key, **options, &block)
|
2785
|
+
return to_enum(:hscan_each, key, **options) unless block_given?
|
2786
|
+
|
2704
2787
|
cursor = 0
|
2705
2788
|
loop do
|
2706
|
-
cursor, values = hscan(key, cursor, options)
|
2789
|
+
cursor, values = hscan(key, cursor, **options)
|
2707
2790
|
values.each(&block)
|
2708
2791
|
break if cursor == "0"
|
2709
2792
|
end
|
@@ -2721,8 +2804,8 @@ class Redis
|
|
2721
2804
|
#
|
2722
2805
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2723
2806
|
# members and scores
|
2724
|
-
def zscan(key, cursor, options
|
2725
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2807
|
+
def zscan(key, cursor, **options)
|
2808
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2726
2809
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2727
2810
|
end
|
2728
2811
|
end
|
@@ -2738,11 +2821,12 @@ class Redis
|
|
2738
2821
|
# - `:count => Integer`: return count keys at most per iteration
|
2739
2822
|
#
|
2740
2823
|
# @return [Enumerator] an enumerator for all found scores and members
|
2741
|
-
def zscan_each(key, options
|
2742
|
-
return to_enum(:zscan_each, key, options) unless block_given?
|
2824
|
+
def zscan_each(key, **options, &block)
|
2825
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
2826
|
+
|
2743
2827
|
cursor = 0
|
2744
2828
|
loop do
|
2745
|
-
cursor, values = zscan(key, cursor, options)
|
2829
|
+
cursor, values = zscan(key, cursor, **options)
|
2746
2830
|
values.each(&block)
|
2747
2831
|
break if cursor == "0"
|
2748
2832
|
end
|
@@ -2759,8 +2843,8 @@ class Redis
|
|
2759
2843
|
# - `:count => Integer`: return count keys at most per iteration
|
2760
2844
|
#
|
2761
2845
|
# @return [String, Array<String>] the next cursor and all found members
|
2762
|
-
def sscan(key, cursor, options
|
2763
|
-
_scan(:sscan, cursor, [key], options)
|
2846
|
+
def sscan(key, cursor, **options)
|
2847
|
+
_scan(:sscan, cursor, [key], **options)
|
2764
2848
|
end
|
2765
2849
|
|
2766
2850
|
# Scan a set
|
@@ -2774,11 +2858,12 @@ class Redis
|
|
2774
2858
|
# - `:count => Integer`: return count keys at most per iteration
|
2775
2859
|
#
|
2776
2860
|
# @return [Enumerator] an enumerator for all keys in the set
|
2777
|
-
def sscan_each(key, options
|
2778
|
-
return to_enum(:sscan_each, key, options) unless block_given?
|
2861
|
+
def sscan_each(key, **options, &block)
|
2862
|
+
return to_enum(:sscan_each, key, **options) unless block_given?
|
2863
|
+
|
2779
2864
|
cursor = 0
|
2780
2865
|
loop do
|
2781
|
-
cursor, keys = sscan(key, cursor, options)
|
2866
|
+
cursor, keys = sscan(key, cursor, **options)
|
2782
2867
|
keys.each(&block)
|
2783
2868
|
break if cursor == "0"
|
2784
2869
|
end
|
@@ -2842,12 +2927,12 @@ class Redis
|
|
2842
2927
|
end
|
2843
2928
|
end
|
2844
2929
|
|
2845
|
-
|
2846
2930
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2847
2931
|
# given maximum distance from a point
|
2848
2932
|
#
|
2849
2933
|
# @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
|
2850
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2934
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2935
|
+
# or the farthest to the nearest relative to the center
|
2851
2936
|
# @param [Integer] count limit the results to the first N matching items
|
2852
2937
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2853
2938
|
# @return [Array<String>] may be changed with `options`
|
@@ -2864,7 +2949,8 @@ class Redis
|
|
2864
2949
|
# given maximum distance from an already existing member
|
2865
2950
|
#
|
2866
2951
|
# @param [Array] args key, member, radius, unit(m|km|ft|mi)
|
2867
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2952
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2953
|
+
# to the nearest relative to the center
|
2868
2954
|
# @param [Integer] count limit the results to the first N matching items
|
2869
2955
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2870
2956
|
# @return [Array<String>] may be changed with `options`
|
@@ -2881,7 +2967,8 @@ class Redis
|
|
2881
2967
|
#
|
2882
2968
|
# @param [String] key
|
2883
2969
|
# @param [String, Array<String>] member one member or array of members
|
2884
|
-
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2970
|
+
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2971
|
+
# element is either array of longitude and latitude or nil
|
2885
2972
|
def geopos(key, member)
|
2886
2973
|
synchronize do |client|
|
2887
2974
|
client.call([:geopos, key, member])
|
@@ -2945,10 +3032,14 @@ class Redis
|
|
2945
3032
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2946
3033
|
#
|
2947
3034
|
# @return [String] the entry id
|
2948
|
-
def xadd(key, entry,
|
3035
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2949
3036
|
args = [:xadd, key]
|
2950
|
-
|
2951
|
-
|
3037
|
+
if maxlen
|
3038
|
+
args << "MAXLEN"
|
3039
|
+
args << "~" if approximate
|
3040
|
+
args << maxlen
|
3041
|
+
end
|
3042
|
+
args << id
|
2952
3043
|
args.concat(entry.to_a.flatten)
|
2953
3044
|
synchronize { |client| client.call(args) }
|
2954
3045
|
end
|
@@ -3003,8 +3094,8 @@ class Redis
|
|
3003
3094
|
# @param count [Integer] the number of entries as limit
|
3004
3095
|
#
|
3005
3096
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3006
|
-
def xrange(key, start = '-',
|
3007
|
-
args = [:xrange, key, start,
|
3097
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3098
|
+
args = [:xrange, key, start, range_end]
|
3008
3099
|
args.concat(['COUNT', count]) if count
|
3009
3100
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3010
3101
|
end
|
@@ -3026,8 +3117,8 @@ class Redis
|
|
3026
3117
|
# @params count [Integer] the number of entries as limit
|
3027
3118
|
#
|
3028
3119
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3029
|
-
def xrevrange(key,
|
3030
|
-
args = [:xrevrange, key,
|
3120
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3121
|
+
args = [:xrevrange, key, range_end, start]
|
3031
3122
|
args.concat(['COUNT', count]) if count
|
3032
3123
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3033
3124
|
end
|
@@ -3119,12 +3210,12 @@ class Redis
|
|
3119
3210
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3120
3211
|
#
|
3121
3212
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3122
|
-
def xreadgroup(group, consumer, keys, ids,
|
3213
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3123
3214
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3124
|
-
args << 'COUNT' <<
|
3125
|
-
args << 'BLOCK' <<
|
3126
|
-
args << 'NOACK' if
|
3127
|
-
_xread(args, keys, ids,
|
3215
|
+
args << 'COUNT' << count if count
|
3216
|
+
args << 'BLOCK' << block.to_i if block
|
3217
|
+
args << 'NOACK' if noack
|
3218
|
+
_xread(args, keys, ids, block)
|
3128
3219
|
end
|
3129
3220
|
|
3130
3221
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3189,6 +3280,38 @@ class Redis
|
|
3189
3280
|
synchronize { |client| client.call(args, &blk) }
|
3190
3281
|
end
|
3191
3282
|
|
3283
|
+
# Transfers ownership of pending stream entries that match the specified criteria.
|
3284
|
+
#
|
3285
|
+
# @example Claim next pending message stuck > 5 minutes and mark as retry
|
3286
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0')
|
3287
|
+
# @example Claim 50 next pending messages stuck > 5 minutes and mark as retry
|
3288
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', count: 50)
|
3289
|
+
# @example Claim next pending message stuck > 5 minutes and don't mark as retry
|
3290
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', justid: true)
|
3291
|
+
# @example Claim next pending message after this id stuck > 5 minutes and mark as retry
|
3292
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '1641321233-0')
|
3293
|
+
#
|
3294
|
+
# @param key [String] the stream key
|
3295
|
+
# @param group [String] the consumer group name
|
3296
|
+
# @param consumer [String] the consumer name
|
3297
|
+
# @param min_idle_time [Integer] the number of milliseconds
|
3298
|
+
# @param start [String] entry id to start scanning from or 0-0 for everything
|
3299
|
+
# @param count [Integer] number of messages to claim (default 1)
|
3300
|
+
# @param justid [Boolean] whether to fetch just an array of entry ids or not.
|
3301
|
+
# Does not increment retry count when true
|
3302
|
+
#
|
3303
|
+
# @return [Hash{String => Hash}] the entries successfully claimed
|
3304
|
+
# @return [Array<String>] the entry ids successfully claimed if justid option is `true`
|
3305
|
+
def xautoclaim(key, group, consumer, min_idle_time, start, count: nil, justid: false)
|
3306
|
+
args = [:xautoclaim, key, group, consumer, min_idle_time, start]
|
3307
|
+
if count
|
3308
|
+
args << 'COUNT' << count.to_s
|
3309
|
+
end
|
3310
|
+
args << 'JUSTID' if justid
|
3311
|
+
blk = justid ? HashifyStreamAutoclaimJustId : HashifyStreamAutoclaim
|
3312
|
+
synchronize { |client| client.call(args, &blk) }
|
3313
|
+
end
|
3314
|
+
|
3192
3315
|
# Fetches not acknowledging pending entries
|
3193
3316
|
#
|
3194
3317
|
# @example With key and group
|
@@ -3234,8 +3357,8 @@ class Redis
|
|
3234
3357
|
when "get-master-addr-by-name"
|
3235
3358
|
reply
|
3236
3359
|
else
|
3237
|
-
if reply.
|
3238
|
-
if reply[0].
|
3360
|
+
if reply.is_a?(Array)
|
3361
|
+
if reply[0].is_a?(Array)
|
3239
3362
|
reply.map(&Hashify)
|
3240
3363
|
else
|
3241
3364
|
Hashify.call(reply)
|
@@ -3259,12 +3382,17 @@ class Redis
|
|
3259
3382
|
def cluster(subcommand, *args)
|
3260
3383
|
subcommand = subcommand.to_s.downcase
|
3261
3384
|
block = case subcommand
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3385
|
+
when 'slots'
|
3386
|
+
HashifyClusterSlots
|
3387
|
+
when 'nodes'
|
3388
|
+
HashifyClusterNodes
|
3389
|
+
when 'slaves'
|
3390
|
+
HashifyClusterSlaves
|
3391
|
+
when 'info'
|
3392
|
+
HashifyInfo
|
3393
|
+
else
|
3394
|
+
Noop
|
3395
|
+
end
|
3268
3396
|
|
3269
3397
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3270
3398
|
block = Noop unless @cluster_mode
|
@@ -3299,21 +3427,21 @@ class Redis
|
|
3299
3427
|
return @original_client.connection_info if @cluster_mode
|
3300
3428
|
|
3301
3429
|
{
|
3302
|
-
host:
|
3303
|
-
port:
|
3304
|
-
db:
|
3305
|
-
id:
|
3430
|
+
host: @original_client.host,
|
3431
|
+
port: @original_client.port,
|
3432
|
+
db: @original_client.db,
|
3433
|
+
id: @original_client.id,
|
3306
3434
|
location: @original_client.location
|
3307
3435
|
}
|
3308
3436
|
end
|
3309
3437
|
|
3310
|
-
def method_missing(command, *args)
|
3438
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3311
3439
|
synchronize do |client|
|
3312
3440
|
client.call([command] + args)
|
3313
3441
|
end
|
3314
3442
|
end
|
3315
3443
|
|
3316
|
-
private
|
3444
|
+
private
|
3317
3445
|
|
3318
3446
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3319
3447
|
# where the method call will return nil. Propagate the nil instead of falsely
|
@@ -3385,18 +3513,35 @@ private
|
|
3385
3513
|
end
|
3386
3514
|
}
|
3387
3515
|
|
3516
|
+
EMPTY_STREAM_RESPONSE = [nil].freeze
|
3517
|
+
private_constant :EMPTY_STREAM_RESPONSE
|
3518
|
+
|
3388
3519
|
HashifyStreamEntries = lambda { |reply|
|
3389
|
-
reply.map do |entry_id, values|
|
3520
|
+
reply.compact.map do |entry_id, values|
|
3390
3521
|
[entry_id, values.each_slice(2).to_h]
|
3391
3522
|
end
|
3392
3523
|
}
|
3393
3524
|
|
3525
|
+
HashifyStreamAutoclaim = lambda { |reply|
|
3526
|
+
{
|
3527
|
+
'next' => reply[0],
|
3528
|
+
'entries' => reply[1].map { |entry| [entry[0], entry[1].each_slice(2).to_h] }
|
3529
|
+
}
|
3530
|
+
}
|
3531
|
+
|
3532
|
+
HashifyStreamAutoclaimJustId = lambda { |reply|
|
3533
|
+
{
|
3534
|
+
'next' => reply[0],
|
3535
|
+
'entries' => reply[1]
|
3536
|
+
}
|
3537
|
+
}
|
3538
|
+
|
3394
3539
|
HashifyStreamPendings = lambda { |reply|
|
3395
3540
|
{
|
3396
|
-
'size'
|
3541
|
+
'size' => reply[0],
|
3397
3542
|
'min_entry_id' => reply[1],
|
3398
3543
|
'max_entry_id' => reply[2],
|
3399
|
-
'consumers'
|
3544
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3400
3545
|
}
|
3401
3546
|
}
|
3402
3547
|
|
@@ -3405,8 +3550,8 @@ private
|
|
3405
3550
|
{
|
3406
3551
|
'entry_id' => arr[0],
|
3407
3552
|
'consumer' => arr[1],
|
3408
|
-
'elapsed'
|
3409
|
-
'count'
|
3553
|
+
'elapsed' => arr[2],
|
3554
|
+
'count' => arr[3]
|
3410
3555
|
}
|
3411
3556
|
end
|
3412
3557
|
}
|
@@ -3414,15 +3559,15 @@ private
|
|
3414
3559
|
HashifyClusterNodeInfo = lambda { |str|
|
3415
3560
|
arr = str.split(' ')
|
3416
3561
|
{
|
3417
|
-
'node_id'
|
3418
|
-
'ip_port'
|
3419
|
-
'flags'
|
3562
|
+
'node_id' => arr[0],
|
3563
|
+
'ip_port' => arr[1],
|
3564
|
+
'flags' => arr[2].split(','),
|
3420
3565
|
'master_node_id' => arr[3],
|
3421
|
-
'ping_sent'
|
3422
|
-
'pong_recv'
|
3423
|
-
'config_epoch'
|
3424
|
-
'link_state'
|
3425
|
-
'slots'
|
3566
|
+
'ping_sent' => arr[4],
|
3567
|
+
'pong_recv' => arr[5],
|
3568
|
+
'config_epoch' => arr[6],
|
3569
|
+
'link_state' => arr[7],
|
3570
|
+
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3426
3571
|
}
|
3427
3572
|
}
|
3428
3573
|
|
@@ -3433,9 +3578,9 @@ private
|
|
3433
3578
|
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3434
3579
|
{
|
3435
3580
|
'start_slot' => first_slot,
|
3436
|
-
'end_slot'
|
3437
|
-
'master'
|
3438
|
-
'replicas'
|
3581
|
+
'end_slot' => last_slot,
|
3582
|
+
'master' => master,
|
3583
|
+
'replicas' => replicas
|
3439
3584
|
}
|
3440
3585
|
end
|
3441
3586
|
}
|