redis-cluster-client 0.8.2 → 0.9.1

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: 7986c9cc2ea7af5a128397b327e1a4b001740ac6a49af09d8f3ed507665b39d9
4
- data.tar.gz: fcb8ef4cbc7095b8b57f9570b24dd4dc4d9b4a517b0e9d2451aa9c740c676989
3
+ metadata.gz: 75b8f7550c743c813f79d15ba60d5e78fe5e81c751854b5600cc1984b56256fa
4
+ data.tar.gz: c560f4fb9a3e5e044a64c8b8c0da8bf51413d384dd19d069994f14f44e4d4055
5
5
  SHA512:
6
- metadata.gz: d2624fa1a7ff96f625816beb5f53cac2727c1649f44cb4170f2c744b60f8f4b03eb4ba764cfaba41d867f73807b24965c3fbd2938b3875d0cabf37ccf69bcf32
7
- data.tar.gz: b062efff7fea22cda0379c8749c00315d949ad82d491b93307f3c8f42f2af0b563d3af270a1c63bb7b497c9e826f33369618e5dd93fe58415b6097eea9f600b9
6
+ metadata.gz: 5165edd2f2ae4c27680be76227cc73ed1b5e5c17914dc08eb6f9015199d29bb14f0c4961f5a291c3e764b78dfee3892e6666fff6aca95bc466eab144d4ce43d4
7
+ data.tar.gz: 91f09f17897dcd974f11001cd2ea0445a384cb83134d8b51835ad197835ee4710935253e024fd6c938f12fa10bb8daea56465ac7f522a6e2484ec25f942fcb0d
@@ -97,6 +97,12 @@ class RedisClient
97
97
  @commands.key?(::RedisClient::Cluster::NormalizedCmdName.instance.get_by_name(name))
98
98
  end
99
99
 
100
+ def determine_key_step(command)
101
+ name = ::RedisClient::Cluster::NormalizedCmdName.instance.get_by_command(command)
102
+ # Some commands like EVALSHA have zero as the step in COMMANDS somehow.
103
+ @commands[name].key_step == 0 ? 1 : @commands[name].key_step
104
+ end
105
+
100
106
  private
101
107
 
102
108
  def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity
@@ -143,12 +149,6 @@ class RedisClient
143
149
  end
144
150
  end
145
151
 
146
- def determine_key_step(command)
147
- name = ::RedisClient::Cluster::NormalizedCmdName.instance.get_by_command(command)
148
- # Some commands like EVALSHA have zero as the step in COMMANDS somehow.
149
- @commands[name].key_step == 0 ? 1 : @commands[name].key_step
150
- end
151
-
152
152
  def determine_optional_key_position(command, option_name) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
153
153
  idx = command&.flatten&.map(&:to_s)&.map(&:downcase)&.index(option_name&.downcase)
154
154
  idx.nil? ? 0 : idx + 1
@@ -70,6 +70,17 @@ class RedisClient
70
70
 
71
71
  key[s + 1..e - 1]
72
72
  end
73
+
74
+ def hash_tag_included?(key)
75
+ key = key.to_s
76
+ s = key.index(LEFT_BRACKET)
77
+ return false if s.nil?
78
+
79
+ e = key.index(RIGHT_BRACKET, s + 1)
80
+ return false if e.nil?
81
+
82
+ s + 1 < e
83
+ end
73
84
  end
74
85
  end
75
86
  end
@@ -5,6 +5,9 @@ class RedisClient
5
5
  class Node
6
6
  class BaseTopology
7
7
  IGNORE_GENERIC_CONFIG_KEYS = %i[url host port path].freeze
8
+ EMPTY_HASH = {}.freeze
9
+ EMPTY_ARRAY = [].freeze
10
+
8
11
  attr_reader :clients, :primary_clients, :replica_clients
9
12
 
10
13
  def initialize(pool, concurrent_worker, **kwargs)
@@ -92,13 +92,7 @@ class RedisClient
92
92
  end
93
93
  end
94
94
 
