redis 4.2.0 → 4.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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: []
|