redis 3.3.5 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +132 -2
  3. data/README.md +144 -79
  4. data/lib/redis.rb +1174 -405
  5. data/lib/redis/client.rb +150 -90
  6. data/lib/redis/cluster.rb +295 -0
  7. data/lib/redis/cluster/command.rb +81 -0
  8. data/lib/redis/cluster/command_loader.rb +34 -0
  9. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  10. data/lib/redis/cluster/node.rb +107 -0
  11. data/lib/redis/cluster/node_key.rb +31 -0
  12. data/lib/redis/cluster/node_loader.rb +37 -0
  13. data/lib/redis/cluster/option.rb +93 -0
  14. data/lib/redis/cluster/slot.rb +86 -0
  15. data/lib/redis/cluster/slot_loader.rb +49 -0
  16. data/lib/redis/connection.rb +4 -2
  17. data/lib/redis/connection/command_helper.rb +5 -10
  18. data/lib/redis/connection/hiredis.rb +6 -5
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +126 -128
  21. data/lib/redis/connection/synchrony.rb +21 -8
  22. data/lib/redis/distributed.rb +147 -72
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +30 -73
  25. data/lib/redis/pipeline.rb +55 -15
  26. data/lib/redis/subscribe.rb +11 -12
  27. data/lib/redis/version.rb +3 -1
  28. metadata +49 -202
  29. data/.gitignore +0 -16
  30. data/.travis.yml +0 -89
  31. data/.travis/Gemfile +0 -11
  32. data/.yardopts +0 -3
  33. data/Gemfile +0 -4
  34. data/Rakefile +0 -87
  35. data/benchmarking/logging.rb +0 -71
  36. data/benchmarking/pipeline.rb +0 -51
  37. data/benchmarking/speed.rb +0 -21
  38. data/benchmarking/suite.rb +0 -24
  39. data/benchmarking/worker.rb +0 -71
  40. data/examples/basic.rb +0 -15
  41. data/examples/consistency.rb +0 -114
  42. data/examples/dist_redis.rb +0 -43
  43. data/examples/incr-decr.rb +0 -17
  44. data/examples/list.rb +0 -26
  45. data/examples/pubsub.rb +0 -37
  46. data/examples/sentinel.rb +0 -41
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sets.rb +0 -36
  50. data/examples/unicorn/config.ru +0 -3
  51. data/examples/unicorn/unicorn.rb +0 -20
  52. data/redis.gemspec +0 -44
  53. data/test/bitpos_test.rb +0 -69
  54. data/test/blocking_commands_test.rb +0 -42
  55. data/test/client_test.rb +0 -59
  56. data/test/command_map_test.rb +0 -30
  57. data/test/commands_on_hashes_test.rb +0 -21
  58. data/test/commands_on_hyper_log_log_test.rb +0 -21
  59. data/test/commands_on_lists_test.rb +0 -20
  60. data/test/commands_on_sets_test.rb +0 -77
  61. data/test/commands_on_sorted_sets_test.rb +0 -137
  62. data/test/commands_on_strings_test.rb +0 -101
  63. data/test/commands_on_value_types_test.rb +0 -133
  64. data/test/connection_handling_test.rb +0 -277
  65. data/test/connection_test.rb +0 -57
  66. data/test/db/.gitkeep +0 -0
  67. data/test/distributed_blocking_commands_test.rb +0 -46
  68. data/test/distributed_commands_on_hashes_test.rb +0 -10
  69. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  70. data/test/distributed_commands_on_lists_test.rb +0 -22
  71. data/test/distributed_commands_on_sets_test.rb +0 -83
  72. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  73. data/test/distributed_commands_on_strings_test.rb +0 -59
  74. data/test/distributed_commands_on_value_types_test.rb +0 -95
  75. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  76. data/test/distributed_connection_handling_test.rb +0 -23
  77. data/test/distributed_internals_test.rb +0 -79
  78. data/test/distributed_key_tags_test.rb +0 -52
  79. data/test/distributed_persistence_control_commands_test.rb +0 -26
  80. data/test/distributed_publish_subscribe_test.rb +0 -92
  81. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  82. data/test/distributed_scripting_test.rb +0 -102
  83. data/test/distributed_sorting_test.rb +0 -20
  84. data/test/distributed_test.rb +0 -58
  85. data/test/distributed_transactions_test.rb +0 -32
  86. data/test/encoding_test.rb +0 -18
  87. data/test/error_replies_test.rb +0 -59
  88. data/test/fork_safety_test.rb +0 -65
  89. data/test/helper.rb +0 -232
  90. data/test/helper_test.rb +0 -24
  91. data/test/internals_test.rb +0 -417
  92. data/test/lint/blocking_commands.rb +0 -150
  93. data/test/lint/hashes.rb +0 -162
  94. data/test/lint/hyper_log_log.rb +0 -60
  95. data/test/lint/lists.rb +0 -143
  96. data/test/lint/sets.rb +0 -140
  97. data/test/lint/sorted_sets.rb +0 -316
  98. data/test/lint/strings.rb +0 -260
  99. data/test/lint/value_types.rb +0 -122
  100. data/test/persistence_control_commands_test.rb +0 -26
  101. data/test/pipelining_commands_test.rb +0 -242
  102. data/test/publish_subscribe_test.rb +0 -282
  103. data/test/remote_server_control_commands_test.rb +0 -118
  104. data/test/scanning_test.rb +0 -413
  105. data/test/scripting_test.rb +0 -78
  106. data/test/sentinel_command_test.rb +0 -80
  107. data/test/sentinel_test.rb +0 -255
  108. data/test/sorting_test.rb +0 -59
  109. data/test/ssl_test.rb +0 -73
  110. data/test/support/connection/hiredis.rb +0 -1
  111. data/test/support/connection/ruby.rb +0 -1
  112. data/test/support/connection/synchrony.rb +0 -17
  113. data/test/support/redis_mock.rb +0 -130
  114. data/test/support/ssl/gen_certs.sh +0 -31
  115. data/test/support/ssl/trusted-ca.crt +0 -25
  116. data/test/support/ssl/trusted-ca.key +0 -27
  117. data/test/support/ssl/trusted-cert.crt +0 -81
  118. data/test/support/ssl/trusted-cert.key +0 -28
  119. data/test/support/ssl/untrusted-ca.crt +0 -26
  120. data/test/support/ssl/untrusted-ca.key +0 -27
  121. data/test/support/ssl/untrusted-cert.crt +0 -82
  122. data/test/support/ssl/untrusted-cert.key +0 -28
  123. data/test/support/wire/synchrony.rb +0 -24
  124. data/test/support/wire/thread.rb +0 -5
  125. data/test/synchrony_driver.rb +0 -88
  126. data/test/test.conf.erb +0 -9
  127. data/test/thread_safety_test.rb +0 -62
  128. data/test/transactions_test.rb +0 -264
  129. data/test/unknown_commands_test.rb +0 -14
  130. data/test/url_param_test.rb +0 -138
