redis 3.3.5 → 4.5.1

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.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +161 -2
  3. data/README.md +144 -79
  4. data/lib/redis/client.rb +166 -90
  5. data/lib/redis/cluster/command.rb +81 -0
  6. data/lib/redis/cluster/command_loader.rb +33 -0
  7. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  8. data/lib/redis/cluster/node.rb +108 -0
  9. data/lib/redis/cluster/node_key.rb +31 -0
  10. data/lib/redis/cluster/node_loader.rb +37 -0
  11. data/lib/redis/cluster/option.rb +93 -0
  12. data/lib/redis/cluster/slot.rb +86 -0
  13. data/lib/redis/cluster/slot_loader.rb +49 -0
  14. data/lib/redis/cluster.rb +291 -0
  15. data/lib/redis/connection/command_helper.rb +7 -10
  16. data/lib/redis/connection/hiredis.rb +6 -5
  17. data/lib/redis/connection/registry.rb +2 -1
  18. data/lib/redis/connection/ruby.rb +128 -129
  19. data/lib/redis/connection/synchrony.rb +21 -8
  20. data/lib/redis/connection.rb +4 -2
  21. data/lib/redis/distributed.rb +194 -72
  22. data/lib/redis/errors.rb +48 -0
  23. data/lib/redis/hash_ring.rb +30 -73
  24. data/lib/redis/pipeline.rb +55 -15
  25. data/lib/redis/subscribe.rb +11 -12
  26. data/lib/redis/version.rb +3 -1
  27. data/lib/redis.rb +1451 -403
  28. metadata +49 -202
  29. data/.gitignore +0 -16
  30. data/.travis/Gemfile +0 -11
  31. data/.travis.yml +0 -89
  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/sentinel.conf +0 -9
  47. data/examples/sentinel/start +0 -49
  48. data/examples/sentinel.rb +0 -41
  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,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)
@@ -11,11 +12,13 @@ class Redis
11
12
  if i.is_a? Array
12
13
  i.each do |j|
13
14
  j = j.to_s
15
+ j = j.encoding == Encoding::BINARY ? j : j.b
14
16
  command << "$#{j.bytesize}"
15
17
  command << j
16
18
  end
17
19
  else
18
20
  i = i.to_s
21
+ i = i.encoding == Encoding::BINARY ? i : i.b
19
22
  command << "$#{i.bytesize}"
20
23
  command << i
21
24
  end
@@ -28,16 +31,10 @@ class Redis
28
31
  command.join(COMMAND_DELIMITER)
29
32
  end
30
33
 
31
- protected
34
+ protected
32
35
 
33
- if defined?(Encoding::default_external)
34
- def encode(string)
35
- string.force_encoding(Encoding::default_external)
36
- end
37
- else
38
- def encode(string)
39
- string
40
- end
36
+ def encode(string)
37
+ string.force_encoding(Encoding.default_external)
41
38
  end
42
39
  end
43
40
  end
@@ -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,88 @@ 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 = "".b
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
+ buffer = String.new(capacity: nbytes, encoding: Encoding::ASCII_8BIT)
39
+ result << _read_from_socket(nbytes - result.bytesize, buffer) while result.bytesize < nbytes
67
40
 
68
41
  result
69
42
  end
70
43
 
71
44
  def gets
72
- crlf = nil
73
-
74
- while (crlf = @buffer.index(CRLF)) == nil
75
- @buffer << _read_from_socket(1024)
45
+ while (crlf = @buffer.index(CRLF)).nil?
46
+ @buffer << _read_from_socket(16_384)
76
47
  end
77
48
 
78
49
  @buffer.slice!(0, crlf + CRLF.bytesize)
79
50
  end
80
51
 
81
- 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
+ def _read_from_socket(nbytes, buffer = nil)
53
+ loop do
54
+ case chunk = read_nonblock(nbytes, buffer, exception: false)
55
+ when :wait_readable
56
+ unless wait_readable(@timeout)
57
+ raise Redis::TimeoutError
58
+ end
59
+ when :wait_writable
60
+ unless wait_writable(@timeout)
61
+ raise Redis::TimeoutError
62
+ end
63
+ when nil
64
+ raise Errno::ECONNRESET
65
+ when String
66
+ return chunk
119
67
  end
120
68
  end
121
-
122
- rescue EOFError
123
- raise Errno::ECONNRESET
124
69
  end
125
70
 
126
- def write(data)
127
- return super(data) unless @write_timeout
71
+ def write(buffer)
72
+ return super(buffer) unless @write_timeout
128
73
 
129
- length = data.bytesize
130
- total_count = 0
74
+ bytes_to_write = buffer.bytesize
75
+ total_bytes_written = 0
131
76
  loop do
132
- count = _write_to_socket(data)
77
+ case bytes_written = write_nonblock(buffer, exception: false)
78
+ when :wait_readable
79
+ unless wait_readable(@write_timeout)
80
+ raise Redis::TimeoutError
81
+ end
82
+ when :wait_writable
83
+ unless wait_writable(@write_timeout)
84
+ raise Redis::TimeoutError
85
+ end
86
+ when nil
87
+ raise Errno::ECONNRESET
88
+ when Integer
89
+ total_bytes_written += bytes_written
90
+
91
+ if total_bytes_written >= bytes_to_write
92
+ return total_bytes_written
93
+ end
133
94
 
