redis 4.2.0 → 4.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9796f6646b7d3aaeeb5ef37629fb1a43422285724d8d2901a219ef4f2882eff5
4
- data.tar.gz: b89f4f1d6a3c9ee93202ce08cdcd3ed184694b5693f7461be7cf7e517139a278
3
+ metadata.gz: 862e8133262fead707e4ca317b29d0e35425e3a7861ea1a52033bc91ba61bf6d
4
+ data.tar.gz: 5b2b32250d783fe58b0af54cc386f2568241644a0badc0b7247bb29b1ac94a93
5
5
  SHA512:
6
- metadata.gz: be709e1aad1acee8d7c3e121e946060ce9b693ac80e25af200e2a579988f3952d6522cb9855917dc76628ae2038365bb8754b49a7cc6e90395706ba30fc87a86
7
- data.tar.gz: 00102b01b4b37daab76fc90990f980a4710bec0e797a70d65a7544ef304f01f9b9babbdcc680da71513dd8f79649bd5f529e6804e71297b26978625bea746367
6
+ metadata.gz: 2aab289f4f22b2f3a804ca7b0da4cf95e352a8d246611490d8d803edebbbc7e7c299355cd0b90e6f3ac8bc0d11e9bf3792a328c95847d32e1d984729afe66ed2
7
+ data.tar.gz: d9ec8ba4d314d099e909cdddf6dfb4c3c14b853b46f45c4909ac3ba10fb1880bd9a7b0465257fa91f9a4ea6c9f82723c16c177810ac15c89fab3790d7af31ad0
@@ -1,5 +1,29 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.2.5
4
+
5
+ * Optimize the ruby connector write buffering. See #964.
6
+
7
+ # 4.2.4
8
+
9
+ * Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
10
+
11
+ # 4.2.3
12
+
13
+ * Use io/wait instead of IO.select in the ruby connector. See #960.
14
+ * Use exception free non blocking IOs in the ruby connector. See #926.
15
+ * Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
16
+
17
+ # 4.2.2
18
+
19
+ * Fix `WATCH` support for `Redis::Distributed`. See #941.
20
+ * Fix handling of empty stream responses. See #905, #929.
21
+
22
+ # 4.2.1
23
+
24
+ * Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
25
+ * Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
26
+
3
27
  # 4.2.0
4
28
 
5
29
  * Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
@@ -12,6 +36,7 @@
12
36
  * Optimized initialization of Redis::Cluster. See #912.
13
37
  * Accept sentinel options even with string key. See #599.
14
38
  * Verify TLS connections by default. See #900.
39
+ * Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
15
40
 
16
41
  # 4.1.4
17
42
 
data/README.md CHANGED
@@ -265,6 +265,7 @@ All timeout values are specified in seconds.
265
265
  When using pub/sub, you can subscribe to a channel using a timeout as well:
266
266
 
267
267
  ```ruby
268
+ redis = Redis.new(reconnect_attempts: 0)
268
269
  redis.subscribe_with_timeout(5, "news") do |on|
269
270
  on.message do |channel, message|
270
271
  # ...
@@ -5,7 +5,20 @@ require_relative "redis/errors"
5
5
 
6
6
  class Redis
7
7
  class << self
8
- attr_accessor :exists_returns_integer
8
+ attr_reader :exists_returns_integer
9
+
10
+ def exists_returns_integer=(value)
11
+ unless value
12
+ message = "`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
13
+ "disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
14
+ "`exists?` instead."
15
+
16
+ ::Kernel.warn(message)
17
+ end
18
+
19
+ @exists_returns_integer = value
20
+ end
21
+
9
22
  attr_writer :current
10
23
  end
11
24
 
@@ -561,11 +574,16 @@ class Redis
561
574
  # @return [Integer]
562
575
  def exists(*keys)
563
576
  if !Redis.exists_returns_integer && keys.size == 1