@@ -1,12 +1,13 @@
1
- require "redis/connection/registry"
2
- require "redis/errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "registry"
4
+ require_relative "../errors"
3
5
  require "hiredis/connection"
4
6
  require "timeout"
5
7
 
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 && @connection.connected?
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.new(err.message)
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,6 +1,8 @@
1
- require "redis/connection/registry"
2
- require "redis/connection/command_helper"
3
- require "redis/errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "registry"
4
+ require_relative "command_helper"
5
+ require_relative "../errors"
4
6
  require "socket"
5
7
  require "timeout"
6
8
 
@@ -10,130 +12,87 @@ rescue LoadError
10
12
  # Not all systems have OpenSSL support
11
13
  end
12
14
 
13
- if RUBY_VERSION < "1.9.3"
14
- class String
15
- # Ruby 1.8.7 does not have byteslice, but it handles encodings differently anyway.
16
- # We can simply slice the string, which is a byte array there.
17
- def byteslice(*args)
18
- slice(*args)
19
- end
20
- end
21
- end
22
-
23
15
  class Redis
24
16
  module Connection
25
17
  module SocketMixin
26
-
27
- CRLF = "\r\n".freeze
28
-
29
- # Exceptions raised during non-blocking I/O ops that require retrying the op
30
- if RUBY_VERSION >= "1.9.3"
31
- NBIO_READ_EXCEPTIONS = [IO::WaitReadable]
32
- NBIO_WRITE_EXCEPTIONS = [IO::WaitWritable]
33
- else
34
- NBIO_READ_EXCEPTIONS = [Errno::EWOULDBLOCK, Errno::EAGAIN]
35
- NBIO_WRITE_EXCEPTIONS = [Errno::EWOULDBLOCK, Errno::EAGAIN]
36
- end
18
+ CRLF = "\r\n"
37
19
 
