redis 4.1.4 → 4.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "connection/registry"
3
4
 
4
5
  # If a connection driver was required before this file, the array
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  module Connection
4
5
  module CommandHelper
5
-
6
6
  COMMAND_DELIMITER = "\r\n"
7
7
 
8
8
  def build_command(args)
@@ -29,7 +29,7 @@ class Redis
29
29
  command.join(COMMAND_DELIMITER)
30
30
  end
31
31
 
32
- protected
32
+ protected
33
33
 
34
34
  def encode(string)
35
35
  string.force_encoding(Encoding.default_external)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "registry"
3
4
  require_relative "../errors"
4
5
  require "hiredis/connection"
@@ -7,7 +8,6 @@ require "timeout"
7
8
  class Redis
8
9
  module Connection
9
10
  class Hiredis
10
-
11
11
  def self.connect(config)
12
12
  connection = ::Hiredis::Connection.new
13
13
  connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
@@ -32,7 +32,7 @@ class Redis
32
32
  end
33
33
 
34
34
  def connected?
35
- @connection && @connection.connected?
35
+ @connection&.connected?
36
36
  end
37
37
 
38
38
  def timeout=(timeout)
@@ -58,7 +58,7 @@ class Redis
58
58
  rescue Errno::EAGAIN
59
59
  raise TimeoutError
60
60
  rescue RuntimeError => err
61
- raise ProtocolError.new(err.message)
61
+ raise ProtocolError, err.message
62
62
  end
63
63
  end
64
64
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  module Connection
4
-
5
5
  # Store a list of loaded connection drivers in the Connection module.
6
6
  # Redis::Client uses the last required driver by default, and will be aware
7
7
  # of the loaded connection drivers if the user chooses to override the
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "registry"
3
4
  require_relative "command_helper"
4
5
  require_relative "../errors"
@@ -14,8 +15,7 @@ end
14
15
  class Redis
15
16
  module Connection
16
17
  module SocketMixin
17
-
18
- CRLF = "\r\n".freeze
18
+ CRLF = "\r\n"
19
19
 
20
20
  def initialize(*args)
21
21
  super(*args)
@@ -25,89 +25,77 @@ class Redis
25
25
  end
26
26
 
27
27
  def timeout=(timeout)
28
- if timeout && timeout > 0
29
- @timeout = timeout
30
- else
31
- @timeout = nil
32
- end
28
+ @timeout = (timeout if timeout && timeout > 0)
33
29
  end
34
30
 
35
31
  def write_timeout=(timeout)
36
- if timeout && timeout > 0
37
- @write_timeout = timeout
38
- else
39
- @write_timeout = nil
40
- end
32
+ @write_timeout = (timeout if timeout && timeout > 0)
41
33
  end
42
34
 
43
35
  def read(nbytes)
44
36
  result = @buffer.slice!(0, nbytes)
45
37
 
46
- while result.bytesize < nbytes
47
- result << _read_from_socket(nbytes - result.bytesize)
48
- end
38
+ result << _read_from_socket(nbytes - result.bytesize) while result.bytesize < nbytes
49
39
 
50
40
  result
51
41
  end
52
42
 
53
43
  def gets
54
- crlf = nil
55
-
56
- while (crlf = @buffer.index(CRLF)) == nil
57
- @buffer << _read_from_socket(16384)
44
+ while (crlf = @buffer.index(CRLF)).nil?
45
+ @buffer << _read_from_socket(16_384)
58
46
  end
59
47
 
60
48
  @buffer.slice!(0, crlf + CRLF.bytesize)
61
49
  end
62
50
 
63
51
  def _read_from_socket(nbytes)
64
-
65
- begin
66
- read_nonblock(nbytes)
67
-
68
- rescue IO::WaitReadable
69
- if IO.select([self], nil, nil, @timeout)
70
- retry
71
- else
72
- raise Redis::TimeoutError
73
- end
74
- rescue IO::WaitWritable
75
- if IO.select(nil, [self], nil, @timeout)
76
- retry
77
- else
78
- 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
79
66
  end
80
67
  end
81
-
82
- rescue EOFError
83
- raise Errno::ECONNRESET
84
68
  end
85
69
 
86
70
  def _write_to_socket(data)
