Skip to content

Commit b38c904

Browse files
authored
chore: use hard coding instead of using command information (#362)
1 parent 523fd6a commit b38c904

File tree

4 files changed

+52
-35
lines changed

4 files changed

+52
-35
lines changed

lib/redis_client/cluster/command.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,6 @@ def exists?(name)
9797
@commands.key?(::RedisClient::Cluster::NormalizedCmdName.instance.get_by_name(name))
9898
end
9999

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-
106100
private
107101

108102
def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity
@@ -153,6 +147,12 @@ def determine_optional_key_position(command, option_name) # rubocop:disable Metr
153147
idx = command&.flatten&.map(&:to_s)&.map(&:downcase)&.index(option_name&.downcase)
154148
idx.nil? ? 0 : idx + 1
155149
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
156156
end
157157
end
158158
end

lib/redis_client/cluster/router.rb

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ class Cluster
1818
class Router
1919
ZERO_CURSOR_FOR_SCAN = '0'
2020
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
2621

2722
def initialize(config, concurrent_worker, pool: nil, **kwargs)
2823
@config = config.dup
@@ -334,27 +329,31 @@ def send_watch_command(command)
334329
end
335330
end
336331

332+
MULTIPLE_KEYS_COMMAND_TO_SINGLE = {
333+
'mget' => ['get', 1].freeze,
334+
'mset' => ['set', 2].freeze,
335+
'del' => ['del', 1].freeze
336+
}.freeze
337+
337338
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])
342343

343344
seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
344345
pipeline = ::RedisClient::Cluster::Pipeline.new(self, @command_builder, @concurrent_worker, exception: true, seed: seed)
345346

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)
349348
single_command[0] = single_key_cmd
350-
if key_step == 1
349+
if keys_step == 1
351350
command[1..].each do |key|
352351
single_command[1] = key
353352
pipeline.call_v(single_command)
354353
end
355354
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] }
358357
pipeline.call_v(single_command)
359358
end
360359
end

test/redis_client/cluster/test_command.rb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,6 @@ def test_exists?
147147
end
148148
end
149149

150-
def test_determine_key_step
151-
cmd = ::RedisClient::Cluster::Command.load(@raw_clients)
152-
[
153-
{ name: 'MSET', want: 2 },
154-
{ name: 'MGET', want: 1 },
155-
{ name: 'DEL', want: 1 },
156-
{ name: 'EVALSHA', want: 1 }
157-
].each_with_index do |c, idx|
158-
msg = "Case: #{idx}"
159-
got = cmd.determine_key_step(c[:name])
160-
assert_equal(c[:want], got, msg)
161-
end
162-
end
163-
164150
def test_determine_first_key_position
165151
cmd = ::RedisClient::Cluster::Command.load(@raw_clients)
166152
[
@@ -205,6 +191,20 @@ def test_determine_optional_key_position
205191
end
206192
end
207193

194+
def test_determine_key_step
195+
cmd = ::RedisClient::Cluster::Command.load(@raw_clients)
196+
[
197+
{ name: 'MSET', want: 2 },
198+
{ name: 'MGET', want: 1 },
199+
{ name: 'DEL', want: 1 },
200+
{ name: 'EVALSHA', want: 1 }
201+
].each_with_index do |c, idx|
202+
msg = "Case: #{idx}"
203+
got = cmd.send(:determine_key_step, c[:name])
204+
assert_equal(c[:want], got, msg)
205+
end
206+
end
207+
208208
def test_extract_all_keys
209209
cmd = ::RedisClient::Cluster::Command.load(@raw_clients)
210210
[

test/redis_client/test_cluster.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ def test_transaction_with_single_key
207207
end
208208

209209
assert_equal(['OK', 1, 2], got)
210+
211+
wait_for_replication
210212
assert_equal('2', @client.call('GET', 'counter'))
211213
end
212214

@@ -284,6 +286,8 @@ def test_transaction_with_hashtag
284286
end
285287

286288
assert_equal(%w[OK OK], got)
289+
290+
wait_for_replication
287291
assert_equal(%w[1 2 3 4], @client.call('MGET', '{key}1', '{key}2', '{key}3', '{key}4'))
288292
end
289293

@@ -319,6 +323,8 @@ def test_transaction_with_watch
319323
end
320324

321325
assert_equal(%w[START OK OK FINISH], got)
326+
327+
wait_for_replication
322328
assert_equal(%w[1 2], @client.call('MGET', '{key}1', '{key}2'))
323329
end
324330

@@ -339,6 +345,7 @@ def test_transaction_with_unsafe_watch
339345
end
340346
end
341347

348+
wait_for_replication
342349
assert_equal(%w[0 0], @client.call('MGET', '{key}1', '{key}2'))
343350
end
344351

@@ -353,6 +360,8 @@ def test_transaction_with_meaningless_watch
353360
end
354361

355362
assert_equal(%w[START OK OK FINISH], got)
363+
364+
wait_for_replication
356365
assert_equal(%w[1 2], @client.call('MGET', '{key}1', '{key}2'))
357366
end
358367

@@ -392,6 +401,7 @@ def test_transaction_does_not_unwatch_on_connection_error
392401
tx.call('QUIT')
393402
end
394403
end
404+
395405
command_list = @captured_commands.to_a.map(&:command).map(&:first)
396406
assert_includes(command_list, 'WATCH')
397407
refute_includes(command_list, 'UNWATCH')
@@ -421,6 +431,7 @@ def test_transaction_does_not_retry_without_rewatching
421431
end
422432

423433
# The transaction did not commit.
434+
wait_for_replication
424435
assert_equal('client2_value', @client.call('GET', 'key'))
425436
end
426437

@@ -449,6 +460,7 @@ def test_transaction_with_watch_retries_block
449460
end
450461

451462
# The transaction did commit (but it was the second time)
463+
wait_for_replication
452464
assert_equal('@client_value_2', @client.call('GET', 'key'))
453465
assert_equal(2, call_count)
454466
end
@@ -463,6 +475,7 @@ def test_transaction_with_error
463475
end
464476
end
465477

478+
wait_for_replication
466479
assert_equal('x', @client.call('GET', 'key1'))
467480
end
468481

@@ -476,6 +489,7 @@ def test_transaction_without_error_during_queueing
476489
end
477490
end
478491

492+
wait_for_replication
479493
assert_equal('aaa', @client.call('GET', 'key1'))
480494
end
481495

@@ -518,6 +532,8 @@ def test_transaction_in_race_condition
518532
end
519533

520534
assert_nil(got)
535+
536+
wait_for_replication
521537
assert_equal(%w[3 4], @client.call('MGET', '{key}1', '{key}2'))
522538
end
523539

@@ -532,6 +548,8 @@ def test_transaction_with_dedicated_watch_command
532548
end
533549

534550
assert_equal(%w[START OK OK FINISH], got)
551+
552+
wait_for_replication
535553
assert_equal(%w[1 2], @client.call('MGET', '{key}1', '{key}2'))
536554
end
537555

0 commit comments

Comments
 (0)