finsync_redis 3.3.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.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis/Gemfile +11 -0
  4. data/.travis.yml +89 -0
  5. data/.yardopts +3 -0
  6. data/CHANGELOG.md +373 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +20 -0
  9. data/README.md +410 -0
  10. data/Rakefile +87 -0
  11. data/benchmarking/logging.rb +71 -0
  12. data/benchmarking/pipeline.rb +51 -0
  13. data/benchmarking/speed.rb +21 -0
  14. data/benchmarking/suite.rb +24 -0
  15. data/benchmarking/worker.rb +71 -0
  16. data/examples/basic.rb +15 -0
  17. data/examples/consistency.rb +114 -0
  18. data/examples/dist_redis.rb +43 -0
  19. data/examples/incr-decr.rb +17 -0
  20. data/examples/list.rb +26 -0
  21. data/examples/pubsub.rb +37 -0
  22. data/examples/sentinel/sentinel.conf +9 -0
  23. data/examples/sentinel/start +49 -0
  24. data/examples/sentinel.rb +41 -0
  25. data/examples/sets.rb +36 -0
  26. data/examples/unicorn/config.ru +3 -0
  27. data/examples/unicorn/unicorn.rb +20 -0
  28. data/lib/redis/client.rb +590 -0
  29. data/lib/redis/connection/command_helper.rb +44 -0
  30. data/lib/redis/connection/hiredis.rb +66 -0
  31. data/lib/redis/connection/registry.rb +12 -0
  32. data/lib/redis/connection/ruby.rb +429 -0
  33. data/lib/redis/connection/synchrony.rb +133 -0
  34. data/lib/redis/connection.rb +9 -0
  35. data/lib/redis/distributed.rb +873 -0
  36. data/lib/redis/errors.rb +40 -0
  37. data/lib/redis/hash_ring.rb +132 -0
  38. data/lib/redis/pipeline.rb +141 -0
  39. data/lib/redis/subscribe.rb +91 -0
  40. data/lib/redis/version.rb +3 -0
  41. data/lib/redis.rb +2788 -0
  42. data/redis.gemspec +44 -0
  43. data/test/bitpos_test.rb +69 -0
  44. data/test/blocking_commands_test.rb +42 -0
  45. data/test/client_test.rb +59 -0
  46. data/test/command_map_test.rb +30 -0
  47. data/test/commands_on_hashes_test.rb +21 -0
  48. data/test/commands_on_hyper_log_log_test.rb +21 -0
  49. data/test/commands_on_lists_test.rb +20 -0
  50. data/test/commands_on_sets_test.rb +77 -0
  51. data/test/commands_on_sorted_sets_test.rb +137 -0
  52. data/test/commands_on_strings_test.rb +101 -0
  53. data/test/commands_on_value_types_test.rb +133 -0
  54. data/test/connection_handling_test.rb +277 -0
  55. data/test/connection_test.rb +57 -0
  56. data/test/db/.gitkeep +0 -0
  57. data/test/distributed_blocking_commands_test.rb +46 -0
  58. data/test/distributed_commands_on_hashes_test.rb +10 -0
  59. data/test/distributed_commands_on_hyper_log_log_test.rb +33 -0
  60. data/test/distributed_commands_on_lists_test.rb +22 -0
  61. data/test/distributed_commands_on_sets_test.rb +83 -0
  62. data/test/distributed_commands_on_sorted_sets_test.rb +18 -0
  63. data/test/distributed_commands_on_strings_test.rb +59 -0
  64. data/test/distributed_commands_on_value_types_test.rb +95 -0
  65. data/test/distributed_commands_requiring_clustering_test.rb +164 -0
  66. data/test/distributed_connection_handling_test.rb +23 -0
  67. data/test/distributed_internals_test.rb +79 -0
  68. data/test/distributed_key_tags_test.rb +52 -0
  69. data/test/distributed_persistence_control_commands_test.rb +26 -0
  70. data/test/distributed_publish_subscribe_test.rb +92 -0
  71. data/test/distributed_remote_server_control_commands_test.rb +66 -0
  72. data/test/distributed_scripting_test.rb +102 -0
  73. data/test/distributed_sorting_test.rb +20 -0
  74. data/test/distributed_test.rb +58 -0
  75. data/test/distributed_transactions_test.rb +32 -0
  76. data/test/encoding_test.rb +18 -0
  77. data/test/error_replies_test.rb +59 -0
  78. data/test/fork_safety_test.rb +65 -0
  79. data/test/helper.rb +232 -0
  80. data/test/helper_test.rb +24 -0
  81. data/test/internals_test.rb +417 -0
  82. data/test/lint/blocking_commands.rb +150 -0
  83. data/test/lint/hashes.rb +162 -0
  84. data/test/lint/hyper_log_log.rb +60 -0
  85. data/test/lint/lists.rb +143 -0
  86. data/test/lint/sets.rb +140 -0
  87. data/test/lint/sorted_sets.rb +316 -0
  88. data/test/lint/strings.rb +260 -0
  89. data/test/lint/value_types.rb +122 -0
  90. data/test/persistence_control_commands_test.rb +26 -0
  91. data/test/pipelining_commands_test.rb +242 -0
  92. data/test/publish_subscribe_test.rb +282 -0
  93. data/test/remote_server_control_commands_test.rb +118 -0
  94. data/test/scanning_test.rb +413 -0
  95. data/test/scripting_test.rb +78 -0
  96. data/test/sentinel_command_test.rb +80 -0
  97. data/test/sentinel_test.rb +255 -0
  98. data/test/sorting_test.rb +59 -0
  99. data/test/ssl_test.rb +73 -0
  100. data/test/support/connection/hiredis.rb +1 -0
  101. data/test/support/connection/ruby.rb +1 -0
  102. data/test/support/connection/synchrony.rb +17 -0
  103. data/test/support/redis_mock.rb +130 -0
  104. data/test/support/ssl/gen_certs.sh +31 -0
  105. data/test/support/ssl/trusted-ca.crt +25 -0
  106. data/test/support/ssl/trusted-ca.key +27 -0
  107. data/test/support/ssl/trusted-cert.crt +81 -0
  108. data/test/support/ssl/trusted-cert.key +28 -0
  109. data/test/support/ssl/untrusted-ca.crt +26 -0
  110. data/test/support/ssl/untrusted-ca.key +27 -0
  111. data/test/support/ssl/untrusted-cert.crt +82 -0
  112. data/test/support/ssl/untrusted-cert.key +28 -0
  113. data/test/support/wire/synchrony.rb +24 -0
  114. data/test/support/wire/thread.rb +5 -0
  115. data/test/synchrony_driver.rb +88 -0
  116. data/test/test.conf.erb +9 -0
  117. data/test/thread_safety_test.rb +62 -0
  118. data/test/transactions_test.rb +264 -0
  119. data/test/unknown_commands_test.rb +14 -0
  120. data/test/url_param_test.rb +138 -0
  121. metadata +202 -0