87
- begin
88
- write_nonblock(data)
89
-
90
- rescue IO::WaitWritable
91
- if IO.select(nil, [self], nil, @write_timeout)
92
- retry
93
- else
94
- raise Redis::TimeoutError
95
- end
96
- rescue IO::WaitReadable
97
- if IO.select([self], nil, nil, @write_timeout)
98
- retry
99
- else
100
- raise Redis::TimeoutError
71
+ total_bytes_written = 0
72
+ loop do
73
+ case bytes_written = write_nonblock(data, exception: false)
74
+ when :wait_readable
75
+ unless wait_readable(@write_timeout)
76
+ raise Redis::TimeoutError
77
+ end
78
+ when :wait_writable
79
+ unless wait_writable(@write_timeout)
80
+ raise Redis::TimeoutError
81
+ end
82
+ when nil
83
+ raise Errno::ECONNRESET
84
+ when Integer
85
+ total_bytes_written += bytes_written
86
+ if bytes_written < data.bytesize
87
+ data.slice!(0, bytes_written)
88
+ else
89
+ return total_bytes_written
90
+ end
101
91
  end
102
92
  end
103
-
104
- rescue EOFError
105
- raise Errno::ECONNRESET
106
93
  end
107
94
 
108
95
  def write(data)
109
96
  return super(data) unless @write_timeout
110
97
 
98
+ data = data.b
111
99
  length = data.bytesize
112
100
  total_count = 0
113
101
  loop do
@@ -115,6 +103,7 @@ class Redis
115
103
 
116
104
  total_count += count
117
105
  return total_count if total_count >= length
106
+
118
107
  data = data.byteslice(count..-1)
119
108
  end
120
109
  end
@@ -125,7 +114,6 @@ class Redis
125
114
  require "timeout"
126
115
 
127
116
  class TCPSocket < ::TCPSocket
128
-
129
117
  include SocketMixin
130
118
 
131
119
  def self.connect(host, port, timeout)
@@ -141,7 +129,6 @@ class Redis
141
129
  if defined?(::UNIXSocket)
142
130
 
143
131
  class UNIXSocket < ::UNIXSocket
144
-
145
132
  include SocketMixin
146
133
 
147
134
  def self.connect(path, timeout)
@@ -153,13 +140,12 @@ class Redis
153
140
  raise TimeoutError
154
141
  end
155
142
 
156
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
143
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
157
144
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
158
145
  # Use the blocking #readpartial method instead.
159
146
 
160
147
  def _read_from_socket(nbytes)
161
148
  readpartial(nbytes)
162
-
163
149
  rescue EOFError
164
150
  raise Errno::ECONNRESET
165
151
  end
@@ -170,19 +156,16 @@ class Redis
170
156
  else
171
157
 
172
158
  class TCPSocket < ::Socket
173
-
174
159
  include SocketMixin
175
160
 
176
- def self.connect_addrinfo(ai, port, timeout)
177
- sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
178
- sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
161
+ def self.connect_addrinfo(addrinfo, port, timeout)
162
+ sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
163
+ sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
179
164
 
180
165
  begin
181
166
  sock.connect_nonblock(sockaddr)
182
167
  rescue Errno::EINPROGRESS
183
- if IO.select(nil, [sock], nil, timeout) == nil
184
- raise TimeoutError
185
- end
168
+ raise TimeoutError unless sock.wait_writable(timeout)
186
169
 
187
170
  begin
188
171
  sock.connect_nonblock(sockaddr)
@@ -221,14 +204,13 @@ class Redis
221
204
  return connect_addrinfo(ai, port, timeout)
222
205
  rescue SystemCallError
223
206
  # Raise if this was our last attempt.
224
- raise if addrinfo.length == i+1
207
+ raise if addrinfo.length == i + 1
225
208
  end
226
209
  end
227
210
  end
228
211
  end
229
212
 
230
213
  class UNIXSocket < ::Socket
231
-
232
214
  include SocketMixin
233
215
 
234
216
  def self.connect(path, timeout)
@@ -238,9 +220,7 @@ class Redis
238
220
  begin
239
221
  sock.connect_nonblock(sockaddr)
240
222
  rescue Errno::EINPROGRESS
241
- if IO.select(nil, [sock], nil, timeout) == nil
242
- raise TimeoutError
243
- end
223
+ raise TimeoutError unless sock.wait_writable(timeout)
244
224
 
245
225
  begin
246
226
  sock.connect_nonblock(sockaddr)
@@ -258,12 +238,26 @@ class Redis
258
238
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
259
239
  include SocketMixin
260
240
 
241
+ unless method_defined?(:wait_readable)
242
+ def wait_readable(timeout = nil)
243
+ to_io.wait_readable(timeout)
244
+ end
245
+ end
246
+
247
+ unless method_defined?(:wait_writable)
248
+ def wait_writable(timeout = nil)
249
+ to_io.wait_writable(timeout)
250
+ end
251
+ end
252
+
261
253
  def self.connect(host, port, timeout, ssl_params)
262
254
  # Note: this is using Redis::Connection::TCPSocket
263
255
  tcp_sock = TCPSocket.connect(host, port, timeout)
264
256
 
265
257
  ctx = OpenSSL::SSL::SSLContext.new
266
- ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
258
+
259
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
260
+ ctx.set_params(ssl_params || {})
267
261
 