95
- def initialize(
96
- concurrent_worker,
97
- config:,
98
- pool: nil,
99
- **kwargs
100
- )
101
-
95
+ def initialize(concurrent_worker, config:, pool: nil, **kwargs)
102
96
  @concurrent_worker = concurrent_worker
103
97
  @slots = build_slot_node_mappings(EMPTY_ARRAY)
104
98
  @replications = build_replication_mappings(EMPTY_ARRAY)
@@ -10,6 +10,7 @@ require 'redis_client/cluster/node_key'
10
10
  require 'redis_client/cluster/normalized_cmd_name'
11
11
  require 'redis_client/cluster/transaction'
12
12
  require 'redis_client/cluster/optimistic_locking'
13
+ require 'redis_client/cluster/pipeline'
13
14
  require 'redis_client/cluster/error_identification'
14
15
 
15
16
  class RedisClient
@@ -17,6 +18,11 @@ class RedisClient
17
18
  class Router
18
19
  ZERO_CURSOR_FOR_SCAN = '0'
19
20
  TSF = ->(f, x) { f.nil? ? x : f.call(x) }.curry
21
+ MULTIPLE_KEYS_COMMAND_TO_PIPELINE = {
22
+ 'mset' => 'set',
23
+ 'mget' => 'get',
24
+ 'del' => 'del'
25
+ }.freeze
20
26
 
21
27
  def initialize(config, concurrent_worker, pool: nil, **kwargs)
22
28
  @config = config.dup
@@ -48,6 +54,8 @@ class RedisClient
48
54
  when 'script' then send_script_command(method, command, args, &block)
49
55
  when 'pubsub' then send_pubsub_command(method, command, args, &block)
50
56
  when 'watch' then send_watch_command(command, &block)
57
+ when 'mset', 'mget', 'del'
58
+ send_multiple_keys_command(cmd, method, command, args, &block)
51
59
  when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
52
60
  @node.call_all(method, command, args).first.then(&TSF.call(block))
53
61
  when 'flushall', 'flushdb'
@@ -314,7 +322,6 @@ class RedisClient
314
322
  end
315
323
  end
316
324
 
317
- # for redis-rb
318
325
  def send_watch_command(command)
319
326
  raise ::RedisClient::Cluster::Transaction::ConsistencyError, 'A block required. And you need to use the block argument as a client for the transaction.' unless block_given?
320
327
 
@@ -327,6 +334,40 @@ class RedisClient
327
334
  end
328
335
  end
329
336
 
