redis 4.3.1 → 4.4.0

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: 416a2f007042c19453c13361aa4440a507e47fb32c28adc68e7c574c6651f5b4
4
- data.tar.gz: 1a845f2af649d64f8b274962c9d5d10e6eb5d046474b6e44288676432fe8a98b
3
+ metadata.gz: d5ff2ee4b6a6f2b087ac26bf96a3c1769cf42f70ea90008361157f7ef04cdb14
4
+ data.tar.gz: f2c24654294c4fa81a5cff4ddb545bc59e6f85b64ee61273278cb1e286a4edb8
5
5
  SHA512:
6
- metadata.gz: 3766992242ae284ca474bc8564c6760de88e635a8c3bc3c80da08062d698cc891bf00455b5d98768709ecc766f8ad305fe03cc5806f03fda3ebb93049e0a1cce
7
- data.tar.gz: f440c984ec58ff091a6a696952239cb04cf145752b485543e5da7215a327b40be4391b3fe6ca67753f84ec43913b9d90ec0b6f812e1696890a7c17cbf3aa3630
6
+ metadata.gz: 0d88c6621659a178dca04d3ca62f25520f5f1a846b6300f93fb008966551fb4795a3e6c37810f99ea18f77a6292b955fa180ae3e06f8c90df7e6a3ca27087ae1
7
+ data.tar.gz: 1427cc268e867872388f214184d23a5c6062104fcb9d1e50d6026dd9daf6e51b9833866fee9fcf80c7a64e4de705295de8399d8e8ac22fa890bf358bd63ff707
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.4.0
4
+
5
+ * Redis cluster: fix cross-slot validation in pipelines. Fix ##1019.
6
+ * Add support for `XAUTOCLAIM`. See #1018.
7
+ * Properly issue `READONLY` when reconnecting to replicas. Fix #1017.
8
+ * Make `del` a noop if passed an empty list of keys. See #998.
9
+ * Add support for `ZINTER`. See #995.
10
+
3
11
  # 4.3.1
4
12
 
5
13
  * Fix password authentication against redis server 5 and older.
data/lib/redis.rb CHANGED
@@ -555,6 +555,9 @@ class Redis
555
555
  # @param [String, Array<String>] keys
556
556
  # @return [Integer] number of keys that were deleted
557
557
  def del(*keys)
558
+ keys.flatten!(1)
559
+ return 0 if keys.empty?
560
+
558
561
  synchronize do |client|
559
562
  client.call([:del] + keys)
560
563
  end
@@ -2062,6 +2065,45 @@ class Redis
2062
2065
  end
2063
2066
  end
2064
2067
 
2068
+ # Return the intersection of multiple sorted sets
2069
+ #
2070
+ # @example Retrieve the intersection of `2*zsetA` and `1*zsetB`
2071
+ # redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0])
2072
+ # # => ["v1", "v2"]
2073
+ # @example Retrieve the intersection of `2*zsetA` and `1*zsetB`, and their scores
2074
+ # redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0], :with_scores => true)
2075
+ # # => [["v1", 3.0], ["v2", 6.0]]
2076
+ #
2077
+ # @param [String, Array<String>] keys one or more keys to intersect
2078
+ # @param [Hash] options
2079
+ # - `:weights => [Float, Float, ...]`: weights to associate with source
2080
+ # sorted sets
2081
+ # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
2082
+ # - `:with_scores => true`: include scores in output
2083
+ #
2084
+ # @return [Array<String>, Array<[String, Float]>]
2085
+ # - when `:with_scores` is not specified, an array of members
2086
+ # - when `:with_scores` is specified, an array with `[member, score]` pairs
2087
+ def zinter(*keys, weights: nil, aggregate: nil, with_scores: false)
2088
+ args = [:zinter, keys.size, *keys]
2089
+
2090
+ if weights
2091
+ args << "WEIGHTS"
2092
+ args.concat(weights)
2093
+ end
2094
+
2095
+ args << "AGGREGATE" << aggregate if aggregate
2096
+
2097
+ if with_scores
2098
+ args << "WITHSCORES"
2099
+ block = FloatifyPairs
2100
+ end
2101
+
2102
+ synchronize do |client|
2103
+ client.call(args, &block)
2104
+ end
2105
+ end
2106
+
2065
2107
  # Intersect multiple sorted sets and store the resulting sorted set in a new
