redis-cluster-client 0.9.0 → 0.10.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: 97383b0daf1dcc2e5fcd8e50640e9ecbd903562a10cca0f4996ada1807469f80
4
- data.tar.gz: 675ae25f2fbf2d9d67234b4e1ad81894656f11a32fe4cd1ebf8ae73c90c67509
3
+ metadata.gz: f88b4bd96fd24566377d49a45a06eaa5fc8029749462995e746074979ba25e70
4
+ data.tar.gz: a5ecd1339399ba2dda3c004c1cf1bbb2e2510c2f963f0f69afcf71544a8b530c
5
5
  SHA512:
6
- metadata.gz: 851565ace738fb9bf51d1211ece97767520c94a7b02e49b053732de351d77a30e7104ae1f8143a0ee3903a2b99de39b298b3eec80c2fb94b08fb4747180bb03d
7
- data.tar.gz: 0a0b6ada72bccfcdb7cecda533f8f31761f15f991e359bc211a4d54ba973b2c68983efd3a9a594e7baab11b614fecb058de98b71f1890f7e52150f40e2c34d1b
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
@@ -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
@@ -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.extract_hash_tag(command[1]).empty? # 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.0
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-02 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