564
- message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
565
- "use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
566
- "(#{::Kernel.caller(1, 1).first})\n"
577
+ if Redis.exists_returns_integer.nil?
578
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
579
+ "should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
580
+ "true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
581
+ "`Redis.exists_returns_integer = false`, but this option will be removed in 5.0. " \
582
+ "(#{::Kernel.caller(1, 1).first})\n"
583
+
584
+ ::Kernel.warn(message)
585
+ end
567
586
 
568
- ::Kernel.warn(message)
569
587
  exists?(*keys)
570
588
  else
571
589
  _exists(*keys)
@@ -584,7 +602,9 @@ class Redis
584
602
  # @return [Boolean]
585
603
  def exists?(*keys)
586
604
  synchronize do |client|
587
- client.call([:exists, *keys], &Boolify)
605
+ client.call([:exists, *keys]) do |value|
606
+ value > 0
607
+ end
588
608
  end
589
609
  end
590
610
 
@@ -2418,14 +2438,13 @@ class Redis
2418
2438
  end
2419
2439
 
2420
2440
  def pipelined
2421
- synchronize do |_client|
2441
+ synchronize do |prior_client|
2422
2442
  begin
2423
- pipeline = Pipeline.new(@client)
2424
- original, @client = @client, pipeline
2443
+ @client = Pipeline.new(prior_client)
2425
2444
  yield(self)
2426
- original.call_pipeline(@client)
2445
+ prior_client.call_pipeline(@client)
2427
2446
  ensure
2428
- @client = original
2447
+ @client = prior_client
2429
2448
  end
2430
2449
  end
2431
2450
  end
@@ -2461,17 +2480,16 @@ class Redis
2461
2480
  # @see #watch
2462
2481
  # @see #unwatch
2463
2482
  def multi
2464
- synchronize do |client|
2483
+ synchronize do |prior_client|
2465
2484
  if !block_given?
2466
- client.call([:multi])
2485
+ prior_client.call([:multi])
2467
2486
  else
2468
2487
  begin
2469
- pipeline = Pipeline::Multi.new(@client)
2470
- original, @client = @client, pipeline
2488
+ @client = Pipeline::Multi.new(prior_client)
2471
2489
  yield(self)
2472
- original.call_pipeline(pipeline)
2490
+ prior_client.call_pipeline(@client)
2473
2491
  ensure
2474
- @client = original
2492
+ @client = prior_client
2475
2493
  end
2476
2494
  end
2477
2495
  end
@@ -3403,8 +3421,11 @@ class Redis
3403
3421
  end
3404
3422
  }
3405
3423
 
3424
+ EMPTY_STREAM_RESPONSE = [nil].freeze
3425
+ private_constant :EMPTY_STREAM_RESPONSE
3426
+
3406
3427
  HashifyStreamEntries = lambda { |reply|
3407
- reply.map do |entry_id, values|
3428
+ reply.compact.map do |entry_id, values|
3408
3429
  [entry_id, values.each_slice(2).to_h]
3409
3430
  end
3410
3431
  }
@@ -6,12 +6,16 @@ require "cgi"
6
6
 
7
7
  class Redis
8
8
  class Client
9
+ # Defaults are also used for converting string keys to symbols.
9
10
  DEFAULTS = {
10
11
  url: -> { ENV["REDIS_URL"] },
11
12
  scheme: "redis",
12
13
  host: "127.0.0.1",
13
14
  port: 6379,
14
15
  path: nil,
16
+ read_timeout: nil,
17
+ write_timeout: nil,
18
+ connect_timeout: nil,
15
19
  timeout: 5.0,
16
20
  password: nil,
17
21
  db: 0,
@@ -22,6 +26,7 @@ class Redis
22
26
  reconnect_delay: 0,
23
27
  reconnect_delay_max: 0.5,
24
28
  inherit_socket: false,
29
+ logger: nil,
25
30
  sentinels: nil,
26
31
  role: nil
27
32
  }.freeze
@@ -49,57 +49,50 @@ class Redis
49
49
  end
50
50
 
51
51
  def _read_from_socket(nbytes)