2066
2108
  # key.
2067
2109
  #
@@ -3238,6 +3280,38 @@ class Redis
3238
3280
  synchronize { |client| client.call(args, &blk) }
3239
3281
  end
3240
3282
 
3283
+ # Transfers ownership of pending stream entries that match the specified criteria.
3284
+ #
3285
+ # @example Claim next pending message stuck > 5 minutes and mark as retry
3286
+ # redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0')
3287
+ # @example Claim 50 next pending messages stuck > 5 minutes and mark as retry
3288
+ # redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', count: 50)
3289
+ # @example Claim next pending message stuck > 5 minutes and don't mark as retry
3290
+ # redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', justid: true)
3291
+ # @example Claim next pending message after this id stuck > 5 minutes and mark as retry
3292
+ # redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '1641321233-0')
3293
+ #
3294
+ # @param key [String] the stream key
3295
+ # @param group [String] the consumer group name
3296
+ # @param consumer [String] the consumer name
3297
+ # @param min_idle_time [Integer] the number of milliseconds
3298
+ # @param start [String] entry id to start scanning from or 0-0 for everything
3299
+ # @param count [Integer] number of messages to claim (default 1)
3300
+ # @param justid [Boolean] whether to fetch just an array of entry ids or not.
3301
+ # Does not increment retry count when true
3302
+ #
3303
+ # @return [Hash{String => Hash}] the entries successfully claimed
3304
+ # @return [Array<String>] the entry ids successfully claimed if justid option is `true`
3305
+ def xautoclaim(key, group, consumer, min_idle_time, start, count: nil, justid: false)
3306
+ args = [:xautoclaim, key, group, consumer, min_idle_time, start]
3307
+ if count
3308
+ args << 'COUNT' << count.to_s
3309
+ end
3310
+ args << 'JUSTID' if justid
3311
+ blk = justid ? HashifyStreamAutoclaimJustId : HashifyStreamAutoclaim
3312
+ synchronize { |client| client.call(args, &blk) }
3313
+ end
3314
+
3241
3315
  # Fetches not acknowledging pending entries
3242
3316
  #
3243
3317
  # @example With key and group
@@ -3448,6 +3522,20 @@ class Redis
3448
3522
  end
3449
3523
  }
3450
3524
 