268
262
  ssl_sock = new(tcp_sock, ctx)
269
263
  ssl_sock.hostname = host
@@ -277,20 +271,23 @@ class Redis
277
271
  # Instead, you have to retry.
278
272
  ssl_sock.connect_nonblock
279
273
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
280
- if IO.select([ssl_sock], nil, nil, timeout)
274
+ if ssl_sock.wait_readable(timeout)
281
275
  retry
282
276
  else
283
277
  raise TimeoutError
284
278
  end
285
279
  rescue IO::WaitWritable
286
- if IO.select(nil, [ssl_sock], nil, timeout)
280
+ if ssl_sock.wait_writable(timeout)
287
281
  retry
288
282
  else
289
283
  raise TimeoutError
290
284
  end
291
285
  end
292
286
 
293
- unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (ctx.respond_to?(:verify_hostname) && !ctx.verify_hostname)
287
+ unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
288
+ ctx.respond_to?(:verify_hostname) &&
289
+ !ctx.verify_hostname
290
+ )
294
291
  ssl_sock.post_connection_check(host)
295
292
  end
296
293
 
@@ -302,15 +299,16 @@ class Redis
302
299
  class Ruby
303
300
  include Redis::Connection::CommandHelper
304
301
 
305
- MINUS = "-".freeze
306
- PLUS = "+".freeze
307
- COLON = ":".freeze
308
- DOLLAR = "$".freeze
309
- ASTERISK = "*".freeze
302
+ MINUS = "-"
303
+ PLUS = "+"
304
+ COLON = ":"
305
+ DOLLAR = "$"
306
+ ASTERISK = "*"
310
307
 
311
308
  def self.connect(config)
312
309
  if config[:scheme] == "unix"
313
310
  raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
311
+
314
312
  sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
315
313
  elsif config[:scheme] == "rediss" || config[:ssl]
316
314
  sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
@@ -326,7 +324,7 @@ class Redis
326
324
  instance
327
325
  end
328
326
 
329
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
327
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
330
328
  def set_tcp_keepalive(keepalive)
331
329
  return unless keepalive.is_a?(Hash)
332
330
 
@@ -338,14 +336,13 @@ class Redis
338
336
 
339
337
  def get_tcp_keepalive
340
338
  {
341
- :time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
342
- :intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
343
- :probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
339
+ time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
340
+ intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
341
+ probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
344
342
  }
345
343
  end
346
344
  else
347
- def set_tcp_keepalive(keepalive)
348
- end
345
+ def set_tcp_keepalive(keepalive); end
349
346
 
350
347
  def get_tcp_keepalive
351
348
  {
@@ -354,13 +351,12 @@ class Redis
354
351
  end
355
352
 
356
353
  # disables Nagle's Algorithm, prevents multiple round trips with MULTI
357
- if [:IPPROTO_TCP, :TCP_NODELAY].all?{|c| Socket.const_defined? c}
354
+ if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
358
355
  def set_tcp_nodelay
359
356
  @sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
360
357
  end
361
358
  else
362
- def set_tcp_nodelay
363
- end
359
+ def set_tcp_nodelay; end
364
360
  end
365
361
 
366
362
  def initialize(sock)
@@ -368,7 +364,7 @@ class Redis
368
364
  end
369
365
 
370
366
  def connected?
371
- !! @sock
367
+ !!@sock
372
368
  end
373
369
 
374
370
  def disconnect
@@ -379,9 +375,7 @@ class Redis
379
375
  end
380
376
 
381
377
  def timeout=(timeout)
382
- if @sock.respond_to?(:timeout=)
383
- @sock.timeout = timeout
384
- end
378
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
385
379
  end
386
380
 
387
381
  def write_timeout=(timeout)
@@ -396,7 +390,6 @@ class Redis
396
390
  line = @sock.gets
397
391
  reply_type = line.slice!(0, 1)
398
392
  format_reply(reply_type, line)
399
-
400
393
  rescue Errno::EAGAIN
401
394
  raise TimeoutError
402
395
  end
@@ -408,7 +401,7 @@ class Redis
408
401
  when COLON then format_integer_reply(line)
409
402
  when DOLLAR then format_bulk_reply(line)
410
403
  when ASTERISK then format_multi_bulk_reply(line)
411
- else raise ProtocolError.new(reply_type)
404
+ else raise ProtocolError, reply_type
412
405
  end
413
406
  end
414
407
 
@@ -427,6 +420,7 @@ class Redis
427
420
  def format_bulk_reply(line)
428
421
  bulklen = line.to_i
429
422
  return if bulklen == -1
423
+
430
424
  reply = encode(@sock.read(bulklen))
431
425
  @sock.read(2) # Discard CRLF.
432
426
  reply