redis 4.8.0 → 5.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -1
- data/README.md +75 -161
- data/lib/redis/client.rb +77 -616
- data/lib/redis/commands/bitmaps.rb +4 -1
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +3 -3
- data/lib/redis/commands/hashes.rb +9 -6
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +5 -23
- data/lib/redis/commands/lists.rb +20 -25
- data/lib/redis/commands/pubsub.rb +7 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +31 -40
- data/lib/redis/commands/sorted_sets.rb +18 -12
- data/lib/redis/commands/streams.rb +39 -19
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +4 -7
- data/lib/redis/distributed.rb +86 -64
- data/lib/redis/errors.rb +15 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +43 -222
- data/lib/redis/subscribe.rb +23 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +89 -184
- metadata +9 -53
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
@@ -136,7 +136,9 @@ class Redis
|
|
136
136
|
# @return [Array<String, Float>] element and score pair if count is not specified
|
137
137
|
# @return [Array<Array<String, Float>>] list of popped elements and scores
|
138
138
|
def zpopmax(key, count = nil)
|
139
|
-
|
139
|
+
command = [:zpopmax, key]
|
140
|
+
command << Integer(count) if count
|
141
|
+
send_command(command) do |members|
|
140
142
|
members = FloatifyPairs.call(members)
|
141
143
|
count.to_i > 1 ? members : members.first
|
142
144
|
end
|
@@ -157,7 +159,9 @@ class Redis
|
|
157
159
|
# @return [Array<String, Float>] element and score pair if count is not specified
|
158
160
|
# @return [Array<Array<String, Float>>] list of popped elements and scores
|
159
161
|
def zpopmin(key, count = nil)
|
160
|
-
|
162
|
+
command = [:zpopmin, key]
|
163
|
+
command << Integer(count) if count
|
164
|
+
send_command(command) do |members|
|
161
165
|
members = FloatifyPairs.call(members)
|
162
166
|
count.to_i > 1 ? members : members.first
|
163
167
|
end
|
@@ -261,7 +265,7 @@ class Redis
|
|
261
265
|
end
|
262
266
|
|
263
267
|
args = [:zrandmember, key]
|
264
|
-
args << count if count
|
268
|
+
args << Integer(count) if count
|
265
269
|
|
266
270
|
if with_scores
|
267
271
|
args << "WITHSCORES"
|
@@ -313,7 +317,7 @@ class Redis
|
|
313
317
|
|
314
318
|
if limit
|
315
319
|
args << "LIMIT"
|
316
|
-
args.concat(limit)
|
320
|
+
args.concat(limit.map { |l| Integer(l) })
|
317
321
|
end
|
318
322
|
|
319
323
|
if with_scores
|
@@ -354,7 +358,7 @@ class Redis
|
|
354
358
|
|
355
359
|
if limit
|
356
360
|
args << "LIMIT"
|
357
|
-
args.concat(limit)
|
361
|
+
args.concat(limit.map { |l| Integer(l) })
|
358
362
|
end
|
359
363
|
|
360
364
|
send_command(args)
|
@@ -372,7 +376,7 @@ class Redis
|
|
372
376
|
#
|
373
377
|
# @see #zrange
|
374
378
|
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
375
|
-
args = [:zrevrange, key, start, stop]
|
379
|
+
args = [:zrevrange, key, Integer(start), Integer(stop)]
|
376
380
|
|
377
381
|
if with_scores
|
378
382
|
args << "WITHSCORES"
|
@@ -466,7 +470,7 @@ class Redis
|
|
466
470
|
|
467
471
|
if limit
|
468
472
|
args << "LIMIT"
|
469
|
-
args.concat(limit)
|
473
|
+
args.concat(limit.map { |l| Integer(l) })
|
470
474
|
end
|
471
475
|
|
472
476
|
send_command(args)
|
@@ -488,7 +492,7 @@ class Redis
|
|
488
492
|
|
489
493
|
if limit
|
490
494
|
args << "LIMIT"
|
491
|
-
args.concat(limit)
|
495
|
+
args.concat(limit.map { |l| Integer(l) })
|
492
496
|
end
|
493
497
|
|
494
498
|
send_command(args)
|
@@ -531,7 +535,7 @@ class Redis
|
|
531
535
|
|
532
536
|
if limit
|
533
537
|
args << "LIMIT"
|
534
|
-
args.concat(limit)
|
538
|
+
args.concat(limit.map { |l| Integer(l) })
|
535
539
|
end
|
536
540
|
|
537
541
|
send_command(args, &block)
|
@@ -561,7 +565,7 @@ class Redis
|
|
561
565
|
|
562
566
|
if limit
|
563
567
|
args << "LIMIT"
|
564
|
-
args.concat(limit)
|
568
|
+
args.concat(limit.map { |l| Integer(l) })
|
565
569
|
end
|
566
570
|
|
567
571
|
send_command(args, &block)
|
@@ -778,7 +782,8 @@ class Redis
|
|
778
782
|
private
|
779
783
|
|
780
784
|
def _zsets_operation(cmd, *keys, weights: nil, aggregate: nil, with_scores: false)
|
781
|
-
|
785
|
+
keys.flatten!(1)
|
786
|
+
command = [cmd, keys.size].concat(keys)
|
782
787
|
|
783
788
|
if weights
|
784
789
|
command << "WEIGHTS"
|
@@ -796,7 +801,8 @@ class Redis
|
|
796
801
|
end
|
797
802
|
|
798
803
|
def _zsets_operation_store(cmd, destination, keys, weights: nil, aggregate: nil)
|
799
|
-
|
804
|
+
keys.flatten!(1)
|
805
|
+
command = [cmd, destination, keys.size].concat(keys)
|
800
806
|
|
801
807
|
if weights
|
802
808
|
command << "WEIGHTS"
|
@@ -21,15 +21,12 @@ class Redis
|
|
21
21
|
# @return [Array<Hash>] information of the consumers if subcommand is `consumers`
|
22
22
|
def xinfo(subcommand, key, group = nil)
|
23
23
|
args = [:xinfo, subcommand, key, group].compact
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
when 'stream' then Hashify.call(reply)
|
28
|
-
when 'groups', 'consumers' then reply.map { |arr| Hashify.call(arr) }
|
29
|
-
else reply
|
30
|
-
end
|
31
|
-
end
|
24
|
+
block = case subcommand.to_s.downcase
|
25
|
+
when 'stream' then Hashify
|
26
|
+
when 'groups', 'consumers' then proc { |r| r.map(&Hashify) }
|
32
27
|
end
|
28
|
+
|
29
|
+
send_command(args, &block)
|
33
30
|
end
|
34
31
|
|
35
32
|
# Add new entry to the stream.
|
@@ -37,7 +34,7 @@ class Redis
|
|
37
34
|
# @example Without options
|
38
35
|
# redis.xadd('mystream', f1: 'v1', f2: 'v2')
|
39
36
|
# @example With options
|
40
|
-
# redis.xadd('mystream', { f1: 'v1', f2: 'v2' }, id: '0-0', maxlen: 1000, approximate: true)
|
37
|
+
# redis.xadd('mystream', { f1: 'v1', f2: 'v2' }, id: '0-0', maxlen: 1000, approximate: true, nomkstream: true)
|
41
38
|
#
|
42
39
|
# @param key [String] the stream key
|
43
40
|
# @param entry [Hash] one or multiple field-value pairs
|
@@ -46,17 +43,19 @@ class Redis
|
|
46
43
|
# @option opts [String] :id the entry id, default value is `*`, it means auto generation
|
47
44
|
# @option opts [Integer] :maxlen max length of entries
|
48
45
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
46
|
+
# @option opts [Boolean] :nomkstream whether to add NOMKSTREAM, default is not to add
|
49
47
|
#
|
50
48
|
# @return [String] the entry id
|
51
|
-
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
49
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, nomkstream: nil, id: '*')
|
52
50
|
args = [:xadd, key]
|
51
|
+
args << 'NOMKSTREAM' if nomkstream
|
53
52
|
if maxlen
|
54
53
|
args << "MAXLEN"
|
55
54
|
args << "~" if approximate
|
56
55
|
args << maxlen
|
57
56
|
end
|
58
57
|
args << id
|
59
|
-
args.concat(entry.
|
58
|
+
args.concat(entry.flatten)
|
60
59
|
send_command(args)
|
61
60
|
end
|
62
61
|
|
@@ -66,14 +65,30 @@ class Redis
|
|
66
65
|
# redis.xtrim('mystream', 1000)
|
67
66
|
# @example With options
|
68
67
|
# redis.xtrim('mystream', 1000, approximate: true)
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
# @
|
68
|
+
# @example With strategy
|
69
|
+
# redis.xtrim('mystream', '1-0', strategy: 'MINID')
|
70
|
+
#
|
71
|
+
# @overload xtrim(key, maxlen, strategy: 'MAXLEN', approximate: true)
|
72
|
+
# @param key [String] the stream key
|
73
|
+
# @param maxlen [Integer] max length of entries
|
74
|
+
# @param strategy [String] the limit strategy, must be MAXLEN
|
75
|
+
# @param approximate [Boolean] whether to add `~` modifier of maxlen or not
|
76
|
+
# @param limit [Integer] maximum count of entries to be evicted
|
77
|
+
# @overload xtrim(key, minid, strategy: 'MINID', approximate: true)
|
78
|
+
# @param key [String] the stream key
|
79
|
+
# @param minid [String] minimum id of entries
|
80
|
+
# @param strategy [String] the limit strategy, must be MINID
|
81
|
+
# @param approximate [Boolean] whether to add `~` modifier of minid or not
|
82
|
+
# @param limit [Integer] maximum count of entries to be evicted
|
73
83
|
#
|
74
84
|
# @return [Integer] the number of entries actually deleted
|
75
|
-
def xtrim(key,
|
76
|
-
|
85
|
+
def xtrim(key, len_or_id, strategy: 'MAXLEN', approximate: false, limit: nil)
|
86
|
+
strategy = strategy.to_s.upcase
|
87
|
+
|
88
|
+
args = [:xtrim, key, strategy]
|
89
|
+
args << '~' if approximate
|
90
|
+
args << len_or_id
|
91
|
+
args.concat(['LIMIT', limit]) if limit
|
77
92
|
send_command(args)
|
78
93
|
end
|
79
94
|
|
@@ -113,7 +128,7 @@ class Redis
|
|
113
128
|
def xrange(key, start = '-', range_end = '+', count: nil)
|
114
129
|
args = [:xrange, key, start, range_end]
|
115
130
|
args.concat(['COUNT', count]) if count
|
116
|
-
|
131
|
+
send_command(args, &HashifyStreamEntries)
|
117
132
|
end
|
118
133
|
|
119
134
|
# Fetches entries of the stream in descending order.
|
@@ -334,6 +349,8 @@ class Redis
|
|
334
349
|
# redis.xpending('mystream', 'mygroup')
|
335
350
|
# @example With range options
|
336
351
|
# redis.xpending('mystream', 'mygroup', '-', '+', 10)
|
352
|
+
# @example With range and idle time options
|
353
|
+
# redis.xpending('mystream', 'mygroup', '-', '+', 10, idle: 9000)
|
337
354
|
# @example With range and consumer options
|
338
355
|
# redis.xpending('mystream', 'mygroup', '-', '+', 10, 'consumer1')
|
339
356
|
#
|
@@ -344,10 +361,13 @@ class Redis
|
|
344
361
|
# @param count [Integer] count the number of entries as limit
|
345
362
|
# @param consumer [String] the consumer name
|
346
363
|
#
|
364
|
+
# @option opts [Integer] :idle pending message minimum idle time in milliseconds
|
365
|
+
#
|
347
366
|
# @return [Hash] the summary of pending entries
|
348
367
|
# @return [Array<Hash>] the pending entries details if options were specified
|
349
|
-
def xpending(key, group, *args)
|
368
|
+
def xpending(key, group, *args, idle: nil)
|
350
369
|
command_args = [:xpending, key, group]
|
370
|
+
command_args << 'IDLE' << Integer(idle) if idle
|
351
371
|
case args.size
|
352
372
|
when 0, 3, 4
|
353
373
|
command_args.concat(args)
|
@@ -25,7 +25,7 @@ class Redis
|
|
25
25
|
# @param [Integer] decrement
|
26
26
|
# @return [Integer] value after decrementing it
|
27
27
|
def decrby(key, decrement)
|
28
|
-
send_command([:decrby, key, decrement])
|
28
|
+
send_command([:decrby, key, Integer(decrement)])
|
29
29
|
end
|
30
30
|
|
31
31
|
# Increment the integer value of a key by one.
|
@@ -50,7 +50,7 @@ class Redis
|
|
50
50
|
# @param [Integer] increment
|
51
51
|
# @return [Integer] value after incrementing it
|
52
52
|
def incrby(key, increment)
|
53
|
-
send_command([:incrby, key, increment])
|
53
|
+
send_command([:incrby, key, Integer(increment)])
|
54
54
|
end
|
55
55
|
|
56
56
|
# Increment the numeric value of a key by the given float number.
|
@@ -63,7 +63,7 @@ class Redis
|
|
63
63
|
# @param [Float] increment
|
64
64
|
# @return [Float] value after incrementing it
|
65
65
|
def incrbyfloat(key, increment)
|
66
|
-
send_command([:incrbyfloat, key, increment], &Floatify)
|
66
|
+
send_command([:incrbyfloat, key, Float(increment)], &Floatify)
|
67
67
|
end
|
68
68
|
|
69
69
|
# Set the string value of a key.
|
@@ -82,10 +82,10 @@ class Redis
|
|
82
82
|
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
83
83
|
def set(key, value, ex: nil, px: nil, exat: nil, pxat: nil, nx: nil, xx: nil, keepttl: nil, get: nil)
|
84
84
|
args = [:set, key, value.to_s]
|
85
|
-
args << "EX" << ex if ex
|
86
|
-
args << "PX" << px if px
|
87
|
-
args << "EXAT" << exat if exat
|
88
|
-
args << "PXAT" << pxat if pxat
|
85
|
+
args << "EX" << Integer(ex) if ex
|
86
|
+
args << "PX" << Integer(px) if px
|
87
|
+
args << "EXAT" << Integer(exat) if exat
|
88
|
+
args << "PXAT" << Integer(pxat) if pxat
|
89
89
|
args << "NX" if nx
|
90
90
|
args << "XX" if xx
|
91
91
|
args << "KEEPTTL" if keepttl
|
@@ -105,7 +105,7 @@ class Redis
|
|
105
105
|
# @param [String] value
|
106
106
|
# @return [String] `"OK"`
|
107
107
|
def setex(key, ttl, value)
|
108
|
-
send_command([:setex, key, ttl, value.to_s])
|
108
|
+
send_command([:setex, key, Integer(ttl), value.to_s])
|
109
109
|
end
|
110
110
|
|
111
111
|
# Set the time to live in milliseconds of a key.
|
@@ -115,7 +115,7 @@ class Redis
|
|
115
115
|
# @param [String] value
|
116
116
|
# @return [String] `"OK"`
|
117
117
|
def psetex(key, ttl, value)
|
118
|
-
send_command([:psetex, key, ttl, value.to_s])
|
118
|
+
send_command([:psetex, key, Integer(ttl), value.to_s])
|
119
119
|
end
|
120
120
|
|
121
121
|
# Set the value of a key, only if the key does not exist.
|
@@ -152,7 +152,7 @@ class Redis
|
|
152
152
|
#
|
153
153
|
# @see #mset
|
154
154
|
def mapped_mset(hash)
|
155
|
-
mset(hash.
|
155
|
+
mset(hash.flatten)
|
156
156
|
end
|
157
157
|
|
158
158
|
# Set one or more values, only if none of the keys exist.
|
@@ -180,7 +180,7 @@ class Redis
|
|
180
180
|
#
|
181
181
|
# @see #msetnx
|
182
182
|
def mapped_msetnx(hash)
|
183
|
-
msetnx(hash.
|
183
|
+
msetnx(hash.flatten)
|
184
184
|
end
|
185
185
|
|
186
186
|
# Get the value of a key.
|
@@ -202,6 +202,7 @@ class Redis
|
|
202
202
|
#
|
203
203
|
# @see #mapped_mget
|
204
204
|
def mget(*keys, &blk)
|
205
|
+
keys.flatten!(1)
|
205
206
|
send_command([:mget, *keys], &blk)
|
206
207
|
end
|
207
208
|
|
@@ -232,7 +233,7 @@ class Redis
|
|
232
233
|
# @param [String] value
|
233
234
|
# @return [Integer] length of the string after it was modified
|
234
235
|
def setrange(key, offset, value)
|
235
|
-
send_command([:setrange, key, offset, value.to_s])
|
236
|
+
send_command([:setrange, key, Integer(offset), value.to_s])
|
236
237
|
end
|
237
238
|
|
238
239
|
# Get a substring of the string stored at a key.
|
@@ -243,7 +244,7 @@ class Redis
|
|
243
244
|
# the end of the string
|
244
245
|
# @return [Integer] `0` or `1`
|
245
246
|
def getrange(key, start, stop)
|
246
|
-
send_command([:getrange, key, start, stop])
|
247
|
+
send_command([:getrange, key, Integer(start), Integer(stop)])
|
247
248
|
end
|
248
249
|
|
249
250
|
# Append a value to a key.
|
@@ -291,10 +292,10 @@ class Redis
|
|
291
292
|
# @return [String] The value of key, or nil when key does not exist.
|
292
293
|
def getex(key, ex: nil, px: nil, exat: nil, pxat: nil, persist: false)
|
293
294
|
args = [:getex, key]
|
294
|
-
args << "EX" << ex if ex
|
295
|
-
args << "PX" << px if px
|
296
|
-
args << "EXAT" << exat if exat
|
297
|
-
args << "PXAT" << pxat if pxat
|
295
|
+
args << "EX" << Integer(ex) if ex
|
296
|
+
args << "PX" << Integer(px) if px
|
297
|
+
args << "EXAT" << Integer(exat) if exat
|
298
|
+
args << "PXAT" << Integer(pxat) if pxat
|
298
299
|
args << "PERSIST" if persist
|
299
300
|
|
300
301
|
send_command(args)
|
@@ -5,48 +5,26 @@ class Redis
|
|
5
5
|
module Transactions
|
6
6
|
# Mark the start of a transaction block.
|
7
7
|
#
|
8
|
-
# Passing a block is optional.
|
9
|
-
#
|
10
8
|
# @example With a block
|
11
9
|
# redis.multi do |multi|
|
12
10
|
# multi.set("key", "value")
|
13
11
|
# multi.incr("counter")
|
14
12
|
# end # => ["OK", 6]
|
15
13
|
#
|
16
|
-
# @example Without a block
|
17
|
-
# redis.multi
|
18
|
-
# # => "OK"
|
19
|
-
# redis.set("key", "value")
|
20
|
-
# # => "QUEUED"
|
21
|
-
# redis.incr("counter")
|
22
|
-
# # => "QUEUED"
|
23
|
-
# redis.exec
|
24
|
-
# # => ["OK", 6]
|
25
|
-
#
|
26
14
|
# @yield [multi] the commands that are called inside this block are cached
|
27
15
|
# and written to the server upon returning from it
|
28
16
|
# @yieldparam [Redis] multi `self`
|
29
17
|
#
|
30
|
-
# @return [
|
31
|
-
# -
|
32
|
-
# - when a block is given, an array with replies
|
18
|
+
# @return [Array<...>]
|
19
|
+
# - an array with replies
|
33
20
|
#
|
34
21
|
# @see #watch
|
35
22
|
# @see #unwatch
|
36
|
-
def multi
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
synchronize do |prior_client|
|
43
|
-
pipeline = Pipeline::Multi.new(prior_client)
|
44
|
-
pipelined_connection = PipelinedConnection.new(pipeline)
|
45
|
-
yield pipelined_connection
|
46
|
-
prior_client.call_pipeline(pipeline)
|
23
|
+
def multi
|
24
|
+
synchronize do |client|
|
25
|
+
client.multi do |raw_transaction|
|
26
|
+
yield MultiConnection.new(raw_transaction)
|
47
27
|
end
|
48
|
-
else
|
49
|
-
send_command([:multi])
|
50
28
|
end
|
51
29
|
end
|
52
30
|
|
@@ -82,7 +60,7 @@ class Redis
|
|
82
60
|
# @see #multi
|
83
61
|
def watch(*keys)
|
84
62
|
synchronize do |client|
|
85
|
-
res = client.
|
63
|
+
res = client.call_v([:watch] + keys)
|
86
64
|
|
87
65
|
if block_given?
|
88
66
|
begin
|
@@ -125,8 +103,6 @@ class Redis
|
|
125
103
|
|
126
104
|
# Discard all commands issued after MULTI.
|
127
105
|
#
|
128
|
-
# Only call this method when `#multi` was called **without** a block.
|
129
|
-
#
|
130
106
|
# @return [String] `"OK"`
|
131
107
|
#
|
132
108
|
# @see #multi
|
data/lib/redis/commands.rb
CHANGED
@@ -40,12 +40,7 @@ class Redis
|
|
40
40
|
# where the method call will return nil. Propagate the nil instead of falsely
|
41
41
|
# returning false.
|
42
42
|
Boolify = lambda { |value|
|
43
|
-
|
44
|
-
when Integer
|
45
|
-
value > 0
|
46
|
-
else
|
47
|
-
value
|
48
|
-
end
|
43
|
+
value != 0 unless value.nil?
|
49
44
|
}
|
50
45
|
|
51
46
|
BoolifySet = lambda { |value|
|
@@ -124,7 +119,9 @@ class Redis
|
|
124
119
|
HashifyStreamAutoclaim = lambda { |reply|
|
125
120
|
{
|
126
121
|
'next' => reply[0],
|
127
|
-
'entries' => reply[1].map
|
122
|
+
'entries' => reply[1].compact.map do |entry, values|
|
123
|
+
[entry, values.each_slice(2)&.to_h]
|
124
|
+
end
|
128
125
|
}
|
129
126
|
}
|
130
127
|
|