337
+ def send_multiple_keys_command(cmd, method, command, args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
338
+ key_step = @command.determine_key_step(cmd)
339
+ if command.size <= key_step + 1 || ::RedisClient::Cluster::KeySlotConverter.hash_tag_included?(command[1]) # rubocop:disable Style/IfUnlessModifier
340
+ return try_send(assign_node(command), method, command, args, &block)
341
+ end
342
+
343
+ seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
344
+ pipeline = ::RedisClient::Cluster::Pipeline.new(self, @command_builder, @concurrent_worker, exception: true, seed: seed)
345
+
346
+ # This implementation is prioritized to lessen memory consumption rather than readability.
347
+ single_key_cmd = MULTIPLE_KEYS_COMMAND_TO_PIPELINE[cmd]
348
+ single_command = Array.new(key_step + 1)
349
+ single_command[0] = single_key_cmd
350
+ if key_step == 1
351
+ command[1..].each do |key|
352
+ single_command[1] = key
353
+ pipeline.call_v(single_command)
354
+ end
355
+ else
356
+ command[1..].each_slice(key_step) do |v|
357
+ key_step.times { |i| single_command[i + 1] = v[i] }
358
+ pipeline.call_v(single_command)
359
+ end
360
+ end
361
+
362
+ replies = pipeline.execute
363
+ result = case cmd
364
+ when 'mset' then replies.first
365
+ when 'del' then replies.sum
366
+ else replies
367
+ end
368
+ block_given? ? yield(result) : result
369
+ end
370
+
330
371
  def update_cluster_info!
331
372
  @node.reload!
332
373
  end
@@ -5,7 +5,6 @@ require 'redis_client/cluster/pipeline'
5
5
  require 'redis_client/cluster/pub_sub'
6
6
  require 'redis_client/cluster/router'
7
7
  require 'redis_client/cluster/transaction'
8
- require 'redis_client/cluster/pinning_node'
9
8
  require 'redis_client/cluster/optimistic_locking'
10
9
 
11
10
  class RedisClient
@@ -118,13 +117,8 @@ class RedisClient
118
117
  ::RedisClient::Cluster::PubSub.new(@router, @command_builder)
119
118
  end
120
119
 
121
- # TODO: This isn't an official public interface yet. Don't use in your production environment.
122
- # @see https://github.com/redis-rb/redis-cluster-client/issues/299
123
- def with(key: nil, hashtag: nil, write: true)
124
- key = process_with_arguments(key, hashtag)
125
- node_key = @router.find_node_key_by_key(key, primary: write)
126
- node = @router.find_node(node_key)
127
- node.with { |c| yield ::RedisClient::Cluster::PinningNode.new(c) }
120
+ def with(...)
121
+ raise NotImplementedError, 'No way to use'
128
122
  end
129
123
 
130
124
  def close
@@ -135,19 +129,6 @@ class RedisClient
135
129
 
136
130
  private
137
131
 
138
- def process_with_arguments(key, hashtag) # rubocop:disable Metrics/CyclomaticComplexity
139
- raise ArgumentError, 'Only one of key or hashtag may be provided' if key && hashtag
140
-
141
- if hashtag
142
- # The documentation says not to wrap your hashtag in {}, but people will probably
143
- # do it anyway and it's easy for us to fix here.
144
- key = hashtag&.match?(/^{.*}$/) ? hashtag : "{#{hashtag}}"
145
- end
146
- raise ArgumentError, 'One of key or hashtag must be provided' if key.nil? || key.empty?
147
-
148
- key
149
- end
150
-
151
132
  def method_missing(name, *args, **kwargs, &block)
152
133
  if @router.command_exists?(name)
153
134
  args.unshift(name)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-cluster-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taishi Kasuga
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-16 00:00:00.000000000 Z
11
+ date: 2024-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -50,7 +50,6 @@ files:
50
50
  - lib/redis_client/cluster/node_key.rb
51
51
  - lib/redis_client/cluster/normalized_cmd_name.rb
52
52
  - lib/redis_client/cluster/optimistic_locking.rb
53
- - lib/redis_client/cluster/pinning_node.rb
54
53
  - lib/redis_client/cluster/pipeline.rb
55
54
  - lib/redis_client/cluster/pub_sub.rb
56
55
  - lib/redis_client/cluster/router.rb
@@ -78,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
77
  - !ruby/object:Gem::Version
79
78
  version: '0'
80
79
  requirements: []
81
- rubygems_version: 3.5.3
80
+ rubygems_version: 3.5.9
82
81
  signing_key:
83
82
  specification_version: 4
84
83
  summary: A Redis cluster client for Ruby
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class RedisClient
4
- class Cluster
5
- class PinningNode
6
- def initialize(client)
7
- @client = client
8
- end
9
-
10
- def call(*args, **kwargs, &block)
11
- @client.call(*args, **kwargs, &block)
12
- end
13
-
14
- def call_v(args, &block)
15
- @client.call_v(args, &block)
16
- end
17
-
18
- def call_once(*args, **kwargs, &block)
19
- @client.call_once(*args, **kwargs, &block)
20
- end
21
-
22
- def call_once_v(args, &block)
23
- @client.call_once_v(args, &block)
24
- end
25
-
26
- def blocking_call(timeout, *args, **kwargs, &block)
27
- @client.blocking_call(timeout, *args, **kwargs, &block)
28
- end
29
-
30
- def blocking_call_v(timeout, args, &block)
31
- @client.blocking_call_v(timeout, args, &block)
32
- end
33
- end
34
- end
35
- end