52
- begin
53
- read_nonblock(nbytes)
54
- rescue IO::WaitReadable
55
- if IO.select([self], nil, nil, @timeout)
56
- retry
57
- else
58
- raise Redis::TimeoutError
59
- end
60
- rescue IO::WaitWritable
61
- if IO.select(nil, [self], nil, @timeout)
62
- retry
63
- else
64
- raise Redis::TimeoutError
65
- end
66
- end
67
- rescue EOFError
68
- raise Errno::ECONNRESET
69
- end
70
-
71
- def _write_to_socket(data)
72
- begin
73
- write_nonblock(data)
74
- rescue IO::WaitWritable
75
- if IO.select(nil, [self], nil, @write_timeout)
76
- retry
77
- else
78
- raise Redis::TimeoutError
79
- end
80
- rescue IO::WaitReadable
81
- if IO.select([self], nil, nil, @write_timeout)
82
- retry
83
- else
84
- 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
85
66
  end
86
67
  end
87
- rescue EOFError
88
- raise Errno::ECONNRESET
89
68
  end
90
69
 
91
- def write(data)
92
- return super(data) unless @write_timeout
70
+ def write(buffer)
71
+ return super(buffer) unless @write_timeout
93
72
 
94
- length = data.bytesize
95
- total_count = 0
73
+ bytes_to_write = buffer.bytesize
74
+ total_bytes_written = 0
96
75
  loop do
97
- count = _write_to_socket(data)
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
98
89
 
99
- total_count += count
100
- return total_count if total_count >= length
90
+ if total_bytes_written >= bytes_to_write
91
+ return total_bytes_written
92
+ end
101
93
 
102
- data = data.byteslice(count..-1)
94
+ buffer = buffer.byteslice(bytes_written..-1)
95
+ end
103
96
  end
104
97
  end
105
98
  end
@@ -135,7 +128,7 @@ class Redis
135
128
  raise TimeoutError
136
129
  end
137
130
 
138
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
131
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
139
132
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
140
133
  # Use the blocking #readpartial method instead.
141
134
 
@@ -160,7 +153,7 @@ class Redis
160
153
  begin
161
154
  sock.connect_nonblock(sockaddr)
162
155
  rescue Errno::EINPROGRESS
163
- raise TimeoutError if IO.select(nil, [sock], nil, timeout).nil?
156
+ raise TimeoutError unless sock.wait_writable(timeout)
164
157
 
165
158
  begin
166
159
  sock.connect_nonblock(sockaddr)
@@ -215,7 +208,7 @@ class Redis
215
208
  begin
216
209
  sock.connect_nonblock(sockaddr)
217
210
  rescue Errno::EINPROGRESS
218
- raise TimeoutError if IO.select(nil, [sock], nil, timeout).nil?
211
+ raise TimeoutError unless sock.wait_writable(timeout)
219
212
 
220
213
  begin
221
214
  sock.connect_nonblock(sockaddr)
@@ -233,6 +226,18 @@ class Redis
233
226
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
234
227
  include SocketMixin
235
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
+
236
241
  def self.connect(host, port, timeout, ssl_params)
237
242
  # Note: this is using Redis::Connection::TCPSocket
238
243
  tcp_sock = TCPSocket.connect(host, port, timeout)
@@ -254,13 +259,13 @@ class Redis
254
259
  # Instead, you have to retry.
255
260
  ssl_sock.connect_nonblock
256
261
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
257
- if IO.select([ssl_sock], nil, nil, timeout)
262
+ if ssl_sock.wait_readable(timeout)
258
263
  retry
259
264
  else
260
265
  raise TimeoutError
261
266
  end
262
267
  rescue IO::WaitWritable
263
- if IO.select(nil, [ssl_sock], nil, timeout)
268
+ if ssl_sock.wait_writable(timeout)
264
269
  retry
265
270
  else
266
271
  raise TimeoutError
@@ -24,10 +24,14 @@ class Redis
24
24
  @default_options = options.dup
25
25
  node_configs.each { |node_config| add_node(node_config) }
