redis 3.3.5 → 4.3.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +132 -2
- data/README.md +144 -79
- data/lib/redis.rb +1174 -405
- data/lib/redis/client.rb +150 -90
- data/lib/redis/cluster.rb +295 -0
- 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 +107 -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/connection.rb +4 -2
- data/lib/redis/connection/command_helper.rb +5 -10
- data/lib/redis/connection/hiredis.rb +6 -5
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +126 -128
- data/lib/redis/connection/synchrony.rb +21 -8
- data/lib/redis/distributed.rb +147 -72
- data/lib/redis/errors.rb +48 -0
- data/lib/redis/hash_ring.rb +30 -73
- data/lib/redis/pipeline.rb +55 -15
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- metadata +49 -202
- data/.gitignore +0 -16
- data/.travis.yml +0 -89
- data/.travis/Gemfile +0 -11
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -87
- 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/dist_redis.rb +0 -43
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel.rb +0 -41
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/redis.gemspec +0 -44
- data/test/bitpos_test.rb +0 -69
- data/test/blocking_commands_test.rb +0 -42
- data/test/client_test.rb +0 -59
- data/test/command_map_test.rb +0 -30
- data/test/commands_on_hashes_test.rb +0 -21
- data/test/commands_on_hyper_log_log_test.rb +0 -21
- data/test/commands_on_lists_test.rb +0 -20
- data/test/commands_on_sets_test.rb +0 -77
- data/test/commands_on_sorted_sets_test.rb +0 -137
- data/test/commands_on_strings_test.rb +0 -101
- data/test/commands_on_value_types_test.rb +0 -133
- data/test/connection_handling_test.rb +0 -277
- data/test/connection_test.rb +0 -57
- data/test/db/.gitkeep +0 -0
- data/test/distributed_blocking_commands_test.rb +0 -46
- data/test/distributed_commands_on_hashes_test.rb +0 -10
- data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
- data/test/distributed_commands_on_lists_test.rb +0 -22
- data/test/distributed_commands_on_sets_test.rb +0 -83
- data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
- data/test/distributed_commands_on_strings_test.rb +0 -59
- data/test/distributed_commands_on_value_types_test.rb +0 -95
- data/test/distributed_commands_requiring_clustering_test.rb +0 -164
- data/test/distributed_connection_handling_test.rb +0 -23
- data/test/distributed_internals_test.rb +0 -79
- data/test/distributed_key_tags_test.rb +0 -52
- data/test/distributed_persistence_control_commands_test.rb +0 -26
- data/test/distributed_publish_subscribe_test.rb +0 -92
- data/test/distributed_remote_server_control_commands_test.rb +0 -66
- data/test/distributed_scripting_test.rb +0 -102
- data/test/distributed_sorting_test.rb +0 -20
- data/test/distributed_test.rb +0 -58
- data/test/distributed_transactions_test.rb +0 -32
- data/test/encoding_test.rb +0 -18
- data/test/error_replies_test.rb +0 -59
- data/test/fork_safety_test.rb +0 -65
- data/test/helper.rb +0 -232
- data/test/helper_test.rb +0 -24
- data/test/internals_test.rb +0 -417
- data/test/lint/blocking_commands.rb +0 -150
- data/test/lint/hashes.rb +0 -162
- data/test/lint/hyper_log_log.rb +0 -60
- data/test/lint/lists.rb +0 -143
- data/test/lint/sets.rb +0 -140
- data/test/lint/sorted_sets.rb +0 -316
- data/test/lint/strings.rb +0 -260
- data/test/lint/value_types.rb +0 -122
- data/test/persistence_control_commands_test.rb +0 -26
- data/test/pipelining_commands_test.rb +0 -242
- data/test/publish_subscribe_test.rb +0 -282
- data/test/remote_server_control_commands_test.rb +0 -118
- data/test/scanning_test.rb +0 -413
- data/test/scripting_test.rb +0 -78
- data/test/sentinel_command_test.rb +0 -80
- data/test/sentinel_test.rb +0 -255
- data/test/sorting_test.rb +0 -59
- data/test/ssl_test.rb +0 -73
- 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 -88
- data/test/test.conf.erb +0 -9
- data/test/thread_safety_test.rb +0 -62
- data/test/transactions_test.rb +0 -264
- data/test/unknown_commands_test.rb +0 -14
- data/test/url_param_test.rb +0 -138
@@ -1,12 +1,13 @@
|
|
1
|
-
|
2
|
-
|
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
|
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,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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(
|
127
|
-
return super(
|
70
|
+
def write(buffer)
|
71
|
+
return super(buffer) unless @write_timeout
|
128
72
|
|
129
|
-
|
130
|
-
|
73
|
+
bytes_to_write = buffer.bytesize
|
74
|
+
total_bytes_written = 0
|
131
75
|
loop do
|
132
|
-
|
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
|
-
|
135
|
-
|
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
|
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(
|
195
|
-
sock = new(::Socket.const_get(
|
196
|
-
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])
|
197
152
|
|
198
153
|
begin
|
199
154
|
sock.connect_nonblock(sockaddr)
|
200
155
|
rescue Errno::EINPROGRESS
|
201
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
289
|
-
|
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 = "-"
|
300
|
-
PLUS = "+"
|
301
|
-
COLON = ":"
|
302
|
-
DOLLAR = "$"
|
303
|
-
ASTERISK = "*"
|
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[:
|
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 [
|
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
|
-
:
|
336
|
-
:
|
337
|
-
:
|
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
|
-
|
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
|
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
|