38
20
  def initialize(*args)
39
21
  super(*args)
40
22
 
41
23
  @timeout = @write_timeout = nil
42
- @buffer = ""
24
+ @buffer = "".dup
43
25
  end
44
26
 
45
27
  def timeout=(timeout)
46
- if timeout && timeout > 0
47
- @timeout = timeout
48
- else
49
- @timeout = nil
50
- end
28
+ @timeout = (timeout if timeout && timeout > 0)
51
29
  end
52
30
 
53
31
  def write_timeout=(timeout)
54
- if timeout && timeout > 0
55
- @write_timeout = timeout
56
- else
57
- @write_timeout = nil
58
- end
32
+ @write_timeout = (timeout if timeout && timeout > 0)
59
33
  end
60
34
 
61
35
  def read(nbytes)
62
36
  result = @buffer.slice!(0, nbytes)
63
37
 
64
- while result.bytesize < nbytes
65
- result << _read_from_socket(nbytes - result.bytesize)
66
- end
38
+ result << _read_from_socket(nbytes - result.bytesize) while result.bytesize < nbytes
67
39
 
68
40
  result
69
41
  end
70
42
 
71
43
  def gets
72
- crlf = nil
73
-
74
- while (crlf = @buffer.index(CRLF)) == nil
75
- @buffer << _read_from_socket(1024)
44
+ while (crlf = @buffer.index(CRLF)).nil?
45
+ @buffer << _read_from_socket(16_384)
76
46
  end
77
47
 
78
48
  @buffer.slice!(0, crlf + CRLF.bytesize)
79
49
  end
80
50
 
81
51
  def _read_from_socket(nbytes)
82
-
83
- begin
84
- read_nonblock(nbytes)
85
-
86
- rescue *NBIO_READ_EXCEPTIONS
87
- if IO.select([self], nil, nil, @timeout)
88
- retry
89
- else
90
- raise Redis::TimeoutError
91
- end
92
- rescue *NBIO_WRITE_EXCEPTIONS
93
- if IO.select(nil, [self], nil, @timeout)
94
- retry
95
- else
96
- raise Redis::TimeoutError
97
- end
98
- end
99
-
100
- rescue EOFError
101
- raise Errno::ECONNRESET
102
- end
103
-
104
- def _write_to_socket(data)
105
- begin
106
- write_nonblock(data)
107
-
108
- rescue *NBIO_WRITE_EXCEPTIONS
109
- if IO.select(nil, [self], nil, @write_timeout)
110
- retry
111
- else
112
- raise Redis::TimeoutError
113
- end
114
- rescue *NBIO_READ_EXCEPTIONS
115
- if IO.select([self], nil, nil, @write_timeout)
116
- retry
117
- else
118
- 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
119
66
  end
120
67
  end
121
-
122
- rescue EOFError
123
- raise Errno::ECONNRESET
124
68
  end
