redis 4.2.0 → 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 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: []