redis 4.2.0 → 4.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +1 -0
- data/lib/redis.rb +39 -18
- data/lib/redis/client.rb +5 -0
- data/lib/redis/connection/ruby.rb +53 -48
- data/lib/redis/distributed.rb +37 -8
- data/lib/redis/version.rb +1 -1
- metadata +12 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 862e8133262fead707e4ca317b29d0e35425e3a7861ea1a52033bc91ba61bf6d
|
4
|
+
data.tar.gz: 5b2b32250d783fe58b0af54cc386f2568241644a0badc0b7247bb29b1ac94a93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aab289f4f22b2f3a804ca7b0da4cf95e352a8d246611490d8d803edebbbc7e7c299355cd0b90e6f3ac8bc0d11e9bf3792a328c95847d32e1d984729afe66ed2
|
7
|
+
data.tar.gz: d9ec8ba4d314d099e909cdddf6dfb4c3c14b853b46f45c4909ac3ba10fb1880bd9a7b0465257fa91f9a4ea6c9f82723c16c177810ac15c89fab3790d7af31ad0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.2.5
|
4
|
+
|
5
|
+
* Optimize the ruby connector write buffering. See #964.
|
6
|
+
|
7
|
+
# 4.2.4
|
8
|
+
|
9
|
+
* Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
|
10
|
+
|
11
|
+
# 4.2.3
|
12
|
+
|
13
|
+
* Use io/wait instead of IO.select in the ruby connector. See #960.
|
14
|
+
* Use exception free non blocking IOs in the ruby connector. See #926.
|
15
|
+
* Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
|
16
|
+
|
17
|
+
# 4.2.2
|
18
|
+
|
19
|
+
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
20
|
+
* Fix handling of empty stream responses. See #905, #929.
|
21
|
+
|
22
|
+
# 4.2.1
|
23
|
+
|
24
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
25
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
26
|
+
|
3
27
|
# 4.2.0
|
4
28
|
|
5
29
|
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
@@ -12,6 +36,7 @@
|
|
12
36
|
* Optimized initialization of Redis::Cluster. See #912.
|
13
37
|
* Accept sentinel options even with string key. See #599.
|
14
38
|
* Verify TLS connections by default. See #900.
|
39
|
+
* Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
|
15
40
|
|
16
41
|
# 4.1.4
|
17
42
|
|
data/README.md
CHANGED
@@ -265,6 +265,7 @@ All timeout values are specified in seconds.
|
|
265
265
|
When using pub/sub, you can subscribe to a channel using a timeout as well:
|
266
266
|
|
267
267
|
```ruby
|
268
|
+
redis = Redis.new(reconnect_attempts: 0)
|
268
269
|
redis.subscribe_with_timeout(5, "news") do |on|
|
269
270
|
on.message do |channel, message|
|
270
271
|
# ...
|
data/lib/redis.rb
CHANGED
@@ -5,7 +5,20 @@ require_relative "redis/errors"
|
|
5
5
|
|
6
6
|
class Redis
|
7
7
|
class << self
|
8
|
-
|
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
|
+
|
9
22
|
attr_writer :current
|
10
23
|
end
|
11
24
|
|
@@ -561,11 +574,16 @@ class Redis
|
|
561
574
|
# @return [Integer]
|
562
575
|
def exists(*keys)
|
563
576
|
if !Redis.exists_returns_integer && keys.size == 1
|
564
|
-
|
565
|
-
"
|
566
|
-
|
577
|
+
if Redis.exists_returns_integer.nil?
|
578
|
+
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
|
579
|
+
"should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
|
580
|
+
"true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
|
581
|
+
"`Redis.exists_returns_integer = false`, but this option will be removed in 5.0. " \
|
582
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
583
|
+
|
584
|
+
::Kernel.warn(message)
|
585
|
+
end
|
567
586
|
|
568
|
-
::Kernel.warn(message)
|
569
587
|
exists?(*keys)
|
570
588
|
else
|
571
589
|
_exists(*keys)
|
@@ -584,7 +602,9 @@ class Redis
|
|
584
602
|
# @return [Boolean]
|
585
603
|
def exists?(*keys)
|
586
604
|
synchronize do |client|
|
587
|
-
client.call([:exists, *keys]
|
605
|
+
client.call([:exists, *keys]) do |value|
|
606
|
+
value > 0
|
607
|
+
end
|
588
608
|
end
|
589
609
|
end
|
590
610
|
|
@@ -2418,14 +2438,13 @@ class Redis
|
|
2418
2438
|
end
|
2419
2439
|
|
2420
2440
|
def pipelined
|
2421
|
-
synchronize do |
|
2441
|
+
synchronize do |prior_client|
|
2422
2442
|
begin
|
2423
|
-
|
2424
|
-
original, @client = @client, pipeline
|
2443
|
+
@client = Pipeline.new(prior_client)
|
2425
2444
|
yield(self)
|
2426
|
-
|
2445
|
+
prior_client.call_pipeline(@client)
|
2427
2446
|
ensure
|
2428
|
-
@client =
|
2447
|
+
@client = prior_client
|
2429
2448
|
end
|
2430
2449
|
end
|
2431
2450
|
end
|
@@ -2461,17 +2480,16 @@ class Redis
|
|
2461
2480
|
# @see #watch
|
2462
2481
|
# @see #unwatch
|
2463
2482
|
def multi
|
2464
|
-
synchronize do |
|
2483
|
+
synchronize do |prior_client|
|
2465
2484
|
if !block_given?
|
2466
|
-
|
2485
|
+
prior_client.call([:multi])
|
2467
2486
|
else
|
2468
2487
|
begin
|
2469
|
-
|
2470
|
-
original, @client = @client, pipeline
|
2488
|
+
@client = Pipeline::Multi.new(prior_client)
|
2471
2489
|
yield(self)
|
2472
|
-
|
2490
|
+
prior_client.call_pipeline(@client)
|
2473
2491
|
ensure
|
2474
|
-
@client =
|
2492
|
+
@client = prior_client
|
2475
2493
|
end
|
2476
2494
|
end
|
2477
2495
|
end
|
@@ -3403,8 +3421,11 @@ class Redis
|
|
3403
3421
|
end
|
3404
3422
|
}
|
3405
3423
|
|
3424
|
+
EMPTY_STREAM_RESPONSE = [nil].freeze
|
3425
|
+
private_constant :EMPTY_STREAM_RESPONSE
|
3426
|
+
|
3406
3427
|
HashifyStreamEntries = lambda { |reply|
|
3407
|
-
reply.map do |entry_id, values|
|
3428
|
+
reply.compact.map do |entry_id, values|
|
3408
3429
|
[entry_id, values.each_slice(2).to_h]
|
3409
3430
|
end
|
3410
3431
|
}
|
data/lib/redis/client.rb
CHANGED
@@ -6,12 +6,16 @@ require "cgi"
|
|
6
6
|
|
7
7
|
class Redis
|
8
8
|
class Client
|
9
|
+
# Defaults are also used for converting string keys to symbols.
|
9
10
|
DEFAULTS = {
|
10
11
|
url: -> { ENV["REDIS_URL"] },
|
11
12
|
scheme: "redis",
|
12
13
|
host: "127.0.0.1",
|
13
14
|
port: 6379,
|
14
15
|
path: nil,
|
16
|
+
read_timeout: nil,
|
17
|
+
write_timeout: nil,
|
18
|
+
connect_timeout: nil,
|
15
19
|
timeout: 5.0,
|
16
20
|
password: nil,
|
17
21
|
db: 0,
|
@@ -22,6 +26,7 @@ class Redis
|
|
22
26
|
reconnect_delay: 0,
|
23
27
|
reconnect_delay_max: 0.5,
|
24
28
|
inherit_socket: false,
|
29
|
+
logger: nil,
|
25
30
|
sentinels: nil,
|
26
31
|
role: nil
|
27
32
|
}.freeze
|
@@ -49,57 +49,50 @@ class Redis
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def _read_from_socket(nbytes)
|
52
|
-
|
53
|
-
read_nonblock(nbytes)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
rescue EOFError
|
68
|
-
raise Errno::ECONNRESET
|
69
|
-
end
|
70
|
-
|
71
|
-
def _write_to_socket(data)
|
72
|
-
begin
|
73
|
-
write_nonblock(data)
|
74
|
-
rescue IO::WaitWritable
|
75
|
-
if IO.select(nil, [self], nil, @write_timeout)
|
76
|
-
retry
|
77
|
-
else
|
78
|
-
raise Redis::TimeoutError
|
79
|
-
end
|
80
|
-
rescue IO::WaitReadable
|
81
|
-
if IO.select([self], nil, nil, @write_timeout)
|
82
|
-
retry
|
83
|
-
else
|
84
|
-
raise Redis::TimeoutError
|
52
|
+
loop do
|
53
|
+
case chunk = read_nonblock(nbytes, exception: false)
|
54
|
+
when :wait_readable
|
55
|
+
unless wait_readable(@timeout)
|
56
|
+
raise Redis::TimeoutError
|
57
|
+
end
|
58
|
+
when :wait_writable
|
59
|
+
unless wait_writable(@timeout)
|
60
|
+
raise Redis::TimeoutError
|
61
|
+
end
|
62
|
+
when nil
|
63
|
+
raise Errno::ECONNRESET
|
64
|
+
when String
|
65
|
+
return chunk
|
85
66
|
end
|
86
67
|
end
|
87
|
-
rescue EOFError
|
88
|
-
raise Errno::ECONNRESET
|
89
68
|
end
|
90
69
|
|
91
|
-
def write(
|
92
|
-
return super(
|
70
|
+
def write(buffer)
|
71
|
+
return super(buffer) unless @write_timeout
|
93
72
|
|
94
|
-
|
95
|
-
|
73
|
+
bytes_to_write = buffer.bytesize
|
74
|
+
total_bytes_written = 0
|
96
75
|
loop do
|
97
|
-
|
76
|
+
case bytes_written = write_nonblock(buffer, exception: false)
|
77
|
+
when :wait_readable
|
78
|
+
unless wait_readable(@write_timeout)
|
79
|
+
raise Redis::TimeoutError
|
80
|
+
end
|
81
|
+
when :wait_writable
|
82
|
+
unless wait_writable(@write_timeout)
|
83
|
+
raise Redis::TimeoutError
|
84
|
+
end
|
85
|
+
when nil
|
86
|
+
raise Errno::ECONNRESET
|
87
|
+
when Integer
|
88
|
+
total_bytes_written += bytes_written
|
98
89
|
|
99
|
-
|
100
|
-
|
90
|
+
if total_bytes_written >= bytes_to_write
|
91
|
+
return total_bytes_written
|
92
|
+
end
|
101
93
|
|
102
|
-
|
94
|
+
buffer = buffer.byteslice(bytes_written..-1)
|
95
|
+
end
|
103
96
|
end
|
104
97
|
end
|
105
98
|
end
|
@@ -135,7 +128,7 @@ class Redis
|
|
135
128
|
raise TimeoutError
|
136
129
|
end
|
137
130
|
|
138
|
-
# JRuby raises Errno::EAGAIN on #read_nonblock even when
|
131
|
+
# JRuby raises Errno::EAGAIN on #read_nonblock even when it
|
139
132
|
# says it is readable (1.6.6, in both 1.8 and 1.9 mode).
|
140
133
|
# Use the blocking #readpartial method instead.
|
141
134
|
|
@@ -160,7 +153,7 @@ class Redis
|
|
160
153
|
begin
|
161
154
|
sock.connect_nonblock(sockaddr)
|
162
155
|
rescue Errno::EINPROGRESS
|
163
|
-
raise TimeoutError
|
156
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
164
157
|
|
165
158
|
begin
|
166
159
|
sock.connect_nonblock(sockaddr)
|
@@ -215,7 +208,7 @@ class Redis
|
|
215
208
|
begin
|
216
209
|
sock.connect_nonblock(sockaddr)
|
217
210
|
rescue Errno::EINPROGRESS
|
218
|
-
raise TimeoutError
|
211
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
219
212
|
|
220
213
|
begin
|
221
214
|
sock.connect_nonblock(sockaddr)
|
@@ -233,6 +226,18 @@ class Redis
|
|
233
226
|
class SSLSocket < ::OpenSSL::SSL::SSLSocket
|
234
227
|
include SocketMixin
|
235
228
|
|
229
|
+
unless method_defined?(:wait_readable)
|
230
|
+
def wait_readable(timeout = nil)
|
231
|
+
to_io.wait_readable(timeout)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
unless method_defined?(:wait_writable)
|
236
|
+
def wait_writable(timeout = nil)
|
237
|
+
to_io.wait_writable(timeout)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
236
241
|
def self.connect(host, port, timeout, ssl_params)
|
237
242
|
# Note: this is using Redis::Connection::TCPSocket
|
238
243
|
tcp_sock = TCPSocket.connect(host, port, timeout)
|
@@ -254,13 +259,13 @@ class Redis
|
|
254
259
|
# Instead, you have to retry.
|
255
260
|
ssl_sock.connect_nonblock
|
256
261
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
257
|
-
if
|
262
|
+
if ssl_sock.wait_readable(timeout)
|
258
263
|
retry
|
259
264
|
else
|
260
265
|
raise TimeoutError
|
261
266
|
end
|
262
267
|
rescue IO::WaitWritable
|
263
|
-
if
|
268
|
+
if ssl_sock.wait_writable(timeout)
|
264
269
|
retry
|
265
270
|
else
|
266
271
|
raise TimeoutError
|
data/lib/redis/distributed.rb
CHANGED
@@ -24,10 +24,14 @@ class Redis
|
|
24
24
|
@default_options = options.dup
|
25
25
|
node_configs.each { |node_config| add_node(node_config) }
|
26
26
|
@subscribed_node = nil
|
27
|
+
@watch_key = nil
|
27
28
|
end
|
28
29
|
|
29
30
|
def node_for(key)
|
30
|
-
|
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)
|
31
35
|
end
|
32
36
|
|
33
37
|
def nodes
|
@@ -799,13 +803,26 @@ class Redis
|
|
799
803
|
end
|
800
804
|
|
801
805
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
802
|
-
def watch(*
|
803
|
-
|
806
|
+
def watch(*keys, &block)
|
807
|
+
ensure_same_node(:watch, keys) do |node|
|
808
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
809
|
+
|
810
|
+
begin
|
811
|
+
node.watch(*keys, &block)
|
812
|
+
rescue StandardError
|
813
|
+
@watch_key = nil
|
814
|
+
raise
|
815
|
+
end
|
816
|
+
end
|
804
817
|
end
|
805
818
|
|
806
819
|
# Forget about all watched keys.
|
807
820
|
def unwatch
|
808
|
-
raise CannotDistribute, :unwatch
|
821
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
822
|
+
|
823
|
+
result = node_for(@watch_key).unwatch
|
824
|
+
@watch_key = nil
|
825
|
+
result
|
809
826
|
end
|
810
827
|
|
811
828
|
def pipelined
|
@@ -813,18 +830,30 @@ class Redis
|
|
813
830
|
end
|
814
831
|
|
815
832
|
# Mark the start of a transaction block.
|
816
|
-
def multi
|
817
|
-
raise CannotDistribute, :multi
|
833
|
+
def multi(&block)
|
834
|
+
raise CannotDistribute, :multi unless @watch_key
|
835
|
+
|
836
|
+
result = node_for(@watch_key).multi(&block)
|
837
|
+
@watch_key = nil if block_given?
|
838
|
+
result
|
818
839
|
end
|
819
840
|
|
820
841
|
# Execute all commands issued after MULTI.
|
821
842
|
def exec
|
822
|
-
raise CannotDistribute, :exec
|
843
|
+
raise CannotDistribute, :exec unless @watch_key
|
844
|
+
|
845
|
+
result = node_for(@watch_key).exec
|
846
|
+
@watch_key = nil
|
847
|
+
result
|
823
848
|
end
|
824
849
|
|
825
850
|
# Discard all commands issued after MULTI.
|
826
851
|
def discard
|
827
|
-
raise CannotDistribute, :discard
|
852
|
+
raise CannotDistribute, :discard unless @watch_key
|
853
|
+
|
854
|
+
result = node_for(@watch_key).discard
|
855
|
+
@watch_key = nil
|
856
|
+
result
|
828
857
|
end
|
829
858
|
|
830
859
|
# Control remote script registry.
|
data/lib/redis/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.2.
|
4
|
+
version: 4.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -13,10 +13,10 @@ authors:
|
|
13
13
|
- Michel Martens
|
14
14
|
- Damian Janowski
|
15
15
|
- Pieter Noordhuis
|
16
|
-
autorequire:
|
16
|
+
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2020-
|
19
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: em-synchrony
|
@@ -99,8 +99,13 @@ files:
|
|
99
99
|
homepage: https://github.com/redis/redis-rb
|
100
100
|
licenses:
|
101
101
|
- MIT
|
102
|
-
metadata:
|
103
|
-
|
102
|
+
metadata:
|
103
|
+
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
104
|
+
changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
|
105
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/4.2.5
|
106
|
+
homepage_uri: https://github.com/redis/redis-rb
|
107
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v4.2.5
|
108
|
+
post_install_message:
|
104
109
|
rdoc_options: []
|
105
110
|
require_paths:
|
106
111
|
- lib
|
@@ -115,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
120
|
- !ruby/object:Gem::Version
|
116
121
|
version: '0'
|
117
122
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
119
|
-
signing_key:
|
123
|
+
rubygems_version: 3.1.2
|
124
|
+
signing_key:
|
120
125
|
specification_version: 4
|
121
126
|
summary: A Ruby client library for Redis
|
122
127
|
test_files: []
|