134
- total_count += count
135
- return total_count if total_count >= length
136
- data = data.byteslice(count..-1)
95
+ buffer = buffer.byteslice(bytes_written..-1)
96
+ end
137
97
  end
138
98
  end
139
99
  end
@@ -143,7 +103,6 @@ class Redis
143
103
  require "timeout"
144
104
 
145
105
  class TCPSocket < ::TCPSocket
146
-
147
106
  include SocketMixin
148
107
 
149
108
  def self.connect(host, port, timeout)
@@ -159,7 +118,6 @@ class Redis
159
118
  if defined?(::UNIXSocket)
160
119
 
161
120
  class UNIXSocket < ::UNIXSocket
162
-
163
121
  include SocketMixin
164
122
 
165
123
  def self.connect(path, timeout)
@@ -171,13 +129,12 @@ class Redis
171
129
  raise TimeoutError
172
130
  end
173
131
 
174
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
132
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
175
133
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
176
134
  # Use the blocking #readpartial method instead.
177
135
 
178
136
  def _read_from_socket(nbytes)
179
137
  readpartial(nbytes)
180
-
181
138
  rescue EOFError
182
139
  raise Errno::ECONNRESET
183
140
  end
@@ -188,19 +145,16 @@ class Redis
188
145
  else
189
146
 
190
147
  class TCPSocket < ::Socket
191
-
192
148
  include SocketMixin
193
149
 
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])
150
+ def self.connect_addrinfo(addrinfo, port, timeout)
151
+ sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
152
+ sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
197
153
 
198
154
  begin
199
155
  sock.connect_nonblock(sockaddr)
200
156
  rescue Errno::EINPROGRESS
201
- if IO.select(nil, [sock], nil, timeout) == nil
202
- raise TimeoutError
203
- end
157
+ raise TimeoutError unless sock.wait_writable(timeout)
204
158
 
205
159
  begin
206
160
  sock.connect_nonblock(sockaddr)
@@ -239,14 +193,13 @@ class Redis
239
193
  return connect_addrinfo(ai, port, timeout)
240
194
  rescue SystemCallError
241
195
  # Raise if this was our last attempt.
242
- raise if addrinfo.length == i+1
196
+ raise if addrinfo.length == i + 1
243
197
  end
244
198
  end
245
199
  end
246
200
  end
247
201
 
248
202
  class UNIXSocket < ::Socket
249
-
250
203
  include SocketMixin
251
204
 
252
205
  def self.connect(path, timeout)
@@ -256,9 +209,7 @@ class Redis
256
209
  begin
257
210
  sock.connect_nonblock(sockaddr)
258
211
  rescue Errno::EINPROGRESS
259
- if IO.select(nil, [sock], nil, timeout) == nil
260
- raise TimeoutError
261
- end
212
+ raise TimeoutError unless sock.wait_writable(timeout)
262
213
 
263
214
  begin
264
215
  sock.connect_nonblock(sockaddr)
@@ -276,17 +227,58 @@ class Redis
276
227
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
277
228
  include SocketMixin
278
229
 
230
+ unless method_defined?(:wait_readable)
231
+ def wait_readable(timeout = nil)
232
+ to_io.wait_readable(timeout)
233
+ end
234
+ end
235
+
236
+ unless method_defined?(:wait_writable)
237
+ def wait_writable(timeout = nil)
238
+ to_io.wait_writable(timeout)
239
+ end
240
+ end
241
+
279
242
  def self.connect(host, port, timeout, ssl_params)
280
243
  # Note: this is using Redis::Connection::TCPSocket
281
244
  tcp_sock = TCPSocket.connect(host, port, timeout)
282
245
 
283
246
  ctx = OpenSSL::SSL::SSLContext.new
284
- ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
247
+
248
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
249
+ ctx.set_params(ssl_params || {})
285
250
 
286
251
  ssl_sock = new(tcp_sock, ctx)
287
252
  ssl_sock.hostname = host
288
- ssl_sock.connect
289
- ssl_sock.post_connection_check(host)
253
+
254
+ begin
255
+ # Initiate the socket connection in the background. If it doesn't fail
256
+ # immediately it will raise an IO::WaitWritable (Errno::EINPROGRESS)
257
+ # indicating the connection is in progress.
258
+ # Unlike waiting for a tcp socket to connect, you can't time out ssl socket
259
+ # connections during the connect phase properly, because IO.select only partially works.
260
+ # Instead, you have to retry.
261
+ ssl_sock.connect_nonblock
262
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
263
+ if ssl_sock.wait_readable(timeout)
264
+ retry
265
+ else
266
+ raise TimeoutError
267
+ end
268
+ rescue IO::WaitWritable
269
+ if ssl_sock.wait_writable(timeout)
270
+ retry
271
+ else
272
+ raise TimeoutError
273
+ end
274
+ end
275
+
276
+ unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
277
+ ctx.respond_to?(:verify_hostname) &&
278
+ !ctx.verify_hostname
279
+ )
280
+ ssl_sock.post_connection_check(host)
281
+ end
290
282
 
