Skip to content

Commit a4e9f91

Browse files
authored
chore: fix some miscellaneous points (#414)
1 parent 488e6cb commit a4e9f91

File tree

8 files changed

+219
-30
lines changed

8 files changed

+219
-30
lines changed

lib/redis_client/cluster.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def blocking_call_v(timeout, command, &block)
6464
def scan(*args, **kwargs, &block)
6565
return to_enum(__callee__, *args, **kwargs) unless block_given?
6666

67-
command = @command_builder.generate(['SCAN', ZERO_CURSOR_FOR_SCAN] + args, kwargs)
67+
command = @command_builder.generate(['scan', ZERO_CURSOR_FOR_SCAN] + args, kwargs)
6868
seed = Random.new_seed
6969
loop do
7070
cursor, keys = router.scan(command, seed: seed)
@@ -77,21 +77,21 @@ def scan(*args, **kwargs, &block)
7777
def sscan(key, *args, **kwargs, &block)
7878
return to_enum(__callee__, key, *args, **kwargs) unless block_given?
7979

80-
command = @command_builder.generate(['SSCAN', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
80+
command = @command_builder.generate(['sscan', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
8181
router.scan_single_key(command, arity: 1, &block)
8282
end
8383

8484
def hscan(key, *args, **kwargs, &block)
8585
return to_enum(__callee__, key, *args, **kwargs) unless block_given?
8686

87-
command = @command_builder.generate(['HSCAN', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
87+
command = @command_builder.generate(['hscan', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
8888
router.scan_single_key(command, arity: 2, &block)
8989
end
9090

9191
def zscan(key, *args, **kwargs, &block)
9292
return to_enum(__callee__, key, *args, **kwargs) unless block_given?
9393

94-
command = @command_builder.generate(['ZSCAN', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
94+
command = @command_builder.generate(['zscan', key, ZERO_CURSOR_FOR_SCAN] + args, kwargs)
9595
router.scan_single_key(command, arity: 2, &block)
9696
end
9797

lib/redis_client/cluster/command.rb

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,36 +90,38 @@ def find_command_info(name)
9090
end
9191

9292
def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
93-
if command.first.casecmp('get').zero?
94-
find_command_info(command.first)&.first_key_position.to_i
95-
elsif command.first.casecmp('mget').zero?
96-
find_command_info(command.first)&.first_key_position.to_i
97-
elsif command.first.casecmp('set').zero?
98-
find_command_info(command.first)&.first_key_position.to_i
99-
elsif command.first.casecmp('mset').zero?
100-
find_command_info(command.first)&.first_key_position.to_i
101-
elsif command.first.casecmp('del').zero?
102-
find_command_info(command.first)&.first_key_position.to_i
103-
elsif command.first.casecmp('eval').zero?
93+
cmd_name = command.first
94+
95+
if cmd_name.casecmp('get').zero?
96+
find_command_info(cmd_name)&.first_key_position.to_i
97+
elsif cmd_name.casecmp('mget').zero?
98+
find_command_info(cmd_name)&.first_key_position.to_i
99+
elsif cmd_name.casecmp('set').zero?
100+
find_command_info(cmd_name)&.first_key_position.to_i
101+
elsif cmd_name.casecmp('mset').zero?
102+
find_command_info(cmd_name)&.first_key_position.to_i
103+
elsif cmd_name.casecmp('del').zero?
104+
find_command_info(cmd_name)&.first_key_position.to_i
105+
elsif cmd_name.casecmp('eval').zero?
104106
3
105-
elsif command.first.casecmp('evalsha').zero?
107+
elsif cmd_name.casecmp('evalsha').zero?
106108
3
107-
elsif command.first.casecmp('zinterstore').zero?
109+
elsif cmd_name.casecmp('zinterstore').zero?
108110
3
109-
elsif command.first.casecmp('zunionstore').zero?
111+
elsif cmd_name.casecmp('zunionstore').zero?
110112
3
111-
elsif command.first.casecmp('object').zero?
113+
elsif cmd_name.casecmp('object').zero?
112114
2
113-
elsif command.first.casecmp('memory').zero?
115+
elsif cmd_name.casecmp('memory').zero?
114116
command[1].to_s.casecmp('usage').zero? ? 2 : 0
115-
elsif command.first.casecmp('migrate').zero?
117+
elsif cmd_name.casecmp('migrate').zero?
116118
command[3].empty? ? determine_optional_key_position(command, 'keys') : 3
117-
elsif command.first.casecmp('xread').zero?
119+
elsif cmd_name.casecmp('xread').zero?
118120
determine_optional_key_position(command, 'streams')
119-
elsif command.first.casecmp('xreadgroup').zero?
121+
elsif cmd_name.casecmp('xreadgroup').zero?
120122
determine_optional_key_position(command, 'streams')
121123
else
122-
find_command_info(command.first)&.first_key_position.to_i
124+
find_command_info(cmd_name)&.first_key_position.to_i
123125
end
124126
end
125127

lib/redis_client/cluster/node.rb

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
require 'redis_client/cluster/node/random_replica'
88
require 'redis_client/cluster/node/random_replica_or_primary'
99
require 'redis_client/cluster/node/latency_replica'
10+
require 'redis_client/cluster/node_key'
1011

1112
class RedisClient
1213
class Cluster
@@ -43,6 +44,10 @@ def primary?
4344
def replica?
4445
role == 'slave'
4546
end
47+
48+
def serialize(str)
49+
str << id << node_key << role << primary_id << config_epoch
50+
end
4651
end
4752

4853
class CharArray
@@ -338,9 +343,7 @@ def refetch_node_info_list(startup_clients) # rubocop:disable Metrics/AbcSize, M
338343

339344
grouped = node_info_list.compact.group_by do |info_list|
340345
info_list.sort_by!(&:id)
341-
info_list.each_with_object(String.new(capacity: 128 * info_list.size)) do |e, a|
342-
a << e.id << e.node_key << e.role << e.primary_id << e.config_epoch
343-
end
346+
info_list.each_with_object(String.new(capacity: 128 * info_list.size)) { |e, a| e.serialize(a) }
344347
end
345348

346349
grouped.max_by { |_, v| v.size }[1].first
@@ -375,6 +378,48 @@ def parse_cluster_node_reply(reply) # rubocop:disable Metrics/AbcSize, Metrics/C
375378
end
376379
end
377380

381+
def parse_cluster_slots_reply(reply) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
382+
reply.group_by { |e| e[2][2] }.each_with_object([]) do |(primary_id, group), acc|
383+
slots = group.map { |e| e[0, 2] }.freeze
384+
385+
group.first[2..].each do |arr|
386+
ip = arr[0]
387+
next if ip.nil? || ip.empty? || ip == '?'
388+
389+
id = arr[2]
390+
role = id == primary_id ? 'master' : 'slave'
391+
acc << ::RedisClient::Cluster::Node::Info.new(
392+
id: id,
393+
node_key: NodeKey.build_from_host_port(ip, arr[1]),
394+
role: role,
395+
primary_id: role == 'master' ? nil : primary_id,
396+
slots: role == 'master' ? slots : EMPTY_ARRAY
397+
)
398+
end
399+
end.freeze
400+
end
401+
402+
def parse_cluster_shards_reply(reply) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
403+
reply.each_with_object([]) do |shard, acc|
404+
nodes = shard.fetch('nodes')
405+
primary_id = nodes.find { |n| n.fetch('role') == 'master' }.fetch('id')
406+
407+
nodes.each do |node|
408+
ip = node.fetch('ip')
409+
next if node.fetch('health') != 'online' || ip.nil? || ip.empty? || ip == '?'
410+
411+
role = node.fetch('role')
412+
acc << ::RedisClient::Cluster::Node::Info.new(
413+
id: node.fetch('id'),
414+
node_key: NodeKey.build_from_host_port(ip, node['port'] || node['tls-port']),
415+
role: role == 'master' ? role : 'slave',
416+
primary_id: role == 'master' ? nil : primary_id,
417+
slots: role == 'master' ? shard.fetch('slots').each_slice(2).to_a.freeze : EMPTY_ARRAY
418+
)
419+
end
420+
end.freeze
421+
end
422+
378423
# As redirection node_key is dependent on `cluster-preferred-endpoint-type` config,
379424
# node_key should use hostname if present in CLUSTER NODES output.
380425
#

lib/redis_client/cluster/router.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def initialize(config, concurrent_worker, pool: nil, **kwargs)
3838

3939
def send_command(method, command, *args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
4040
cmd_name = command.first
41+
4142
if cmd_name.casecmp('get').zero?
4243
node = assign_node(command)
4344
try_send(node, method, command, args, &block)

lib/redis_client/cluster_config.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def initialize( # rubocop:disable Metrics/ParameterLists
4747
max_startup_sample: MAX_STARTUP_SAMPLE,
4848
**client_config
4949
)
50-
5150
@replica = true & replica
5251
@replica_affinity = replica_affinity.to_s.to_sym
5352
@fixed_hostname = fixed_hostname.to_s

test/cluster_controller.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def initialize(node_addrs,
4747
replica_size: DEFAULT_REPLICA_SIZE,
4848
state_check_attempts: DEFAULT_MAX_ATTEMPTS,
4949
**kwargs)
50-
5150
@shard_size = shard_size
5251
@replica_size = replica_size
5352
@number_of_replicas = @replica_size * @shard_size

test/ips_slot_node_mapping.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,19 @@ module IpsSlotNodeMapping
1212
def run
1313
ca = ::RedisClient::Cluster::Node::CharArray.new(SIZE, ELEMENTS)
1414
arr = Array.new(SIZE)
15+
hs = {}
1516

1617
print_letter('Mappings between slots and nodes')
1718
fullfill(ca)
1819
fullfill(arr)
19-
bench({ ca.class.name.split('::').last => ca, arr.class.name => arr })
20+
fullfill(hs)
21+
bench(
22+
{
23+
ca.class.name.split('::').last => ca,
24+
arr.class.name => arr,
25+
hs.class.name => hs
26+
}
27+
)
2028
end
2129

2230
def print_letter(title)

test/redis_client/cluster/test_node.rb

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,141 @@ def test_parse_cluster_node_reply_failure_flags
281281
assert_empty(@test_node.send(:parse_cluster_node_reply, info))
282282
end
283283

284+
def test_parse_cluster_slots_reply
285+
reply = [
286+
[
287+
0,
288+
5460,
289+
['10.10.1.6', 6379, '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb', {}],
290+
['10.10.1.5', 6379, 'b60c0672f257c01d76f27eacded14b6e6f4f990e', {}]
291+
],
292+
[
293+
5461,
294+
10_922,
295+
['10.10.1.4', 6379, '712b9a6656b38a5e002244903853fccb4d1eef4b', {}],
296+
['10.10.1.7', 6379, '7038691c545e7caa9147030ecfb4acf1eaad0552', {}]
297+
],
298+
[
299+
10_923,
300+
16_383,
301+
['10.10.1.8', 6379, 'ba85d0807043bb40f72bb4e1e8352b029c6e0082', {}],
302+
['10.10.1.3', 6379, 'f2f36b472b187c577ccd93dd296e9045f473ae7a', {}]
303+
]
304+
]
305+
306+
want = [
307+
{ id: '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb', node_key: '10.10.1.6:6379', role: 'master', primary_id: nil,
308+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[0, 5460]] },
309+
{ id: 'b60c0672f257c01d76f27eacded14b6e6f4f990e', node_key: '10.10.1.5:6379', role: 'slave', primary_id: '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb',
310+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] },
311+
{ id: '712b9a6656b38a5e002244903853fccb4d1eef4b', node_key: '10.10.1.4:6379', role: 'master', primary_id: nil,
312+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[5461, 10_922]] },
313+
{ id: '7038691c545e7caa9147030ecfb4acf1eaad0552', node_key: '10.10.1.7:6379', role: 'slave', primary_id: '712b9a6656b38a5e002244903853fccb4d1eef4b',
314+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] },
315+
{ id: 'ba85d0807043bb40f72bb4e1e8352b029c6e0082', node_key: '10.10.1.8:6379', role: 'master', primary_id: nil,
316+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[10_923, 16_383]] },
317+
{ id: 'f2f36b472b187c577ccd93dd296e9045f473ae7a', node_key: '10.10.1.3:6379', role: 'slave', primary_id: 'ba85d0807043bb40f72bb4e1e8352b029c6e0082',
318+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] }
319+
]
320+
321+
got = @test_node.send(:parse_cluster_slots_reply, reply)
322+
323+
assert_equal(want.sort_by { |e| e.fetch(:id) }, got.sort_by(&:id).map(&:to_h))
324+
end
325+
326+
def test_parse_cluster_shards_reply
327+
reply = [
328+
{
329+
'slots' => [5461, 10_922],
330+
'nodes' => [
331+
{
332+
'id' => '712b9a6656b38a5e002244903853fccb4d1eef4b',
333+
'port' => 6379,
334+
'ip' => '10.10.1.4',
335+
'endpoint' => '10.10.1.4',
336+
'role' => 'master',
337+
'replication-offset' => 98,
338+
'health' => 'online'
339+
},
340+
{
341+
'id' => '7038691c545e7caa9147030ecfb4acf1eaad0552',
342+
'port' => 6379,
343+
'ip' => '10.10.1.7',
344+
'endpoint' => '10.10.1.7',
345+
'role' => 'replica',
346+
'replication-offset' => 98,
347+
'health' => 'online'
348+
}
349+
]
350+
},
351+
{
352+
'slots' => [10_923, 16_383],
353+
'nodes' => [
354+
{
355+
'id' => 'ba85d0807043bb40f72bb4e1e8352b029c6e0082',
356+
'port' => 6379,
357+
'ip' => '10.10.1.8',
358+
'endpoint' => '10.10.1.8',
359+
'role' => 'master',
360+
'replication-offset' => 98,
361+
'health' => 'online'
362+
},
363+
{
364+
'id' => 'f2f36b472b187c577ccd93dd296e9045f473ae7a',
365+
'port' => 6379,
366+
'ip' => '10.10.1.3',
367+
'endpoint' => '10.10.1.3',
368+
'role' => 'replica',
369+
'replication-offset' => 98,
370+
'health' => 'online'
371+
}
372+
]
373+
},
374+
{
375+
'slots' => [0, 5460],
376+
'nodes' => [
377+
{
378+
'id' => '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb',
379+
'port' => 6379,
380+
'ip' => '10.10.1.6',
381+
'endpoint' => '10.10.1.6',
382+
'role' => 'master',
383+
'replication-offset' => 98,
384+
'health' => 'online'
385+
},
386+
{
387+
'id' => 'b60c0672f257c01d76f27eacded14b6e6f4f990e',
388+
'port' => 6379,
389+
'ip' => '10.10.1.5',
390+
'endpoint' => '10.10.1.5',
391+
'role' => 'replica',
392+
'replication-offset' => 98,
393+
'health' => 'online'
394+
}
395+
]
396+
}
397+
]
398+
399+
want = [
400+
{ id: '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb', node_key: '10.10.1.6:6379', role: 'master', primary_id: nil,
401+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[0, 5460]] },
402+
{ id: 'b60c0672f257c01d76f27eacded14b6e6f4f990e', node_key: '10.10.1.5:6379', role: 'slave', primary_id: '00c0d00f2a5eda22b2c8a8929ba27b454c4400fb',
403+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] },
404+
{ id: '712b9a6656b38a5e002244903853fccb4d1eef4b', node_key: '10.10.1.4:6379', role: 'master', primary_id: nil,
405+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[5461, 10_922]] },
406+
{ id: '7038691c545e7caa9147030ecfb4acf1eaad0552', node_key: '10.10.1.7:6379', role: 'slave', primary_id: '712b9a6656b38a5e002244903853fccb4d1eef4b',
407+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] },
408+
{ id: 'ba85d0807043bb40f72bb4e1e8352b029c6e0082', node_key: '10.10.1.8:6379', role: 'master', primary_id: nil,
409+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [[10_923, 16_383]] },
410+
{ id: 'f2f36b472b187c577ccd93dd296e9045f473ae7a', node_key: '10.10.1.3:6379', role: 'slave', primary_id: 'ba85d0807043bb40f72bb4e1e8352b029c6e0082',
411+
ping_sent: nil, pong_recv: nil, config_epoch: nil, link_state: nil, slots: [] }
412+
]
413+
414+
got = @test_node.send(:parse_cluster_shards_reply, reply)
415+
416+
assert_equal(want.sort_by { |e| e.fetch(:id) }, got.sort_by(&:id).map(&:to_h))
417+
end
418+
284419
def test_inspect
285420
assert_match(/^#<RedisClient::Cluster::Node [0-9., :]*>$/, @test_node.inspect)
286421
end

0 commit comments

Comments
 (0)