3525
+ HashifyStreamAutoclaim = lambda { |reply|
3526
+ {
3527
+ 'next' => reply[0],
3528
+ 'entries' => reply[1].map { |entry| [entry[0], entry[1].each_slice(2).to_h] }
3529
+ }
3530
+ }
3531
+
3532
+ HashifyStreamAutoclaimJustId = lambda { |reply|
3533
+ {
3534
+ 'next' => reply[0],
3535
+ 'entries' => reply[1]
3536
+ }
3537
+ }
3538
+
3451
3539
  HashifyStreamPendings = lambda { |reply|
3452
3540
  {
3453
3541
  'size' => reply[0],
data/lib/redis/client.rb CHANGED
@@ -126,6 +126,8 @@ class Redis
126
126
  call [:auth, password]
127
127
  end
128
128
  end
129
+
130
+ call [:readonly] if @options[:readonly]
129
131
  call [:select, db] if db != 0
130
132
  call [:client, :setname, @options[:id]] if @options[:id]
131
133
  @connector.check(self)
data/lib/redis/cluster.rb CHANGED
@@ -78,11 +78,13 @@ class Redis
78
78
  end
79
79
 
80
80
  def call_pipeline(pipeline)
81
- node_keys, command_keys = extract_keys_in_pipeline(pipeline)
82
- raise CrossSlotPipeliningError, command_keys if node_keys.size > 1
81
+ node_keys = pipeline.commands.map { |cmd| find_node_key(cmd, primary_only: true) }.compact.uniq
82
+ if node_keys.size > 1
83
+ raise(CrossSlotPipeliningError,
84
+ pipeline.commands.map { |cmd| @command.extract_first_key(cmd) }.reject(&:empty?).uniq)
85
+ end
83
86
 
84
- node = find_node(node_keys.first)
85
- try_send(node, :call_pipeline, pipeline)
87
+ try_send(find_node(node_keys.first), :call_pipeline, pipeline)
86
88
  end
87
89
 
88
90
  def call_with_timeout(command, timeout, &block)
@@ -253,14 +255,14 @@ class Redis
253
255
  find_node(node_key)
254
256
  end
255
257
 
256
- def find_node_key(command)
258
+ def find_node_key(command, primary_only: false)
257
259
  key = @command.extract_first_key(command)
258
260
  return if key.empty?
259
261
 
260
262
  slot = KeySlotConverter.convert(key)
261
263
  return unless @slot.exists?(slot)
262
264
 
263
- if @command.should_send_to_master?(command)
265
+ if @command.should_send_to_master?(command) || primary_only
264
266
  @slot.find_node_key_of_master(slot)
265
267
  else
266
268
  @slot.find_node_key_of_slave(slot)
@@ -285,11 +287,5 @@ class Redis
285
287
  @node.map(&:disconnect)
286
288
  @node, @slot = fetch_cluster_info!(@option)
287
289
  end
288
-
289
- def extract_keys_in_pipeline(pipeline)
290
- node_keys = pipeline.commands.map { |cmd| find_node_key(cmd) }.compact.uniq
291
- command_keys = pipeline.commands.map { |cmd| @command.extract_first_key(cmd) }.reject(&:empty?)
292
- [node_keys, command_keys]
293
- end
294
290
  end
295
291
  end
@@ -76,8 +76,9 @@ class Redis
76
76
  clients = options.map do |node_key, option|
77
77
  next if replica_disabled? && slave?(node_key)
78
78
 
79
+ option = option.merge(readonly: true) if slave?(node_key)
80
+
79
81
  client = Client.new(option)
80
- client.call(%i[readonly]) if slave?(node_key)
81
82
  [node_key, client]
82
83
  end
83
84
 
@@ -674,6 +674,13 @@ class Redis
674
674
  node_for(key).zcount(key, min, max)
675
675
  end
676
676
 
677
+ # Get the intersection of multiple sorted sets
678
+ def zinter(*keys, **options)
679
+ ensure_same_node(:zinter, keys) do |node|
680
+ node.zinter(*keys, **options)
681
+ end
682
+ end
683
+
677
684
  # Intersect multiple sorted sets and store the resulting sorted set in a new
678
685
  # key.
679
686
  def zinterstore(destination, keys, **options)
data/lib/redis/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '4.3.1'
4
+ VERSION = '4.4.0'
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.3.1
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -16,7 +16,7 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2021-06-11 00:00:00.000000000 Z
19
+ date: 2021-07-28 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: em-synchrony
@@ -102,9 +102,9 @@ licenses:
102
102
  metadata:
103
103
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
104
104
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
105
- documentation_uri: https://www.rubydoc.info/gems/redis/4.3.1
105
+ documentation_uri: https://www.rubydoc.info/gems/redis/4.4.0
106
106
  homepage_uri: https://github.com/redis/redis-rb
107
- source_code_uri: https://github.com/redis/redis-rb/tree/v4.3.1
107
+ source_code_uri: https://github.com/redis/redis-rb/tree/v4.4.0
108
108
  post_install_message:
109
109
  rdoc_options: []
110
110
  require_paths: