redis-cluster-client 0.9.1 → 0.10.0

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: 75b8f7550c743c813f79d15ba60d5e78fe5e81c751854b5600cc1984b56256fa
4
- data.tar.gz: c560f4fb9a3e5e044a64c8b8c0da8bf51413d384dd19d069994f14f44e4d4055
3
+ metadata.gz: f88b4bd96fd24566377d49a45a06eaa5fc8029749462995e746074979ba25e70
4
+ data.tar.gz: a5ecd1339399ba2dda3c004c1cf1bbb2e2510c2f963f0f69afcf71544a8b530c
5
5
  SHA512:
6
- metadata.gz: 5165edd2f2ae4c27680be76227cc73ed1b5e5c17914dc08eb6f9015199d29bb14f0c4961f5a291c3e764b78dfee3892e6666fff6aca95bc466eab144d4ce43d4
7
- data.tar.gz: 91f09f17897dcd974f11001cd2ea0445a384cb83134d8b51835ad197835ee4710935253e024fd6c938f12fa10bb8daea56465ac7f522a6e2484ec25f942fcb0d
6
+ metadata.gz: 81b1776f48d1b84866c21e0f00ee644df2f077e06536a6af2b305e50104296b7dabeb9732cce51e0aaca6ce5111a406b21b14db8c114d56e2b3f8f4b7701f2f7
7
+ data.tar.gz: b2ecb424e00825a115d15808814ee58a7afc06205cf5ca1e4732ca7189a6b9d42d13597974fa8674ca6f1102aa13641d8b7b25883bcea9ede743e2df3dba4814
@@ -97,12 +97,6 @@ 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
-
106
100
  private
107
101
 
108
102
  def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity
@@ -153,6 +147,12 @@ class RedisClient
153
147
  idx = command&.flatten&.map(&:to_s)&.map(&:downcase)&.index(option_name&.downcase)
154
148
  idx.nil? ? 0 : idx + 1
155
149
  end
150
+
151
+ def determine_key_step(command)
152
+ name = ::RedisClient::Cluster::NormalizedCmdName.instance.get_by_command(command)
153
+ # Some commands like EVALSHA have zero as the step in COMMANDS somehow.
154
+ @commands[name].key_step == 0 ? 1 : @commands[name].key_step
155
+ end
156
156
  end
157
157
  end
158
158
  end
@@ -18,11 +18,6 @@ class RedisClient
18
18
  class Router
19
19
  ZERO_CURSOR_FOR_SCAN = '0'
20
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
26
21
 
27
22
  def initialize(config, concurrent_worker, pool: nil, **kwargs)
28
23
  @config = config.dup
@@ -334,27 +329,31 @@ class RedisClient
334
329
  end
335
330
  end
336
331
 
332
+ MULTIPLE_KEYS_COMMAND_TO_SINGLE = {
333
+ 'mget' => ['get', 1].freeze,
334
+ 'mset' => ['set', 2].freeze,
335
+ 'del' => ['del', 1].freeze
336
+ }.freeze
337
+
337
338
  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
339
+ # This implementation is prioritized performance rather than readability or so.
340
+ single_key_cmd, keys_step = MULTIPLE_KEYS_COMMAND_TO_SINGLE.fetch(cmd)
341
+
342
+ return try_send(assign_node(command), method, command, args, &block) if command.size <= keys_step + 1 || ::RedisClient::Cluster::KeySlotConverter.hash_tag_included?(command[1])
342
343
 
343
344
  seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
344
345
  pipeline = ::RedisClient::Cluster::Pipeline.new(self, @command_builder, @concurrent_worker, exception: true, seed: seed)
345
346
 
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)
347
+ single_command = Array.new(keys_step + 1)
349
348
  single_command[0] = single_key_cmd
350
- if key_step == 1
349
+ if keys_step == 1
351
350
  command[1..].each do |key|
352
351
  single_command[1] = key
353
352
  pipeline.call_v(single_command)
354
353
  end
355
354
  else
356
- command[1..].each_slice(key_step) do |v|
357
- key_step.times { |i| single_command[i + 1] = v[i] }
355
+ command[1..].each_slice(keys_step) do |v|
356
+ keys_step.times { |i| single_command[i + 1] = v[i] }
358
357
  pipeline.call_v(single_command)
359
358
  end
360
359
  end
@@ -16,42 +16,47 @@ class RedisClient
16
16
  def initialize(config, pool: nil, concurrency: nil, **kwargs)
17
17
  @config = config
18
18
  @concurrent_worker = ::RedisClient::Cluster::ConcurrentWorker.create(**(concurrency || {}))
19
- @router = ::RedisClient::Cluster::Router.new(config, @concurrent_worker, pool: pool, **kwargs)
20
19
  @command_builder = config.command_builder
20
+
21
+ @pool = pool
22
+ @kwargs = kwargs
23
+ @router = nil
24
+ @mutex = Mutex.new
21
25
  end
22
26
 
23
27
  def inspect
24
- "#<#{self.class.name} #{@router.node_keys.join(', ')}>"
28
+ node_keys = @router.nil? ? @config.startup_nodes.keys : router.node_keys
29
+ "#<#{self.class.name} #{node_keys.join(', ')}>"
25
30
  end
26
31
 
27
32
  def call(*args, **kwargs, &block)
28
33
  command = @command_builder.generate(args, kwargs)
29
- @router.send_command(:call_v, command, &block)
34
+ router.send_command(:call_v, command, &block)
30
35
  end
31
36
 
32
37
  def call_v(command, &block)
33
38
  command = @command_builder.generate(command)
34
- @router.send_command(:call_v, command, &block)
39
+ router.send_command(:call_v, command, &block)
35
40
  end