125
69
 
126
- def write(data)
127
- return super(data) unless @write_timeout
70
+ def write(buffer)
71
+ return super(buffer) unless @write_timeout
128
72
 
129
- length = data.bytesize
130
- total_count = 0
73
+ bytes_to_write = buffer.bytesize
74
+ total_bytes_written = 0
131
75
  loop do
132
- count = _write_to_socket(data)
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
133
93
 
134
- total_count += count
135
- return total_count if total_count >= length
136
- data = data.byteslice(count..-1)
94
+ buffer = buffer.byteslice(bytes_written..-1)
95
+ end
137
96
  end
138
97
  end
139
98
  end
@@ -143,7 +102,6 @@ class Redis
143
102
  require "timeout"
144
103
 
145
104
  class TCPSocket < ::TCPSocket
146
-
147
105
  include SocketMixin
148
106
 
149
107
  def self.connect(host, port, timeout)
@@ -159,7 +117,6 @@ class Redis
159
117
  if defined?(::UNIXSocket)
160
118
 
161
119
  class UNIXSocket < ::UNIXSocket
162
-
163
120
  include SocketMixin
164
121
 
165
122
  def self.connect(path, timeout)
@@ -171,13 +128,12 @@ class Redis
171
128
  raise TimeoutError
172
129
  end
173
130
 
174
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
131
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
175
132
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
176
133
  # Use the blocking #readpartial method instead.
177
134
 
178
135
  def _read_from_socket(nbytes)
179
136
  readpartial(nbytes)
180
-
181
137
  rescue EOFError
182
138
  raise Errno::ECONNRESET
183
139
  end
@@ -188,19 +144,16 @@ class Redis
188
144
  else
189
145
 
190
146
  class TCPSocket < ::Socket
191
-
192
147
  include SocketMixin
193
148
 
194
- def self.connect_addrinfo(ai, port, timeout)
195
- sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
196
- sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
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])
197
152
 
198
153
  begin
199
154
  sock.connect_nonblock(sockaddr)
200
155
  rescue Errno::EINPROGRESS
201
- if IO.select(nil, [sock], nil, timeout) == nil
202
- raise TimeoutError
203
- end
156
+ raise TimeoutError unless sock.wait_writable(timeout)
204
157
 
205
158
  begin
206
159
  sock.connect_nonblock(sockaddr)
@@ -239,14 +192,13 @@ class Redis
239
192
  return connect_addrinfo(ai, port, timeout)
240
193
  rescue SystemCallError
241
194
  # Raise if this was our last attempt.
242
- raise if addrinfo.length == i+1
195
+ raise if addrinfo.length == i + 1
243
196
  end
244
197
  end
245
198
  end
246
199
  end
247
200
 
248
201
  class UNIXSocket < ::Socket
249
-
250
202
  include SocketMixin
251
203
 
252
204
  def self.connect(path, timeout)
@@ -256,9 +208,7 @@ class Redis
256
208
  begin
257
209
  sock.connect_nonblock(sockaddr)
258
210
  rescue Errno::EINPROGRESS
259
- if IO.select(nil, [sock], nil, timeout) == nil
260
- raise TimeoutError
261
- end
211
+ raise TimeoutError unless sock.wait_writable(timeout)
262
212
 
263
213
  begin
264
214
  sock.connect_nonblock(sockaddr)
@@ -276,17 +226,58 @@ class Redis
276
226
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
277
227
  include SocketMixin
278
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
+
279
241
  def self.connect(host, port, timeout, ssl_params)
280
242
  # Note: this is using Redis::Connection::TCPSocket
281
243
  tcp_sock = TCPSocket.connect(host, port, timeout)
282
244
 
283
245
  ctx = OpenSSL::SSL::SSLContext.new
284
- ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
246
+
247
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
248
+ ctx.set_params(ssl_params || {})
285
249
 
286
250
  ssl_sock = new(tcp_sock, ctx)