@@ -0,0 +1,429 @@
1
+ require "redis/connection/registry"
2
+ require "redis/connection/command_helper"
3
+ require "redis/errors"
4
+ require "socket"
5
+ require "timeout"
6
+
7
+ begin
8
+ require "openssl"
9
+ rescue LoadError
10
+ # Not all systems have OpenSSL support
11
+ end
12
+
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
+ class Redis
24
+ module Connection
25
+ 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
37
+
38
+ def initialize(*args)
39
+ super(*args)
40
+
41
+ @timeout = @write_timeout = nil
42
+ @buffer = ""
43
+ end
44
+
45
+ def timeout=(timeout)
46
+ if timeout && timeout > 0
47
+ @timeout = timeout
48
+ else
49
+ @timeout = nil
50
+ end
51
+ end
52
+
53
+ def write_timeout=(timeout)
54
+ if timeout && timeout > 0
55
+ @write_timeout = timeout
56
+ else
57
+ @write_timeout = nil
58
+ end
59
+ end
60
+
61
+ def read(nbytes)
62
+ result = @buffer.slice!(0, nbytes)
63
+
64
+ while result.bytesize < nbytes
65
+ result << _read_from_socket(nbytes - result.bytesize)
66
+ end
67
+
68
+ result
69
+ end
70
+
71
+ def gets
72
+ crlf = nil
73
+
74
+ while (crlf = @buffer.index(CRLF)) == nil
75
+ @buffer << _read_from_socket(1024)
76
+ end
77
+
78
+ @buffer.slice!(0, crlf + CRLF.bytesize)
79
+ end
80
+
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
119
+ end
120
+ end
121
+
122
+ rescue EOFError
123
+ raise Errno::ECONNRESET
124
+ end
125
+
126
+ def write(data)
127
+ return super(data) unless @write_timeout
128
+
129
+ length = data.bytesize
130
+ total_count = 0
131
+ loop do
132
+ count = _write_to_socket(data)
133
+
134
+ total_count += count
135
+ return total_count if total_count >= length
136
+ data = data.byteslice(count..-1)
137
+ end
138
+ end
139
+ end
140
+
141
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
142
+
143
+ require "timeout"
144
+
145
+ class TCPSocket < ::TCPSocket
146
+
147
+ include SocketMixin
148
+
149
+ def self.connect(host, port, timeout)
150
+ Timeout.timeout(timeout) do
151
+ sock = new(host, port)
152
+ sock
153
+ end
154
+ rescue Timeout::Error
155
+ raise TimeoutError
156
+ end
157
+ end
158
+
159
+ if defined?(::UNIXSocket)
160
+
161
+ class UNIXSocket < ::UNIXSocket
162
+
163
+ include SocketMixin
164
+
165
+ def self.connect(path, timeout)
166
+ Timeout.timeout(timeout) do
167
+ sock = new(path)
168
+ sock
169
+ end
170
+ rescue Timeout::Error
171
+ raise TimeoutError
172
+ end
173
+
174
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
175
+ # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
176
+ # Use the blocking #readpartial method instead.
177
+
178
+ def _read_from_socket(nbytes)
179
+ readpartial(nbytes)
180
+
181
+ rescue EOFError
182
+ raise Errno::ECONNRESET
183
+ end
184
+ end
185
+
186
+ end
187
+
188
+ else
189
+
190
+ class TCPSocket < ::Socket
191
+
192
+ include SocketMixin
193
+
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])
197
+
198
+ begin
199
+ sock.connect_nonblock(sockaddr)
200
+ rescue Errno::EINPROGRESS
201
+ if IO.select(nil, [sock], nil, timeout) == nil
202
+ raise TimeoutError
203
+ end
204
+
205
+ begin
206
+ sock.connect_nonblock(sockaddr)
207
+ rescue Errno::EISCONN
208
+ end
209
+ end
210
+
211
+ sock
212
+ end
213
+
214
+ def self.connect(host, port, timeout)
215
+ # Don't pass AI_ADDRCONFIG as flag to getaddrinfo(3)
216
+ #
217
+ # From the man page for getaddrinfo(3):
218
+ #
219
+ # If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4
220
+ # addresses are returned in the list pointed to by res only if the
221
+ # local system has at least one IPv4 address configured, and IPv6
222
+ # addresses are returned only if the local system has at least one
223
+ # IPv6 address configured. The loopback address is not considered
224
+ # for this case as valid as a configured address.
225
+ #
226
+ # We do want the IPv6 loopback address to be returned if applicable,
227
+ # even if it is the only configured IPv6 address on the machine.
228
+ # Also see: https://github.com/redis/redis-rb/pull/394.
229
+ addrinfo = ::Socket.getaddrinfo(host, nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
230
+
231
+ # From the man page for getaddrinfo(3):
232
+ #
233
+ # Normally, the application should try using the addresses in the
234
+ # order in which they are returned. The sorting function used
235
+ # within getaddrinfo() is defined in RFC 3484 [...].
236
+ #
237
+ addrinfo.each_with_index do |ai, i|
238
+ begin
239
+ return connect_addrinfo(ai, port, timeout)
240
+ rescue SystemCallError
241
+ # Raise if this was our last attempt.
242
+ raise if addrinfo.length == i+1
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ class UNIXSocket < ::Socket
249
+
250
+ include SocketMixin
251
+
252
+ def self.connect(path, timeout)
253
+ sock = new(::Socket::AF_UNIX, Socket::SOCK_STREAM, 0)
254
+ sockaddr = ::Socket.pack_sockaddr_un(path)
255
+
256
+ begin
257
+ sock.connect_nonblock(sockaddr)
258
+ rescue Errno::EINPROGRESS
259
+ if IO.select(nil, [sock], nil, timeout) == nil
260
+ raise TimeoutError
261
+ end
262
+
263
+ begin
264
+ sock.connect_nonblock(sockaddr)
265
+ rescue Errno::EISCONN
266
+ end
267
+ end
268
+
269
+ sock
270
+ end
271
+ end
272
+
273
+ end
274
+
275
+ if defined?(OpenSSL)
276
+ class SSLSocket < ::OpenSSL::SSL::SSLSocket
277
+ include SocketMixin
278
+
279
+ def self.connect(host, port, timeout, ssl_params)
280
+ # Note: this is using Redis::Connection::TCPSocket
281
+ tcp_sock = TCPSocket.connect(host, port, timeout)
282
+
283
+ ctx = OpenSSL::SSL::SSLContext.new
284
+ ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
285
+
286
+ ssl_sock = new(tcp_sock, ctx)
287
+ ssl_sock.hostname = host
288
+ ssl_sock.connect
289
+ ssl_sock.post_connection_check(host) unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE
290
+
291
+ ssl_sock
292
+ end
293
+ end
294
+ end
295
+
296
+ class Ruby
297
+ include Redis::Connection::CommandHelper
298
+
299
+ MINUS = "-".freeze
300
+ PLUS = "+".freeze
301
+ COLON = ":".freeze
302
+ DOLLAR = "$".freeze
303
+ ASTERISK = "*".freeze
304
+
305
+ def self.connect(config)
306
+ if config[:scheme] == "unix"
307
+ raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
308
+ sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
309
+ 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
+ sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
312
+ else
313
+ sock = TCPSocket.connect(config[:host], config[:port], config[:connect_timeout])
314
+ end
315
+
316
+ instance = new(sock)
317
+ instance.timeout = config[:timeout]
318
+ instance.write_timeout = config[:write_timeout]
319
+ instance.set_tcp_keepalive config[:tcp_keepalive]
320
+ instance
321
+ end
322
+
323
+ if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
324
+ def set_tcp_keepalive(keepalive)
325
+ return unless keepalive.is_a?(Hash)
326
+
327
+ @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
328
+ @sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, keepalive[:time])
329
+ @sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, keepalive[:intvl])
330
+ @sock.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, keepalive[:probes])
331
+ end
332
+
333
+ def get_tcp_keepalive
334
+ {
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,
338
+ }
339
+ end
340
+ else
341
+ def set_tcp_keepalive(keepalive)
342
+ end
343
+
344
+ def get_tcp_keepalive
345
+ {
346
+ }
347
+ end
348
+ end
349
+
350
+ def initialize(sock)
351
+ @sock = sock
352
+ end
353
+
354
+ def connected?
355
+ !! @sock
356
+ end
357
+
358
+ def disconnect
359
+ @sock.close
360
+ rescue
361
+ ensure
362
+ @sock = nil
363
+ end
364
+
365
+ def timeout=(timeout)
366
+ if @sock.respond_to?(:timeout=)
367
+ @sock.timeout = timeout
368
+ end
369
+ end
370
+
371
+ def write_timeout=(timeout)
372
+ @sock.write_timeout = timeout
373
+ end
374
+
375
+ def write(command)
376
+ @sock.write(build_command(command))
377
+ end
378
+
379
+ def read
380
+ line = @sock.gets
381
+ reply_type = line.slice!(0, 1)
382
+ format_reply(reply_type, line)
383
+
384
+ rescue Errno::EAGAIN
385
+ raise TimeoutError
386
+ end
387
+
388
+ def format_reply(reply_type, line)
389
+ case reply_type
390
+ when MINUS then format_error_reply(line)
391
+ when PLUS then format_status_reply(line)
392
+ when COLON then format_integer_reply(line)
393
+ when DOLLAR then format_bulk_reply(line)
394
+ when ASTERISK then format_multi_bulk_reply(line)
395
+ else raise ProtocolError.new(reply_type)
396
+ end
397
+ end
398
+
399
+ def format_error_reply(line)
400
+ CommandError.new(line.strip)
401
+ end
402
+
403
+ def format_status_reply(line)
404
+ line.strip
405
+ end
406
+
407
+ def format_integer_reply(line)
408
+ line.to_i
409
+ end
410
+
411
+ def format_bulk_reply(line)
412
+ bulklen = line.to_i
413
+ return if bulklen == -1
414
+ reply = encode(@sock.read(bulklen))
415
+ @sock.read(2) # Discard CRLF.
416
+ reply
417
+ end
418
+
419
+ def format_multi_bulk_reply(line)
420
+ n = line.to_i
421
+ return if n == -1
422
+
423
+ Array.new(n) { read }
424
+ end
425
+ end
426
+ end
427
+ end
428
+
429
+ Redis::Connection.drivers << Redis::Connection::Ruby
@@ -0,0 +1,133 @@
1
+ require "redis/connection/command_helper"
2
+ require "redis/connection/registry"
3
+ require "redis/errors"
4
+ require "em-synchrony"
5
+ require "hiredis/reader"
6
+
7
+ class Redis
8
+ module Connection
9
+ class RedisClient < EventMachine::Connection
10
+ include EventMachine::Deferrable
11
+
12
+ attr_accessor :timeout
13
+
14
+ def post_init
15
+ @req = nil
16
+ @connected = false
17
+ @reader = ::Hiredis::Reader.new
18
+ end
19
+
20
+ def connection_completed
21
+ @connected = true
22
+ succeed
23
+ end
24
+
25
+ def connected?
26
+ @connected
27
+ end
28
+
29
+ def receive_data(data)
30
+ @reader.feed(data)
31
+
32
+ loop do
33
+ begin
34
+ reply = @reader.gets
35
+ rescue RuntimeError => err
36
+ @req.fail [:error, ProtocolError.new(err.message)]
37
+ break
38
+ end
39
+
40
+ break if reply == false
41
+
42
+ reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
43
+ @req.succeed [:reply, reply]
44
+ end
45
+ end
46
+
47
+ def read
48
+ @req = EventMachine::DefaultDeferrable.new
49
+ if @timeout > 0
50
+ @req.timeout(@timeout, :timeout)
51
+ end
52
+ EventMachine::Synchrony.sync @req
53
+ end
54
+
55
+ def send(data)
56
+ callback { send_data data }
57
+ end
58
+
59
+ def unbind
60
+ @connected = false
61
+ if @req
62
+ @req.fail [:error, Errno::ECONNRESET]
63
+ @req = nil
64
+ else
65
+ fail
66
+ end
67
+ end
68
+ end
69
+
70
+ class Synchrony
71
+ include Redis::Connection::CommandHelper
72
+
73
+ def self.connect(config)
74
+ if config[:scheme] == "unix"
75
+ conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
76
+ elsif config[:scheme] == "rediss" || config[:ssl]
77
+ raise NotImplementedError, "SSL not supported by synchrony driver"
78
+ else
79
+ conn = EventMachine.connect(config[:host], config[:port], RedisClient) do |c|
80
+ c.pending_connect_timeout = [config[:connect_timeout], 0.1].max
81
+ end
82
+ end
83
+
84
+ fiber = Fiber.current
85
+ conn.callback { fiber.resume }
86
+ conn.errback { fiber.resume :refused }
87
+
88
+ raise Errno::ECONNREFUSED if Fiber.yield == :refused
89
+
90
+ instance = new(conn)
91
+ instance.timeout = config[:read_timeout]
92
+ instance
93
+ end
94
+
95
+ def initialize(connection)
96
+ @connection = connection
97
+ end
98
+
99
+ def connected?
100
+ @connection && @connection.connected?
101
+ end
102
+
103
+ def timeout=(timeout)
104
+ @connection.timeout = timeout
105
+ end
106
+
107
+ def disconnect
108
+ @connection.close_connection
109
+ @connection = nil
110
+ end
111
+
112
+ def write(command)
113
+ @connection.send(build_command(command))
114
+ end
115
+
116
+ def read
117
+ type, payload = @connection.read
118
+
119
+ if type == :reply
120
+ payload
121
+ elsif type == :error
122
+ raise payload
123
+ elsif type == :timeout
124
+ raise TimeoutError
125
+ else
126
+ raise "Unknown type #{type.inspect}"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ Redis::Connection.drivers << Redis::Connection::Synchrony
@@ -0,0 +1,9 @@
1
+ require "redis/connection/registry"
2
+
3
+ # If a connection driver was required before this file, the array
4
+ # Redis::Connection.drivers will contain one or more classes. The last driver
5
+ # in this array will be used as default driver. If this array is empty, we load
6
+ # the plain Ruby driver as our default. Another driver can be required at a
7
+ # later point in time, causing it to be the last element of the #drivers array
8
+ # and therefore be chosen by default.
9
+ require "redis/connection/ruby" if Redis::Connection.drivers.empty?