redis 4.0.0.rc1 → 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 +5 -5
- data/CHANGELOG.md +143 -3
- data/README.md +127 -18
- data/lib/redis/client.rb +150 -93
- data/lib/redis/cluster/command.rb +81 -0
- data/lib/redis/cluster/command_loader.rb +34 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +108 -0
- data/lib/redis/cluster/node_key.rb +31 -0
- data/lib/redis/cluster/node_loader.rb +37 -0
- data/lib/redis/cluster/option.rb +93 -0
- data/lib/redis/cluster/slot.rb +86 -0
- data/lib/redis/cluster/slot_loader.rb +49 -0
- data/lib/redis/cluster.rb +291 -0
- data/lib/redis/connection/command_helper.rb +3 -2
- data/lib/redis/connection/hiredis.rb +4 -3
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +123 -105
- data/lib/redis/connection/synchrony.rb +18 -5
- data/lib/redis/connection.rb +2 -0
- data/lib/redis/distributed.rb +955 -0
- data/lib/redis/errors.rb +48 -0
- data/lib/redis/hash_ring.rb +89 -0
- data/lib/redis/pipeline.rb +55 -9
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +1242 -381
- metadata +34 -141
- data/.gitignore +0 -16
- data/.travis/Gemfile +0 -11
- data/.travis.yml +0 -71
- data/.yardopts +0 -3
- data/Gemfile +0 -3
- data/benchmarking/logging.rb +0 -71
- data/benchmarking/pipeline.rb +0 -51
- data/benchmarking/speed.rb +0 -21
- data/benchmarking/suite.rb +0 -24
- data/benchmarking/worker.rb +0 -71
- data/examples/basic.rb +0 -15
- data/examples/consistency.rb +0 -114
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sentinel.rb +0 -41
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/makefile +0 -42
- data/redis.gemspec +0 -40
- data/test/bitpos_test.rb +0 -63
- data/test/blocking_commands_test.rb +0 -183
- data/test/client_test.rb +0 -59
- data/test/command_map_test.rb +0 -28
- data/test/commands_on_hashes_test.rb +0 -174
- data/test/commands_on_hyper_log_log_test.rb +0 -70
- data/test/commands_on_lists_test.rb +0 -154
- data/test/commands_on_sets_test.rb +0 -208
- data/test/commands_on_sorted_sets_test.rb +0 -444
- data/test/commands_on_strings_test.rb +0 -338
- data/test/commands_on_value_types_test.rb +0 -246
- data/test/connection_handling_test.rb +0 -275
- data/test/db/.gitkeep +0 -0
- data/test/encoding_test.rb +0 -14
- data/test/error_replies_test.rb +0 -57
- data/test/fork_safety_test.rb +0 -60
- data/test/helper.rb +0 -179
- data/test/helper_test.rb +0 -22
- data/test/internals_test.rb +0 -435
- data/test/persistence_control_commands_test.rb +0 -24
- data/test/pipelining_commands_test.rb +0 -238
- data/test/publish_subscribe_test.rb +0 -280
- data/test/remote_server_control_commands_test.rb +0 -175
- data/test/scanning_test.rb +0 -407
- data/test/scripting_test.rb +0 -76
- data/test/sentinel_command_test.rb +0 -78
- data/test/sentinel_test.rb +0 -253
- data/test/sorting_test.rb +0 -57
- data/test/ssl_test.rb +0 -69
- data/test/support/connection/hiredis.rb +0 -1
- data/test/support/connection/ruby.rb +0 -1
- data/test/support/connection/synchrony.rb +0 -17
- data/test/support/redis_mock.rb +0 -130
- data/test/support/ssl/gen_certs.sh +0 -31
- data/test/support/ssl/trusted-ca.crt +0 -25
- data/test/support/ssl/trusted-ca.key +0 -27
- data/test/support/ssl/trusted-cert.crt +0 -81
- data/test/support/ssl/trusted-cert.key +0 -28
- data/test/support/ssl/untrusted-ca.crt +0 -26
- data/test/support/ssl/untrusted-ca.key +0 -27
- data/test/support/ssl/untrusted-cert.crt +0 -82
- data/test/support/ssl/untrusted-cert.key +0 -28
- data/test/support/wire/synchrony.rb +0 -24
- data/test/support/wire/thread.rb +0 -5
- data/test/synchrony_driver.rb +0 -85
- data/test/test.conf.erb +0 -9
- data/test/thread_safety_test.rb +0 -60
- data/test/transactions_test.rb +0 -262
- data/test/unknown_commands_test.rb +0 -12
- data/test/url_param_test.rb +0 -136
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
module Connection
|
3
5
|
module CommandHelper
|
4
|
-
|
5
6
|
COMMAND_DELIMITER = "\r\n"
|
6
7
|
|
7
8
|
def build_command(args)
|
@@ -28,7 +29,7 @@ class Redis
|
|
28
29
|
command.join(COMMAND_DELIMITER)
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
+
protected
|
32
33
|
|
33
34
|
def encode(string)
|
34
35
|
string.force_encoding(Encoding.default_external)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "registry"
|
2
4
|
require_relative "../errors"
|
3
5
|
require "hiredis/connection"
|
@@ -6,7 +8,6 @@ require "timeout"
|
|
6
8
|
class Redis
|
7
9
|
module Connection
|
8
10
|
class Hiredis
|
9
|
-
|
10
11
|
def self.connect(config)
|
11
12
|
connection = ::Hiredis::Connection.new
|
12
13
|
connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
|
@@ -31,7 +32,7 @@ class Redis
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def connected?
|
34
|
-
@connection
|
35
|
+
@connection&.connected?
|
35
36
|
end
|
36
37
|
|
37
38
|
def timeout=(timeout)
|
@@ -57,7 +58,7 @@ class Redis
|
|
57
58
|
rescue Errno::EAGAIN
|
58
59
|
raise TimeoutError
|
59
60
|
rescue RuntimeError => err
|
60
|
-
raise ProtocolError
|
61
|
+
raise ProtocolError, err.message
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
module Connection
|
3
|
-
|
4
5
|
# Store a list of loaded connection drivers in the Connection module.
|
5
6
|
# Redis::Client uses the last required driver by default, and will be aware
|
6
7
|
# of the loaded connection drivers if the user chooses to override the
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "registry"
|
2
4
|
require_relative "command_helper"
|
3
5
|
require_relative "../errors"
|
@@ -13,108 +15,84 @@ end
|
|
13
15
|
class Redis
|
14
16
|
module Connection
|
15
17
|
module SocketMixin
|
16
|
-
|
17
|
-
CRLF = "\r\n".freeze
|
18
|
+
CRLF = "\r\n"
|
18
19
|
|
19
20
|
def initialize(*args)
|
20
21
|
super(*args)
|
21
22
|
|
22
23
|
@timeout = @write_timeout = nil
|
23
|
-
@buffer = ""
|
24
|
+
@buffer = "".dup
|
24
25
|
end
|
25
26
|
|
26
27
|
def timeout=(timeout)
|
27
|
-
if timeout && timeout > 0
|
28
|
-
@timeout = timeout
|
29
|
-
else
|
30
|
-
@timeout = nil
|
31
|
-
end
|
28
|
+
@timeout = (timeout if timeout && timeout > 0)
|
32
29
|
end
|
33
30
|
|
34
31
|
def write_timeout=(timeout)
|
35
|
-
if timeout && timeout > 0
|
36
|
-
@write_timeout = timeout
|
37
|
-
else
|
38
|
-
@write_timeout = nil
|
39
|
-
end
|
32
|
+
@write_timeout = (timeout if timeout && timeout > 0)
|
40
33
|
end
|
41
34
|
|
42
35
|
def read(nbytes)
|
43
36
|
result = @buffer.slice!(0, nbytes)
|
44
37
|
|
45
|
-
while result.bytesize < nbytes
|
46
|
-
result << _read_from_socket(nbytes - result.bytesize)
|
47
|
-
end
|
38
|
+
result << _read_from_socket(nbytes - result.bytesize) while result.bytesize < nbytes
|
48
39
|
|
49
40
|
result
|
50
41
|
end
|
51
42
|
|
52
43
|
def gets
|
53
|
-
crlf = nil
|
54
|
-
|
55
|
-
while (crlf = @buffer.index(CRLF)) == nil
|
56
|
-
@buffer << _read_from_socket(1024)
|
44
|
+
while (crlf = @buffer.index(CRLF)).nil?
|
45
|
+
@buffer << _read_from_socket(16_384)
|
57
46
|
end
|
58
47
|
|
59
48
|
@buffer.slice!(0, crlf + CRLF.bytesize)
|
60
49
|
end
|
61
50
|
|
62
51
|
def _read_from_socket(nbytes)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
raise Redis::TimeoutError
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
rescue EOFError
|
82
|
-
raise Errno::ECONNRESET
|
83
|
-
end
|
84
|
-
|
85
|
-
def _write_to_socket(data)
|
86
|
-
begin
|
87
|
-
write_nonblock(data)
|
88
|
-
|
89
|
-
rescue IO::WaitWritable
|
90
|
-
if IO.select(nil, [self], nil, @write_timeout)
|
91
|
-
retry
|
92
|
-
else
|
93
|
-
raise Redis::TimeoutError
|
94
|
-
end
|
95
|
-
rescue IO::WaitReadable
|
96
|
-
if IO.select([self], nil, nil, @write_timeout)
|
97
|
-
retry
|
98
|
-
else
|
99
|
-
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
|
100
66
|
end
|
101
67
|
end
|
102
|
-
|
103
|
-
rescue EOFError
|
104
|
-
raise Errno::ECONNRESET
|
105
68
|
end
|
106
69
|
|
107
|
-
def write(
|
108
|
-
return super(
|
70
|
+
def write(buffer)
|
71
|
+
return super(buffer) unless @write_timeout
|
109
72
|
|
110
|
-
|
111
|
-
|
73
|
+
bytes_to_write = buffer.bytesize
|
74
|
+
total_bytes_written = 0
|
112
75
|
loop do
|
113
|
-
|
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
|
89
|
+
|
90
|
+
if total_bytes_written >= bytes_to_write
|
91
|
+
return total_bytes_written
|
92
|
+
end
|
114
93
|
|
115
|
-
|
116
|
-
|
117
|
-
data = data.byteslice(count..-1)
|
94
|
+
buffer = buffer.byteslice(bytes_written..-1)
|
95
|
+
end
|
118
96
|
end
|
119
97
|
end
|
120
98
|
end
|
@@ -124,7 +102,6 @@ class Redis
|
|
124
102
|
require "timeout"
|
125
103
|
|
126
104
|
class TCPSocket < ::TCPSocket
|
127
|
-
|
128
105
|
include SocketMixin
|
129
106
|
|
130
107
|
def self.connect(host, port, timeout)
|
@@ -140,7 +117,6 @@ class Redis
|
|
140
117
|
if defined?(::UNIXSocket)
|
141
118
|
|
142
119
|
class UNIXSocket < ::UNIXSocket
|
143
|
-
|
144
120
|
include SocketMixin
|
145
121
|
|
146
122
|
def self.connect(path, timeout)
|
@@ -152,13 +128,12 @@ class Redis
|
|
152
128
|
raise TimeoutError
|
153
129
|
end
|
154
130
|
|
155
|
-
# JRuby raises Errno::EAGAIN on #read_nonblock even when
|
131
|
+
# JRuby raises Errno::EAGAIN on #read_nonblock even when it
|
156
132
|
# says it is readable (1.6.6, in both 1.8 and 1.9 mode).
|
157
133
|
# Use the blocking #readpartial method instead.
|
158
134
|
|
159
135
|
def _read_from_socket(nbytes)
|
160
136
|
readpartial(nbytes)
|
161
|
-
|
162
137
|
rescue EOFError
|
163
138
|
raise Errno::ECONNRESET
|
164
139
|
end
|
@@ -169,19 +144,16 @@ class Redis
|
|
169
144
|
else
|
170
145
|
|
171
146
|
class TCPSocket < ::Socket
|
172
|
-
|
173
147
|
include SocketMixin
|
174
148
|
|
175
|
-
def self.connect_addrinfo(
|
176
|
-
sock = new(::Socket.const_get(
|
177
|
-
sockaddr = ::Socket.pack_sockaddr_in(port,
|
149
|
+
def self.connect_addrinfo(addrinfo, port, timeout)
|
150
|
+
sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
|
151
|
+
sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
|
178
152
|
|
179
153
|
begin
|
180
154
|
sock.connect_nonblock(sockaddr)
|
181
155
|
rescue Errno::EINPROGRESS
|
182
|
-
|
183
|
-
raise TimeoutError
|
184
|
-
end
|
156
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
185
157
|
|
186
158
|
begin
|
187
159
|
sock.connect_nonblock(sockaddr)
|
@@ -220,14 +192,13 @@ class Redis
|
|
220
192
|
return connect_addrinfo(ai, port, timeout)
|
221
193
|
rescue SystemCallError
|
222
194
|
# Raise if this was our last attempt.
|
223
|
-
raise if addrinfo.length == i+1
|
195
|
+
raise if addrinfo.length == i + 1
|
224
196
|
end
|
225
197
|
end
|
226
198
|
end
|
227
199
|
end
|
228
200
|
|
229
201
|
class UNIXSocket < ::Socket
|
230
|
-
|
231
202
|
include SocketMixin
|
232
203
|
|
233
204
|
def self.connect(path, timeout)
|
@@ -237,9 +208,7 @@ class Redis
|
|
237
208
|
begin
|
238
209
|
sock.connect_nonblock(sockaddr)
|
239
210
|
rescue Errno::EINPROGRESS
|
240
|
-
|
241
|
-
raise TimeoutError
|
242
|
-
end
|
211
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
243
212
|
|
244
213
|
begin
|
245
214
|
sock.connect_nonblock(sockaddr)
|
@@ -257,17 +226,58 @@ class Redis
|
|
257
226
|
class SSLSocket < ::OpenSSL::SSL::SSLSocket
|
258
227
|
include SocketMixin
|
259
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
|
+
|
260
241
|
def self.connect(host, port, timeout, ssl_params)
|
261
242
|
# Note: this is using Redis::Connection::TCPSocket
|
262
243
|
tcp_sock = TCPSocket.connect(host, port, timeout)
|
263
244
|
|
264
245
|
ctx = OpenSSL::SSL::SSLContext.new
|
265
|
-
|
246
|
+
|
247
|
+
# The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
|
248
|
+
ctx.set_params(ssl_params || {})
|
266
249
|
|
267
250
|
ssl_sock = new(tcp_sock, ctx)
|
268
251
|
ssl_sock.hostname = host
|
269
|
-
|
270
|
-
|
252
|
+
|
253
|
+
begin
|
254
|
+
# Initiate the socket connection in the background. If it doesn't fail
|
255
|
+
# immediately it will raise an IO::WaitWritable (Errno::EINPROGRESS)
|
256
|
+
# indicating the connection is in progress.
|
257
|
+
# Unlike waiting for a tcp socket to connect, you can't time out ssl socket
|
258
|
+
# connections during the connect phase properly, because IO.select only partially works.
|
259
|
+
# Instead, you have to retry.
|
260
|
+
ssl_sock.connect_nonblock
|
261
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
262
|
+
if ssl_sock.wait_readable(timeout)
|
263
|
+
retry
|
264
|
+
else
|
265
|
+
raise TimeoutError
|
266
|
+
end
|
267
|
+
rescue IO::WaitWritable
|
268
|
+
if ssl_sock.wait_writable(timeout)
|
269
|
+
retry
|
270
|
+
else
|
271
|
+
raise TimeoutError
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
|
276
|
+
ctx.respond_to?(:verify_hostname) &&
|
277
|
+
!ctx.verify_hostname
|
278
|
+
)
|
279
|
+
ssl_sock.post_connection_check(host)
|
280
|
+
end
|
271
281
|
|
272
282
|
ssl_sock
|
273
283
|
end
|
@@ -277,15 +287,16 @@ class Redis
|
|
277
287
|
class Ruby
|
278
288
|
include Redis::Connection::CommandHelper
|
279
289
|
|
280
|
-
MINUS = "-"
|
281
|
-
PLUS = "+"
|
282
|
-
COLON = ":"
|
283
|
-
DOLLAR = "$"
|
284
|
-
ASTERISK = "*"
|
290
|
+
MINUS = "-"
|
291
|
+
PLUS = "+"
|
292
|
+
COLON = ":"
|
293
|
+
DOLLAR = "$"
|
294
|
+
ASTERISK = "*"
|
285
295
|
|
286
296
|
def self.connect(config)
|
287
297
|
if config[:scheme] == "unix"
|
288
298
|
raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
|
299
|
+
|
289
300
|
sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
|
290
301
|
elsif config[:scheme] == "rediss" || config[:ssl]
|
291
302
|
sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
|
@@ -294,13 +305,14 @@ class Redis
|
|
294
305
|
end
|
295
306
|
|
296
307
|
instance = new(sock)
|
297
|
-
instance.timeout = config[:
|
308
|
+
instance.timeout = config[:read_timeout]
|
298
309
|
instance.write_timeout = config[:write_timeout]
|
299
310
|
instance.set_tcp_keepalive config[:tcp_keepalive]
|
311
|
+
instance.set_tcp_nodelay if sock.is_a? TCPSocket
|
300
312
|
instance
|
301
313
|
end
|
302
314
|
|
303
|
-
if [
|
315
|
+
if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
|
304
316
|
def set_tcp_keepalive(keepalive)
|
305
317
|
return unless keepalive.is_a?(Hash)
|
306
318
|
|
@@ -312,14 +324,13 @@ class Redis
|
|
312
324
|
|
313
325
|
def get_tcp_keepalive
|
314
326
|
{
|
315
|
-
:
|
316
|
-
:
|
317
|
-
:
|
327
|
+
time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
|
328
|
+
intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
|
329
|
+
probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
|
318
330
|
}
|
319
331
|
end
|
320
332
|
else
|
321
|
-
def set_tcp_keepalive(keepalive)
|
322
|
-
end
|
333
|
+
def set_tcp_keepalive(keepalive); end
|
323
334
|
|
324
335
|
def get_tcp_keepalive
|
325
336
|
{
|
@@ -327,12 +338,21 @@ class Redis
|
|
327
338
|
end
|
328
339
|
end
|
329
340
|
|
341
|
+
# disables Nagle's Algorithm, prevents multiple round trips with MULTI
|
342
|
+
if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
|
343
|
+
def set_tcp_nodelay
|
344
|
+
@sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
345
|
+
end
|
346
|
+
else
|
347
|
+
def set_tcp_nodelay; end
|
348
|
+
end
|
349
|
+
|
330
350
|
def initialize(sock)
|
331
351
|
@sock = sock
|
332
352
|
end
|
333
353
|
|
334
354
|
def connected?
|
335
|
-
|
355
|
+
!!@sock
|
336
356
|
end
|
337
357
|
|
338
358
|
def disconnect
|
@@ -343,9 +363,7 @@ class Redis
|
|
343
363
|
end
|
344
364
|
|
345
365
|
def timeout=(timeout)
|
346
|
-
if @sock.respond_to?(:timeout=)
|
347
|
-
@sock.timeout = timeout
|
348
|
-
end
|
366
|
+
@sock.timeout = timeout if @sock.respond_to?(:timeout=)
|
349
367
|
end
|
350
368
|
|
351
369
|
def write_timeout=(timeout)
|
@@ -360,7 +378,6 @@ class Redis
|
|
360
378
|
line = @sock.gets
|
361
379
|
reply_type = line.slice!(0, 1)
|
362
380
|
format_reply(reply_type, line)
|
363
|
-
|
364
381
|
rescue Errno::EAGAIN
|
365
382
|
raise TimeoutError
|
366
383
|
end
|
@@ -372,7 +389,7 @@ class Redis
|
|
372
389
|
when COLON then format_integer_reply(line)
|
373
390
|
when DOLLAR then format_bulk_reply(line)
|
374
391
|
when ASTERISK then format_multi_bulk_reply(line)
|
375
|
-
else raise ProtocolError
|
392
|
+
else raise ProtocolError, reply_type
|
376
393
|
end
|
377
394
|
end
|
378
395
|
|
@@ -391,6 +408,7 @@ class Redis
|
|
391
408
|
def format_bulk_reply(line)
|
392
409
|
bulklen = line.to_i
|
393
410
|
return if bulklen == -1
|
411
|
+
|
394
412
|
reply = encode(@sock.read(bulklen))
|
395
413
|
@sock.read(2) # Discard CRLF.
|
396
414
|
reply
|
@@ -1,9 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "command_helper"
|
2
4
|
require_relative "registry"
|
3
5
|
require_relative "../errors"
|
4
6
|
require "em-synchrony"
|
5
7
|
require "hiredis/reader"
|
6
8
|
|
9
|
+
Kernel.warn(
|
10
|
+
"The redis synchrony driver is deprecated and will be removed in redis-rb 5.0. " \
|
11
|
+
"We're looking for people to maintain it as a separate gem, see https://github.com/redis/redis-rb/issues/915"
|
12
|
+
)
|
13
|
+
|
7
14
|
class Redis
|
8
15
|
module Connection
|
9
16
|
class RedisClient < EventMachine::Connection
|
@@ -46,9 +53,7 @@ class Redis
|
|
46
53
|
|
47
54
|
def read
|
48
55
|
@req = EventMachine::DefaultDeferrable.new
|
49
|
-
if @timeout > 0
|
50
|
-
@req.timeout(@timeout, :timeout)
|
51
|
-
end
|
56
|
+
@req.timeout(@timeout, :timeout) if @timeout > 0
|
52
57
|
EventMachine::Synchrony.sync @req
|
53
58
|
end
|
54
59
|
|
@@ -72,7 +77,15 @@ class Redis
|
|
72
77
|
|
73
78
|
def self.connect(config)
|
74
79
|
if config[:scheme] == "unix"
|
75
|
-
|
80
|
+
begin
|
81
|
+
conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
|
82
|
+
rescue RuntimeError => e
|
83
|
+
if e.message == "no connection"
|
84
|
+
raise Errno::ECONNREFUSED
|
85
|
+
else
|
86
|
+
raise e
|
87
|
+
end
|
88
|
+
end
|
76
89
|
elsif config[:scheme] == "rediss" || config[:ssl]
|
77
90
|
raise NotImplementedError, "SSL not supported by synchrony driver"
|
78
91
|
else
|
@@ -97,7 +110,7 @@ class Redis
|
|
97
110
|
end
|
98
111
|
|
99
112
|
def connected?
|
100
|
-
@connection
|
113
|
+
@connection&.connected?
|
101
114
|
end
|
102
115
|
|
103
116
|
def timeout=(timeout)
|