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