26
26
  @subscribed_node = nil
27
+ @watch_key = nil
27
28
  end
28
29
 
29
30
  def node_for(key)
30
- @ring.get_node(key_tag(key.to_s) || key.to_s)
31
+ key = key_tag(key.to_s) || key.to_s
32
+ raise CannotDistribute, :watch if @watch_key && @watch_key != key
33
+
34
+ @ring.get_node(key)
31
35
  end
32
36
 
33
37
  def nodes
@@ -799,13 +803,26 @@ class Redis
799
803
  end
800
804
 
801
805
  # Watch the given keys to determine execution of the MULTI/EXEC block.
802
- def watch(*_keys)
803
- raise CannotDistribute, :watch
806
+ def watch(*keys, &block)
807
+ ensure_same_node(:watch, keys) do |node|
808
+ @watch_key = key_tag(keys.first) || keys.first.to_s
809
+
810
+ begin
811
+ node.watch(*keys, &block)
812
+ rescue StandardError
813
+ @watch_key = nil
814
+ raise
815
+ end
816
+ end
804
817
  end
805
818
 
806
819
  # Forget about all watched keys.
807
820
  def unwatch
808
- raise CannotDistribute, :unwatch
821
+ raise CannotDistribute, :unwatch unless @watch_key
822
+
823
+ result = node_for(@watch_key).unwatch
824
+ @watch_key = nil
825
+ result
809
826
  end
810
827
 
811
828
  def pipelined
@@ -813,18 +830,30 @@ class Redis
813
830
  end
814
831
 
815
832
  # Mark the start of a transaction block.
816
- def multi
817
- raise CannotDistribute, :multi
833
+ def multi(&block)
834
+ raise CannotDistribute, :multi unless @watch_key
835
+
836
+ result = node_for(@watch_key).multi(&block)
837
+ @watch_key = nil if block_given?
838
+ result
818
839
  end
819
840
 
820
841
  # Execute all commands issued after MULTI.
821
842
  def exec
822
- raise CannotDistribute, :exec
843
+ raise CannotDistribute, :exec unless @watch_key
844
+
845
+ result = node_for(@watch_key).exec
846
+ @watch_key = nil
847
+ result
823
848
  end
824
849
 
825
850
  # Discard all commands issued after MULTI.
826
851
  def discard
827
- raise CannotDistribute, :discard
852
+ raise CannotDistribute, :discard unless @watch_key
853
+
854
+ result = node_for(@watch_key).discard
855
+ @watch_key = nil
856
+ result
828
857
  end
829
858
 
830
859
  # Control remote script registry.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '4.2.0'
4
+ VERSION = '4.2.5'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -13,10 +13,10 @@ authors:
13
13
  - Michel Martens
14
14
  - Damian Janowski
15
15
  - Pieter Noordhuis
16
- autorequire:
16
+ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2020-06-09 00:00:00.000000000 Z
19
+ date: 2020-11-20 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: em-synchrony
@@ -99,8 +99,13 @@ files:
99
99
  homepage: https://github.com/redis/redis-rb
100
100
  licenses:
101
101
  - MIT
102
- metadata: {}
103
- post_install_message:
102
+ metadata:
103
+ bug_tracker_uri: https://github.com/redis/redis-rb/issues
104
+ changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
105
+ documentation_uri: https://www.rubydoc.info/gems/redis/4.2.5
106
+ homepage_uri: https://github.com/redis/redis-rb
107
+ source_code_uri: https://github.com/redis/redis-rb/tree/v4.2.5
108
+ post_install_message:
104
109
  rdoc_options: []
105
110
  require_paths:
106
111
  - lib
@@ -115,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
120
  - !ruby/object:Gem::Version
116
121
  version: '0'
117
122
  requirements: []
118
- rubygems_version: 3.0.4
119
- signing_key:
123
+ rubygems_version: 3.1.2
124
+ signing_key:
120
125
  specification_version: 4
121
126
  summary: A Ruby client library for Redis
122
127
  test_files: []