287
251
  ssl_sock.hostname = host
288
- ssl_sock.connect
289
- ssl_sock.post_connection_check(host)
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
290
281
 
291
282
  ssl_sock
292
283
  end
@@ -296,31 +287,32 @@ class Redis
296
287
  class Ruby
297
288
  include Redis::Connection::CommandHelper
298
289
 
299
- MINUS = "-".freeze
300
- PLUS = "+".freeze
301
- COLON = ":".freeze
302
- DOLLAR = "$".freeze
303
- ASTERISK = "*".freeze
290
+ MINUS = "-"
291
+ PLUS = "+"
292
+ COLON = ":"
293
+ DOLLAR = "$"
294
+ ASTERISK = "*"
304
295
 
305
296
  def self.connect(config)
306
297
  if config[:scheme] == "unix"
307
298
  raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
299
+
308
300
  sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
309
301
  elsif config[:scheme] == "rediss" || config[:ssl]
310
- raise ArgumentError, "This library does not support SSL on Ruby < 1.9" if RUBY_VERSION < "1.9.3"
311
302
  sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
312
303
  else
313
304
  sock = TCPSocket.connect(config[:host], config[:port], config[:connect_timeout])
314
305
  end
315
306
 
316
307
  instance = new(sock)
317
- instance.timeout = config[:timeout]
308
+ instance.timeout = config[:read_timeout]
318
309
  instance.write_timeout = config[:write_timeout]
319
310
  instance.set_tcp_keepalive config[:tcp_keepalive]
311
+ instance.set_tcp_nodelay if sock.is_a? TCPSocket
320
312
  instance
321
313
  end
322
314
 
323
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
315
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
324
316
  def set_tcp_keepalive(keepalive)
325
317
  return unless keepalive.is_a?(Hash)
326
318
 
@@ -332,14 +324,13 @@ class Redis
332
324
 
333
325
  def get_tcp_keepalive
334
326
  {
335
- :time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
336
- :intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
337
- :probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
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
338
330
  }
339
331
  end
340
332
  else
341
- def set_tcp_keepalive(keepalive)
342
- end
333
+ def set_tcp_keepalive(keepalive); end
343
334
 
344
335
  def get_tcp_keepalive
345
336
  {
@@ -347,12 +338,21 @@ class Redis
347
338
  end
348
339
  end
349
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
+
350
350
  def initialize(sock)
351
351
  @sock = sock
352
352
  end
353
353
 
354
354
  def connected?
355
- !! @sock
355
+ !!@sock
356
356
  end
357
357
 
358
358
  def disconnect
@@ -363,9 +363,7 @@ class Redis
363
363
  end
364
364
 
365
365
  def timeout=(timeout)
366
- if @sock.respond_to?(:timeout=)
367
- @sock.timeout = timeout
368
- end
366
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
369
367
  end
370
368
 
371
369
  def write_timeout=(timeout)
@@ -380,7 +378,6 @@ class Redis
380
378
  line = @sock.gets
381
379
  reply_type = line.slice!(0, 1)
382
380
  format_reply(reply_type, line)
383
-
384
381
  rescue Errno::EAGAIN
385
382
  raise TimeoutError
386
383
  end
@@ -392,7 +389,7 @@ class Redis
392
389
  when COLON then format_integer_reply(line)
393
390
  when DOLLAR then format_bulk_reply(line)
394
391
  when ASTERISK then format_multi_bulk_reply(line)
395
- else raise ProtocolError.new(reply_type)
392
+ else raise ProtocolError, reply_type
396
393
  end
397
394
  end
398
395
 
@@ -411,6 +408,7 @@ class Redis
411
408
  def format_bulk_reply(line)
412
409
  bulklen = line.to_i
413
410
  return if bulklen == -1
411
+
414
412
  reply = encode(@sock.read(bulklen))
415
413
  @sock.read(2) # Discard CRLF.
416
414
  reply