redis 4.1.4 → 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 +4 -4
- data/CHANGELOG.md +56 -0
- data/README.md +27 -17
- data/lib/redis.rb +405 -260
- data/lib/redis/client.rb +94 -74
- data/lib/redis/cluster.rb +13 -13
- data/lib/redis/cluster/node.rb +5 -1
- data/lib/redis/cluster/option.rb +9 -3
- data/lib/redis/cluster/slot.rb +28 -14
- data/lib/redis/cluster/slot_loader.rb +2 -3
- data/lib/redis/connection.rb +1 -0
- data/lib/redis/connection/command_helper.rb +2 -2
- data/lib/redis/connection/hiredis.rb +3 -3
- data/lib/redis/connection/registry.rb +1 -1
- data/lib/redis/connection/ruby.rb +89 -107
- data/lib/redis/connection/synchrony.rb +8 -4
- data/lib/redis/distributed.rb +121 -63
- data/lib/redis/errors.rb +1 -0
- data/lib/redis/hash_ring.rb +14 -14
- data/lib/redis/pipeline.rb +6 -8
- data/lib/redis/subscribe.rb +10 -12
- data/lib/redis/version.rb +2 -1
- metadata +14 -9
data/lib/redis/cluster/option.rb
CHANGED
@@ -18,6 +18,7 @@ class Redis
|
|
18
18
|
@node_opts = build_node_options(node_addrs)
|
19
19
|
@replica = options.delete(:replica) == true
|
20
20
|
add_common_node_option_if_needed(options, @node_opts, :scheme)
|
21
|
+
add_common_node_option_if_needed(options, @node_opts, :username)
|
21
22
|
add_common_node_option_if_needed(options, @node_opts, :password)
|
22
23
|
@options = options
|
23
24
|
end
|
@@ -43,6 +44,7 @@ class Redis
|
|
43
44
|
|
44
45
|
def build_node_options(addrs)
|
45
46
|
raise InvalidClientOptionError, 'Redis option of `cluster` must be an Array' unless addrs.is_a?(Array)
|
47
|
+
|
46
48
|
addrs.map { |addr| parse_node_addr(addr) }
|
47
49
|
end
|
48
50
|
|
@@ -62,21 +64,25 @@ class Redis
|
|
62
64
|
raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
|
63
65
|
|
64
66
|
db = uri.path.split('/')[1]&.to_i
|
65
|
-
|
67
|
+
|
68
|
+
{ scheme: uri.scheme, username: uri.user, password: uri.password, host: uri.host, port: uri.port, db: db }
|
69
|
+
.reject { |_, v| v.nil? || v == '' }
|
66
70
|
rescue URI::InvalidURIError => err
|
67
71
|
raise InvalidClientOptionError, err.message
|
68
72
|
end
|
69
73
|
|
70
74
|
def parse_node_option(addr)
|
71
75
|
addr = addr.map { |k, v| [k.to_sym, v] }.to_h
|
72
|
-
|
76
|
+
if addr.values_at(:host, :port).any?(&:nil?)
|
77
|
+
raise InvalidClientOptionError, 'Redis option of `cluster` must includes `:host` and `:port` keys'
|
78
|
+
end
|
73
79
|
|
74
80
|
addr
|
75
81
|
end
|
76
82
|
|
77
83
|
# Redis cluster node returns only host and port information.
|
78
84
|
# So we should complement additional information such as:
|
79
|
-
# scheme, password and so on.
|
85
|
+
# scheme, username, password and so on.
|
80
86
|
def add_common_node_option_if_needed(options, node_opts, key)
|
81
87
|
return options if options[key].nil? && node_opts.first[key].nil?
|
82
88
|
|
data/lib/redis/cluster/slot.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'set'
|
4
|
-
|
5
3
|
class Redis
|
6
4
|
class Cluster
|
7
5
|
# Keep slot and node key map for Redis Cluster Client
|
@@ -28,11 +26,20 @@ class Redis
|
|
28
26
|
return nil unless exists?(slot)
|
29
27
|
return find_node_key_of_master(slot) if replica_disabled?
|
30
28
|
|
31
|
-
@map[slot][:slaves].
|
29
|
+
@map[slot][:slaves].sample
|
32
30
|
end
|
33
31
|
|
34
32
|
def put(slot, node_key)
|
35
|
-
|
33
|
+
# Since we're sharing a hash for build_slot_node_key_map, duplicate it
|
34
|
+
# if it already exists instead of preserving as-is.
|
35
|
+
@map[slot] = @map[slot] ? @map[slot].dup : { master: nil, slaves: [] }
|
36
|
+
|
37
|
+
if master?(node_key)
|
38
|
+
@map[slot][:master] = node_key
|
39
|
+
elsif !@map[slot][:slaves].include?(node_key)
|
40
|
+
@map[slot][:slaves] << node_key
|
41
|
+
end
|
42
|
+
|
36
43
|
nil
|
37
44
|
end
|
38
45
|
|
@@ -52,20 +59,27 @@ class Redis
|
|
52
59
|
|
53
60
|
# available_slots is mapping of node_key to list of slot ranges
|
54
61
|
def build_slot_node_key_map(available_slots)
|
55
|
-
|
56
|
-
|
57
|
-
|
62
|
+
by_ranges = {}
|
63
|
+
available_slots.each do |node_key, slots_arr|
|
64
|
+
by_ranges[slots_arr] ||= { master: nil, slaves: [] }
|
65
|
+
|
66
|
+
if master?(node_key)
|
67
|
+
by_ranges[slots_arr][:master] = node_key
|
68
|
+
elsif !by_ranges[slots_arr][:slaves].include?(node_key)
|
69
|
+
by_ranges[slots_arr][:slaves] << node_key
|
58
70
|
end
|
59
71
|
end
|
60
|
-
end
|
61
72
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
73
|
+
by_slot = {}
|
74
|
+
by_ranges.each do |slots_arr, nodes|
|
75
|
+
slots_arr.each do |slots|
|
76
|
+
slots.each do |slot|
|
77
|
+
by_slot[slot] = nodes
|
78
|
+
end
|
79
|
+
end
|
68
80
|
end
|
81
|
+
|
82
|
+
by_slot
|
69
83
|
end
|
70
84
|
end
|
71
85
|
end
|
@@ -25,9 +25,8 @@ class Redis
|
|
25
25
|
def fetch_slot_info(node)
|
26
26
|
hash_with_default_arr = Hash.new { |h, k| h[k] = [] }
|
27
27
|
node.call(%i[cluster slots])
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
.flat_map { |arr| parse_slot_info(arr, default_ip: node.host) }
|
29
|
+
.each_with_object(hash_with_default_arr) { |arr, h| h[arr[0]] << arr[1] }
|
31
30
|
rescue CannotConnectError, ConnectionError, CommandError
|
32
31
|
{} # can retry on another node
|
33
32
|
end
|
data/lib/redis/connection.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
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,97 +25,74 @@ 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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
raise Redis::TimeoutError
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
rescue EOFError
|
83
|
-
raise Errno::ECONNRESET
|
84
|
-
end
|
85
|
-
|
86
|
-
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
|
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
|
101
66
|
end
|
102
67
|
end
|
103
|
-
|
104
|
-
rescue EOFError
|
105
|
-
raise Errno::ECONNRESET
|
106
68
|
end
|
107
69
|
|
108
|
-
def write(
|
109
|
-
return super(
|
70
|
+
def write(buffer)
|
71
|
+
return super(buffer) unless @write_timeout
|
110
72
|
|
111
|
-
|
112
|
-
|
73
|
+
bytes_to_write = buffer.bytesize
|
74
|
+
total_bytes_written = 0
|
113
75
|
loop do
|
114
|
-
|
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
|
115
89
|
|
116
|
-
|
117
|
-
|
118
|
-
|
90
|
+
if total_bytes_written >= bytes_to_write
|
91
|
+
return total_bytes_written
|
92
|
+
end
|
93
|
+
|
94
|
+
buffer = buffer.byteslice(bytes_written..-1)
|
95
|
+
end
|
119
96
|
end
|
120
97
|
end
|
121
98
|
end
|
@@ -125,7 +102,6 @@ class Redis
|
|
125
102
|
require "timeout"
|
126
103
|
|
127
104
|
class TCPSocket < ::TCPSocket
|
128
|
-
|
129
105
|
include SocketMixin
|
130
106
|
|
131
107
|
def self.connect(host, port, timeout)
|
@@ -141,7 +117,6 @@ class Redis
|
|
141
117
|
if defined?(::UNIXSocket)
|
142
118
|
|
143
119
|
class UNIXSocket < ::UNIXSocket
|
144
|
-
|
145
120
|
include SocketMixin
|
146
121
|
|
147
122
|
def self.connect(path, timeout)
|
@@ -153,13 +128,12 @@ class Redis
|
|
153
128
|
raise TimeoutError
|
154
129
|
end
|
155
130
|
|
156
|
-
# JRuby raises Errno::EAGAIN on #read_nonblock even when
|
131
|
+
# JRuby raises Errno::EAGAIN on #read_nonblock even when it
|
157
132
|
# says it is readable (1.6.6, in both 1.8 and 1.9 mode).
|
158
133
|
# Use the blocking #readpartial method instead.
|
159
134
|
|
160
135
|
def _read_from_socket(nbytes)
|
161
136
|
readpartial(nbytes)
|
162
|
-
|
163
137
|
rescue EOFError
|
164
138
|
raise Errno::ECONNRESET
|
165
139
|
end
|
@@ -170,19 +144,16 @@ class Redis
|
|
170
144
|
else
|
171
145
|
|
172
146
|
class TCPSocket < ::Socket
|
173
|
-
|
174
147
|
include SocketMixin
|
175
148
|
|
176
|
-
def self.connect_addrinfo(
|
177
|
-
sock = new(::Socket.const_get(
|
178
|
-
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])
|
179
152
|
|
180
153
|
begin
|
181
154
|
sock.connect_nonblock(sockaddr)
|
182
155
|
rescue Errno::EINPROGRESS
|
183
|
-
|
184
|
-
raise TimeoutError
|
185
|
-
end
|
156
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
186
157
|
|
187
158
|
begin
|
188
159
|
sock.connect_nonblock(sockaddr)
|
@@ -221,14 +192,13 @@ class Redis
|
|
221
192
|
return connect_addrinfo(ai, port, timeout)
|
222
193
|
rescue SystemCallError
|
223
194
|
# Raise if this was our last attempt.
|
224
|
-
raise if addrinfo.length == i+1
|
195
|
+
raise if addrinfo.length == i + 1
|
225
196
|
end
|
226
197
|
end
|
227
198
|
end
|
228
199
|
end
|
229
200
|
|
230
201
|
class UNIXSocket < ::Socket
|
231
|
-
|
232
202
|
include SocketMixin
|
233
203
|
|
234
204
|
def self.connect(path, timeout)
|
@@ -238,9 +208,7 @@ class Redis
|
|
238
208
|
begin
|
239
209
|
sock.connect_nonblock(sockaddr)
|
240
210
|
rescue Errno::EINPROGRESS
|
241
|
-
|
242
|
-
raise TimeoutError
|
243
|
-
end
|
211
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
244
212
|
|
245
213
|
begin
|
246
214
|
sock.connect_nonblock(sockaddr)
|
@@ -258,12 +226,26 @@ class Redis
|
|
258
226
|
class SSLSocket < ::OpenSSL::SSL::SSLSocket
|
259
227
|
include SocketMixin
|
260
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
|
+
|
261
241
|
def self.connect(host, port, timeout, ssl_params)
|
262
242
|
# Note: this is using Redis::Connection::TCPSocket
|
263
243
|
tcp_sock = TCPSocket.connect(host, port, timeout)
|
264
244
|
|
265
245
|
ctx = OpenSSL::SSL::SSLContext.new
|
266
|
-
|
246
|
+
|
247
|
+
# The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
|
248
|
+
ctx.set_params(ssl_params || {})
|
267
249
|
|
268
250
|
ssl_sock = new(tcp_sock, ctx)
|
269
251
|
ssl_sock.hostname = host
|
@@ -277,20 +259,23 @@ class Redis
|
|
277
259
|
# Instead, you have to retry.
|
278
260
|
ssl_sock.connect_nonblock
|
279
261
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
280
|
-
if
|
262
|
+
if ssl_sock.wait_readable(timeout)
|
281
263
|
retry
|
282
264
|
else
|
283
265
|
raise TimeoutError
|
284
266
|
end
|
285
267
|
rescue IO::WaitWritable
|
286
|
-
if
|
268
|
+
if ssl_sock.wait_writable(timeout)
|
287
269
|
retry
|
288
270
|
else
|
289
271
|
raise TimeoutError
|
290
272
|
end
|
291
273
|
end
|
292
274
|
|
293
|
-
unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
|
275
|
+
unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
|
276
|
+
ctx.respond_to?(:verify_hostname) &&
|
277
|
+
!ctx.verify_hostname
|
278
|
+
)
|
294
279
|
ssl_sock.post_connection_check(host)
|
295
280
|
end
|
296
281
|
|
@@ -302,15 +287,16 @@ class Redis
|
|
302
287
|
class Ruby
|
303
288
|
include Redis::Connection::CommandHelper
|
304
289
|
|
305
|
-
MINUS = "-"
|
306
|
-
PLUS = "+"
|
307
|
-
COLON = ":"
|
308
|
-
DOLLAR = "$"
|
309
|
-
ASTERISK = "*"
|
290
|
+
MINUS = "-"
|
291
|
+
PLUS = "+"
|
292
|
+
COLON = ":"
|
293
|
+
DOLLAR = "$"
|
294
|
+
ASTERISK = "*"
|
310
295
|
|
311
296
|
def self.connect(config)
|
312
297
|
if config[:scheme] == "unix"
|
313
298
|
raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
|
299
|
+
|
314
300
|
sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
|
315
301
|
elsif config[:scheme] == "rediss" || config[:ssl]
|
316
302
|
sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
|
@@ -326,7 +312,7 @@ class Redis
|
|
326
312
|
instance
|
327
313
|
end
|
328
314
|
|
329
|
-
if [
|
315
|
+
if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
|
330
316
|
def set_tcp_keepalive(keepalive)
|
331
317
|
return unless keepalive.is_a?(Hash)
|
332
318
|
|
@@ -338,14 +324,13 @@ class Redis
|
|
338
324
|
|
339
325
|
def get_tcp_keepalive
|
340
326
|
{
|
341
|
-
:
|
342
|
-
:
|
343
|
-
:
|
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
|
344
330
|
}
|
345
331
|
end
|
346
332
|
else
|
347
|
-
def set_tcp_keepalive(keepalive)
|
348
|
-
end
|
333
|
+
def set_tcp_keepalive(keepalive); end
|
349
334
|
|
350
335
|
def get_tcp_keepalive
|
351
336
|
{
|
@@ -354,13 +339,12 @@ class Redis
|
|
354
339
|
end
|
355
340
|
|
356
341
|
# disables Nagle's Algorithm, prevents multiple round trips with MULTI
|
357
|
-
if [
|
342
|
+
if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
|
358
343
|
def set_tcp_nodelay
|
359
344
|
@sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
360
345
|
end
|
361
346
|
else
|
362
|
-
def set_tcp_nodelay
|
363
|
-
end
|
347
|
+
def set_tcp_nodelay; end
|
364
348
|
end
|
365
349
|
|
366
350
|
def initialize(sock)
|
@@ -368,7 +352,7 @@ class Redis
|
|
368
352
|
end
|
369
353
|
|
370
354
|
def connected?
|
371
|
-
|
355
|
+
!!@sock
|
372
356
|
end
|
373
357
|
|
374
358
|
def disconnect
|
@@ -379,9 +363,7 @@ class Redis
|
|
379
363
|
end
|
380
364
|
|
381
365
|
def timeout=(timeout)
|
382
|
-
if @sock.respond_to?(:timeout=)
|
383
|
-
@sock.timeout = timeout
|
384
|
-
end
|
366
|
+
@sock.timeout = timeout if @sock.respond_to?(:timeout=)
|
385
367
|
end
|
386
368
|
|
387
369
|
def write_timeout=(timeout)
|
@@ -396,7 +378,6 @@ class Redis
|
|
396
378
|
line = @sock.gets
|
397
379
|
reply_type = line.slice!(0, 1)
|
398
380
|
format_reply(reply_type, line)
|
399
|
-
|
400
381
|
rescue Errno::EAGAIN
|
401
382
|
raise TimeoutError
|
402
383
|
end
|
@@ -408,7 +389,7 @@ class Redis
|
|
408
389
|
when COLON then format_integer_reply(line)
|
409
390
|
when DOLLAR then format_bulk_reply(line)
|
410
391
|
when ASTERISK then format_multi_bulk_reply(line)
|
411
|
-
else raise ProtocolError
|
392
|
+
else raise ProtocolError, reply_type
|
412
393
|
end
|
413
394
|
end
|
414
395
|
|
@@ -427,6 +408,7 @@ class Redis
|
|
427
408
|
def format_bulk_reply(line)
|
428
409
|
bulklen = line.to_i
|
429
410
|
return if bulklen == -1
|
411
|
+
|
430
412
|
reply = encode(@sock.read(bulklen))
|
431
413
|
@sock.read(2) # Discard CRLF.
|
432
414
|
reply
|