291
283
  ssl_sock
292
284
  end
@@ -296,31 +288,32 @@ class Redis
296
288
  class Ruby
297
289
  include Redis::Connection::CommandHelper
298
290
 
299
- MINUS = "-".freeze
300
- PLUS = "+".freeze
301
- COLON = ":".freeze
302
- DOLLAR = "$".freeze
303
- ASTERISK = "*".freeze
291
+ MINUS = "-"
292
+ PLUS = "+"
293
+ COLON = ":"
294
+ DOLLAR = "$"
295
+ ASTERISK = "*"
304
296
 
305
297
  def self.connect(config)
306
298
  if config[:scheme] == "unix"
307
299
  raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
300
+
308
301
  sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
309
302
  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
303
  sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
312
304
  else
313
305
  sock = TCPSocket.connect(config[:host], config[:port], config[:connect_timeout])
314
306
  end
315
307
 
316
308
  instance = new(sock)
317
- instance.timeout = config[:timeout]
309
+ instance.timeout = config[:read_timeout]
318
310
  instance.write_timeout = config[:write_timeout]
319
311
  instance.set_tcp_keepalive config[:tcp_keepalive]
312
+ instance.set_tcp_nodelay if sock.is_a? TCPSocket
320
313
  instance
321
314
  end
322
315
 
323
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
316
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
324
317
  def set_tcp_keepalive(keepalive)
325
318
  return unless keepalive.is_a?(Hash)
326
319
 
@@ -332,14 +325,13 @@ class Redis
332
325
 
333
326
  def get_tcp_keepalive
334
327
  {
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,
328
+ time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
329
+ intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
330
+ probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
338
331
  }
339
332
  end
340
333
  else
341
- def set_tcp_keepalive(keepalive)
342
- end
334
+ def set_tcp_keepalive(keepalive); end
343
335
 
344
336
  def get_tcp_keepalive
345
337
  {
@@ -347,12 +339,21 @@ class Redis
347
339
  end
348
340
  end
349
341
 
342
+ # disables Nagle's Algorithm, prevents multiple round trips with MULTI
343
+ if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
344
+ def set_tcp_nodelay
345
+ @sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
346
+ end
347
+ else
348
+ def set_tcp_nodelay; end
349
+ end
350
+
350
351
  def initialize(sock)
351
352
  @sock = sock
352
353
  end
353
354
 
354
355
  def connected?
355
- !! @sock
356
+ !!@sock
356
357
  end
357
358
 
358
359
  def disconnect
@@ -363,9 +364,7 @@ class Redis
363
364
  end
364
365
 
365
366
  def timeout=(timeout)
366
- if @sock.respond_to?(:timeout=)
367
- @sock.timeout = timeout
368
- end
367
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
369
368
  end
370
369
 
371
370
  def write_timeout=(timeout)
@@ -380,7 +379,6 @@ class Redis
380
379
  line = @sock.gets
381
380
  reply_type = line.slice!(0, 1)
382
381
  format_reply(reply_type, line)
383
-
384
382
  rescue Errno::EAGAIN
385
383
  raise TimeoutError
386
384
  end
@@ -392,7 +390,7 @@ class Redis
392
390
  when COLON then format_integer_reply(line)
393
391
  when DOLLAR then format_bulk_reply(line)
394
392
  when ASTERISK then format_multi_bulk_reply(line)
395
- else raise ProtocolError.new(reply_type)
393
+ else raise ProtocolError, reply_type
396
394
  end
397
395
  end
398
396
 
@@ -411,6 +409,7 @@ class Redis
411
409
  def format_bulk_reply(line)
412
410
  bulklen = line.to_i
413
411
  return if bulklen == -1
412
+
414
413
  reply = encode(@sock.read(bulklen))
415
414
  @sock.read(2) # Discard CRLF.
416
415
  reply
@@ -1,9 +1,16 @@
1
- require "redis/connection/command_helper"
2
- require "redis/connection/registry"
3
- require "redis/errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "command_helper"
4
+ require_relative "registry"
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
- conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
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 && @connection.connected?
113
+ @connection&.connected?
101
114
  end
102
115
 
103
116
  def timeout=(timeout)
@@ -1,4 +1,6 @@
1
- require "redis/connection/registry"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "connection/registry"
2
4
 
3
5
  # If a connection driver was required before this file, the array
4
6
  # Redis::Connection.drivers will contain one or more classes. The last driver
@@ -6,4 +8,4 @@ require "redis/connection/registry"
6
8
  # the plain Ruby driver as our default. Another driver can be required at a
7
9
  # later point in time, causing it to be the last element of the #drivers array
8
10
  # and therefore be chosen by default.
9
- require "redis/connection/ruby" if Redis::Connection.drivers.empty?
11
+ require_relative "connection/ruby" if Redis::Connection.drivers.empty?