redis-cluster-client 0.9.1 → 0.11.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d885c147de46fd113d493e60bd340cac591ecc94b7eafcfddbd6044abe10f79a
|
4
|
+
data.tar.gz: f13c1012ef977e8f9c3e38d928c5c3eb95ba2242761fa992033323c115b318f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68c939431088425c7735c68b4af0949bc5918837d9f19878c62d71aa1fec6e31efee5de2868325447a9e4672c108299a86cc6d047447ef10e7987daa04ecb1e9
|
7
|
+
data.tar.gz: f8ae784f6977151fd825c34878e7f6162175cd828d0b81a92da07e5af96a00a56467ffbed3822f24c198f2373900dc20ea69f8446e3468fc7ba54945baa44f65
|
@@ -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
|
@@ -13,9 +13,6 @@ class RedisClient
|
|
13
13
|
class Node
|
14
14
|
include Enumerable
|
15
15
|
|
16
|
-
# It affects to strike a balance between load and stability in initialization or changed states.
|
17
|
-
MAX_STARTUP_SAMPLE = Integer(ENV.fetch('REDIS_CLIENT_MAX_STARTUP_SAMPLE', 3))
|
18
|
-
|
19
16
|
# less memory consumption, but slow
|
20
17
|
USE_CHAR_ARRAY_SLOT = Integer(ENV.fetch('REDIS_CLIENT_USE_CHAR_ARRAY_SLOT', 1)) == 1
|
21
18
|
|
@@ -197,7 +194,7 @@ class RedisClient
|
|
197
194
|
|
198
195
|
def reload!
|
199
196
|
with_reload_lock do
|
200
|
-
with_startup_clients(
|
197
|
+
with_startup_clients(@config.max_startup_sample) do |startup_clients|
|
201
198
|
@node_info = refetch_node_info_list(startup_clients)
|
202
199
|
@node_configs = @node_info.to_h do |node_info|
|
203
200
|
[node_info.node_key, @config.client_config_for_node(node_info.node_key)]
|
@@ -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
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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
|
-
|
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
|
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(
|
357
|
-
|
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
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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 =
|
71
|
-
|
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 =
|
76
|
-
|
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 =
|
81
|
-
|
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
|
-
|
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(
|
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(
|
112
|
+
::RedisClient::Cluster::OptimisticLocking.new(router).watch(watch) do |c, slot, asking|
|
108
113
|
transaction = ::RedisClient::Cluster::Transaction.new(
|
109
|
-
|
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(
|
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
|
146
|
+
if router.command_exists?(name)
|
134
147
|
args.unshift(name)
|
135
148
|
command = @command_builder.generate(args, kwargs)
|
136
|
-
return
|
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
|
156
|
+
return true if router.command_exists?(name)
|
144
157
|
|
145
158
|
super
|
146
159
|
end
|
@@ -20,13 +20,15 @@ class RedisClient
|
|
20
20
|
MAX_WORKERS = Integer(ENV.fetch('REDIS_CLIENT_MAX_THREADS', 5))
|
21
21
|
# It's used with slow queries of fetching meta data like CLUSTER NODES, COMMAND and so on.
|
22
22
|
SLOW_COMMAND_TIMEOUT = Float(ENV.fetch('REDIS_CLIENT_SLOW_COMMAND_TIMEOUT', -1))
|
23
|
+
# It affects to strike a balance between load and stability in initialization or changed states.
|
24
|
+
MAX_STARTUP_SAMPLE = Integer(ENV.fetch('REDIS_CLIENT_MAX_STARTUP_SAMPLE', 3))
|
23
25
|
|
24
26
|
InvalidClientConfigError = Class.new(::RedisClient::Error)
|
25
27
|
|
26
28
|
attr_reader :command_builder, :client_config, :replica_affinity, :slow_command_timeout,
|
27
|
-
:connect_with_original_config, :startup_nodes
|
29
|
+
:connect_with_original_config, :startup_nodes, :max_startup_sample
|
28
30
|
|
29
|
-
def initialize(
|
31
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
30
32
|
nodes: DEFAULT_NODES,
|
31
33
|
replica: false,
|
32
34
|
replica_affinity: :random,
|
@@ -36,6 +38,7 @@ class RedisClient
|
|
36
38
|
client_implementation: ::RedisClient::Cluster, # for redis gem
|
37
39
|
slow_command_timeout: SLOW_COMMAND_TIMEOUT,
|
38
40
|
command_builder: ::RedisClient::CommandBuilder,
|
41
|
+
max_startup_sample: MAX_STARTUP_SAMPLE,
|
39
42
|
**client_config
|
40
43
|
)
|
41
44
|
|
@@ -51,6 +54,7 @@ class RedisClient
|
|
51
54
|
@connect_with_original_config = connect_with_original_config
|
52
55
|
@client_implementation = client_implementation
|
53
56
|
@slow_command_timeout = slow_command_timeout
|
57
|
+
@max_startup_sample = max_startup_sample
|
54
58
|
end
|
55
59
|
|
56
60
|
def inspect
|
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.
|
4
|
+
version: 0.11.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-
|
11
|
+
date: 2024-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
|
-
rubygems_version: 3.5.
|
80
|
+
rubygems_version: 3.5.11
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
83
|
summary: A Redis cluster client for Ruby
|