36
41
 
37
42
  def call_once(*args, **kwargs, &block)
38
43
  command = @command_builder.generate(args, kwargs)
39
- @router.send_command(:call_once_v, command, &block)
44
+ router.send_command(:call_once_v, command, &block)
40
45
  end
41
46
 
42
47
  def call_once_v(command, &block)
43
48
  command = @command_builder.generate(command)
44
- @router.send_command(:call_once_v, command, &block)
49
+ router.send_command(:call_once_v, command, &block)
45
50
  end
46
51
 
47
52
  def blocking_call(timeout, *args, **kwargs, &block)
48
53
  command = @command_builder.generate(args, kwargs)
49
- @router.send_command(:blocking_call_v, command, timeout, &block)
54
+ router.send_command(:blocking_call_v, command, timeout, &block)
50
55
  end
51
56
 
52
57
  def blocking_call_v(timeout, command, &block)
53
58
  command = @command_builder.generate(command)
54
- @router.send_command(:blocking_call_v, command, timeout, &block)
59
+ router.send_command(:blocking_call_v, command, timeout, &block)
55
60
  end
56
61
 
57
62
  def scan(*args, **kwargs, &block)
@@ -60,31 +65,31 @@ class RedisClient
60
65
  seed = Random.new_seed
61
66
  cursor = ZERO_CURSOR_FOR_SCAN
62
67
  loop do
63
- cursor, keys = @router.scan('SCAN', cursor, *args, seed: seed, **kwargs)
68
+ cursor, keys = router.scan('SCAN', cursor, *args, seed: seed, **kwargs)
64
69
  keys.each(&block)
65
70
  break if cursor == ZERO_CURSOR_FOR_SCAN
66
71
  end
67
72
  end
68
73
 
69
74
  def sscan(key, *args, **kwargs, &block)
70
- node = @router.assign_node(['SSCAN', key])
71
- @router.try_delegate(node, :sscan, key, *args, **kwargs, &block)
75
+ node = router.assign_node(['SSCAN', key])
76
+ router.try_delegate(node, :sscan, key, *args, **kwargs, &block)
72
77
  end
73
78
 
74
79
  def hscan(key, *args, **kwargs, &block)
75
- node = @router.assign_node(['HSCAN', key])
76
- @router.try_delegate(node, :hscan, key, *args, **kwargs, &block)
80
+ node = router.assign_node(['HSCAN', key])
81
+ router.try_delegate(node, :hscan, key, *args, **kwargs, &block)
77
82
  end
78
83
 
79
84
  def zscan(key, *args, **kwargs, &block)
80
- node = @router.assign_node(['ZSCAN', key])
81
- @router.try_delegate(node, :zscan, key, *args, **kwargs, &block)
85
+ node = router.assign_node(['ZSCAN', key])
86
+ router.try_delegate(node, :zscan, key, *args, **kwargs, &block)
82
87
  end
83
88
 
84
89
  def pipelined(exception: true)
85
90
  seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
86
91
  pipeline = ::RedisClient::Cluster::Pipeline.new(
87
- @router,
92
+ router,
88
93
  @command_builder,
89
94
  @concurrent_worker,
90
95
  exception: exception,
@@ -99,14 +104,14 @@ class RedisClient
99
104
 
100
105
  def multi(watch: nil)
101
106
  if watch.nil? || watch.empty?
102
- transaction = ::RedisClient::Cluster::Transaction.new(@router, @command_builder)
107
+ transaction = ::RedisClient::Cluster::Transaction.new(router, @command_builder)
103
108
  yield transaction
104
109
  return transaction.execute
105
110
  end
106
111
 
107
- ::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, slot, asking|
112
+ ::RedisClient::Cluster::OptimisticLocking.new(router).watch(watch) do |c, slot, asking|
108
113
  transaction = ::RedisClient::Cluster::Transaction.new(
109
- @router, @command_builder, node: c, slot: slot, asking: asking
114
+ router, @command_builder, node: c, slot: slot, asking: asking
110
115
  )
111
116
  yield transaction
112
117
  transaction.execute
@@ -114,7 +119,7 @@ class RedisClient
114
119
  end
115
120
 
116
121
  def pubsub
117
- ::RedisClient::Cluster::PubSub.new(@router, @command_builder)
122
+ ::RedisClient::Cluster::PubSub.new(router, @command_builder)
118
123
  end
119
124
 
120
125
  def with(...)
@@ -122,25 +127,33 @@ class RedisClient
122
127
  end
123
128
 
124
129
  def close
130
+ @router&.close
125
131
  @concurrent_worker.close
126
- @router.close
127
132
  nil
128
133
  end
129
134
 
130
135
  private
131
136
 
137
+ def router
138
+ return @router unless @router.nil?
139
+
140
+ @mutex.synchronize do
141
+ @router ||= ::RedisClient::Cluster::Router.new(@config, @concurrent_worker, pool: @pool, **@kwargs)
142
+ end
143
+ end
144
+
132
145
  def method_missing(name, *args, **kwargs, &block)
133
- if @router.command_exists?(name)
146
+ if router.command_exists?(name)
134
147
  args.unshift(name)
135
148
  command = @command_builder.generate(args, kwargs)
136
- return @router.send_command(:call_v, command, &block)
149
+ return router.send_command(:call_v, command, &block)
137
150
  end
138
151
 
139
152
  super
140
153
  end
141
154
 
142
155
  def respond_to_missing?(name, include_private = false)
143
- return true if @router.command_exists?(name)
156
+ return true if router.command_exists?(name)
144
157
 
145
158
  super
146
159
  end
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.9.1
4
+ version: 0.10.0
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-05-04 00:00:00.000000000 Z
11
+ date: 2024-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client