redis-cluster-client 0.8.1 → 0.9.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 +4 -4
- data/lib/redis_client/cluster/command.rb +6 -6
- data/lib/redis_client/cluster/node/base_topology.rb +3 -0
- data/lib/redis_client/cluster/node.rb +2 -7
- data/lib/redis_client/cluster/router.rb +42 -1
- data/lib/redis_client/cluster/transaction.rb +13 -3
- data/lib/redis_client/cluster.rb +2 -21
- metadata +3 -4
- data/lib/redis_client/cluster/pinning_node.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97383b0daf1dcc2e5fcd8e50640e9ecbd903562a10cca0f4996ada1807469f80
|
4
|
+
data.tar.gz: 675ae25f2fbf2d9d67234b4e1ad81894656f11a32fe4cd1ebf8ae73c90c67509
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 851565ace738fb9bf51d1211ece97767520c94a7b02e49b053732de351d77a30e7104ae1f8143a0ee3903a2b99de39b298b3eec80c2fb94b08fb4747180bb03d
|
7
|
+
data.tar.gz: 0a0b6ada72bccfcdb7cecda533f8f31761f15f991e359bc211a4d54ba973b2c68983efd3a9a594e7baab11b614fecb058de98b71f1890f7e52150f40e2c34d1b
|
@@ -97,6 +97,12 @@ 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
|
+
|
100
106
|
private
|
101
107
|
|
102
108
|
def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity
|
@@ -143,12 +149,6 @@ class RedisClient
|
|
143
149
|
end
|
144
150
|
end
|
145
151
|
|
146
|
-
def determine_key_step(command)
|
147
|
-
name = ::RedisClient::Cluster::NormalizedCmdName.instance.get_by_command(command)
|
148
|
-
# Some commands like EVALSHA have zero as the step in COMMANDS somehow.
|
149
|
-
@commands[name].key_step == 0 ? 1 : @commands[name].key_step
|
150
|
-
end
|
151
|
-
|
152
152
|
def determine_optional_key_position(command, option_name) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
153
153
|
idx = command&.flatten&.map(&:to_s)&.map(&:downcase)&.index(option_name&.downcase)
|
154
154
|
idx.nil? ? 0 : idx + 1
|
@@ -5,6 +5,9 @@ class RedisClient
|
|
5
5
|
class Node
|
6
6
|
class BaseTopology
|
7
7
|
IGNORE_GENERIC_CONFIG_KEYS = %i[url host port path].freeze
|
8
|
+
EMPTY_HASH = {}.freeze
|
9
|
+
EMPTY_ARRAY = [].freeze
|
10
|
+
|
8
11
|
attr_reader :clients, :primary_clients, :replica_clients
|
9
12
|
|
10
13
|
def initialize(pool, concurrent_worker, **kwargs)
|
@@ -92,13 +92,7 @@ class RedisClient
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
def initialize(
|
96
|
-
concurrent_worker,
|
97
|
-
config:,
|
98
|
-
pool: nil,
|
99
|
-
**kwargs
|
100
|
-
)
|
101
|
-
|
95
|
+
def initialize(concurrent_worker, config:, pool: nil, **kwargs)
|
102
96
|
@concurrent_worker = concurrent_worker
|
103
97
|
@slots = build_slot_node_mappings(EMPTY_ARRAY)
|
104
98
|
@replications = build_replication_mappings(EMPTY_ARRAY)
|
@@ -106,6 +100,7 @@ class RedisClient
|
|
106
100
|
@topology = klass.new(pool, @concurrent_worker, **kwargs)
|
107
101
|
@config = config
|
108
102
|
@mutex = Mutex.new
|
103
|
+
@last_reloaded_at = nil
|
109
104
|
end
|
110
105
|
|
111
106
|
def inspect
|
@@ -10,6 +10,7 @@ require 'redis_client/cluster/node_key'
|
|
10
10
|
require 'redis_client/cluster/normalized_cmd_name'
|
11
11
|
require 'redis_client/cluster/transaction'
|
12
12
|
require 'redis_client/cluster/optimistic_locking'
|
13
|
+
require 'redis_client/cluster/pipeline'
|
13
14
|
require 'redis_client/cluster/error_identification'
|
14
15
|
|
15
16
|
class RedisClient
|
@@ -17,6 +18,11 @@ class RedisClient
|
|
17
18
|
class Router
|
18
19
|
ZERO_CURSOR_FOR_SCAN = '0'
|
19
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
|
20
26
|
|
21
27
|
def initialize(config, concurrent_worker, pool: nil, **kwargs)
|
22
28
|
@config = config.dup
|
@@ -48,6 +54,8 @@ class RedisClient
|
|
48
54
|
when 'script' then send_script_command(method, command, args, &block)
|
49
55
|
when 'pubsub' then send_pubsub_command(method, command, args, &block)
|
50
56
|
when 'watch' then send_watch_command(command, &block)
|
57
|
+
when 'mset', 'mget', 'del'
|
58
|
+
send_multiple_keys_command(cmd, method, command, args, &block)
|
51
59
|
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
52
60
|
@node.call_all(method, command, args).first.then(&TSF.call(block))
|
53
61
|
when 'flushall', 'flushdb'
|
@@ -314,7 +322,6 @@ class RedisClient
|
|
314
322
|
end
|
315
323
|
end
|
316
324
|
|
317
|
-
# for redis-rb
|
318
325
|
def send_watch_command(command)
|
319
326
|
raise ::RedisClient::Cluster::Transaction::ConsistencyError, 'A block required. And you need to use the block argument as a client for the transaction.' unless block_given?
|
320
327
|
|
@@ -327,6 +334,40 @@ class RedisClient
|
|
327
334
|
end
|
328
335
|
end
|
329
336
|
|
337
|
+
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
|
342
|
+
|
343
|
+
seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
|
344
|
+
pipeline = ::RedisClient::Cluster::Pipeline.new(self, @command_builder, @concurrent_worker, exception: true, seed: seed)
|
345
|
+
|
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)
|
349
|
+
single_command[0] = single_key_cmd
|
350
|
+
if key_step == 1
|
351
|
+
command[1..].each do |key|
|
352
|
+
single_command[1] = key
|
353
|
+
pipeline.call_v(single_command)
|
354
|
+
end
|
355
|
+
else
|
356
|
+
command[1..].each_slice(key_step) do |v|
|
357
|
+
key_step.times { |i| single_command[i + 1] = v[i] }
|
358
|
+
pipeline.call_v(single_command)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
replies = pipeline.execute
|
363
|
+
result = case cmd
|
364
|
+
when 'mset' then replies.first
|
365
|
+
when 'del' then replies.sum
|
366
|
+
else replies
|
367
|
+
end
|
368
|
+
block_given? ? yield(result) : result
|
369
|
+
end
|
370
|
+
|
330
371
|
def update_cluster_info!
|
331
372
|
@node.reload!
|
332
373
|
end
|
@@ -8,6 +8,7 @@ class RedisClient
|
|
8
8
|
class Transaction
|
9
9
|
ConsistencyError = Class.new(::RedisClient::Error)
|
10
10
|
MAX_REDIRECTION = 2
|
11
|
+
EMPTY_ARRAY = [].freeze
|
11
12
|
|
12
13
|
def initialize(router, command_builder, node: nil, slot: nil, asking: false)
|
13
14
|
@router = router
|
@@ -62,10 +63,10 @@ class RedisClient
|
|
62
63
|
def execute
|
63
64
|
@pending_commands.each(&:call)
|
64
65
|
|
65
|
-
|
66
|
+
return EMPTY_ARRAY if @pipeline._empty?
|
66
67
|
raise ConsistencyError, "couldn't determine the node: #{@pipeline._commands}" if @node.nil?
|
67
68
|
|
68
|
-
|
69
|
+
commit
|
69
70
|
end
|
70
71
|
|
71
72
|
private
|
@@ -92,8 +93,17 @@ class RedisClient
|
|
92
93
|
@pending_commands.clear
|
93
94
|
end
|
94
95
|
|
95
|
-
def
|
96
|
+
def commit
|
96
97
|
@pipeline.call('EXEC')
|
98
|
+
settle
|
99
|
+
end
|
100
|
+
|
101
|
+
def cancel
|
102
|
+
@pipeline.call('DISCARD')
|
103
|
+
settle
|
104
|
+
end
|
105
|
+
|
106
|
+
def settle
|
97
107
|
# If we needed ASKING on the watch, we need ASKING on the multi as well.
|
98
108
|
@node.call('ASKING') if @asking
|
99
109
|
# Don't handle redirections at this level if we're in a watch (the watcher handles redirections
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -5,7 +5,6 @@ require 'redis_client/cluster/pipeline'
|
|
5
5
|
require 'redis_client/cluster/pub_sub'
|
6
6
|
require 'redis_client/cluster/router'
|
7
7
|
require 'redis_client/cluster/transaction'
|
8
|
-
require 'redis_client/cluster/pinning_node'
|
9
8
|
require 'redis_client/cluster/optimistic_locking'
|
10
9
|
|
11
10
|
class RedisClient
|
@@ -118,13 +117,8 @@ class RedisClient
|
|
118
117
|
::RedisClient::Cluster::PubSub.new(@router, @command_builder)
|
119
118
|
end
|
120
119
|
|
121
|
-
|
122
|
-
|
123
|
-
def with(key: nil, hashtag: nil, write: true)
|
124
|
-
key = process_with_arguments(key, hashtag)
|
125
|
-
node_key = @router.find_node_key_by_key(key, primary: write)
|
126
|
-
node = @router.find_node(node_key)
|
127
|
-
node.with { |c| yield ::RedisClient::Cluster::PinningNode.new(c) }
|
120
|
+
def with(...)
|
121
|
+
raise NotImplementedError, 'No way to use'
|
128
122
|
end
|
129
123
|
|
130
124
|
def close
|
@@ -135,19 +129,6 @@ class RedisClient
|
|
135
129
|
|
136
130
|
private
|
137
131
|
|
138
|
-
def process_with_arguments(key, hashtag) # rubocop:disable Metrics/CyclomaticComplexity
|
139
|
-
raise ArgumentError, 'Only one of key or hashtag may be provided' if key && hashtag
|
140
|
-
|
141
|
-
if hashtag
|
142
|
-
# The documentation says not to wrap your hashtag in {}, but people will probably
|
143
|
-
# do it anyway and it's easy for us to fix here.
|
144
|
-
key = hashtag&.match?(/^{.*}$/) ? hashtag : "{#{hashtag}}"
|
145
|
-
end
|
146
|
-
raise ArgumentError, 'One of key or hashtag must be provided' if key.nil? || key.empty?
|
147
|
-
|
148
|
-
key
|
149
|
-
end
|
150
|
-
|
151
132
|
def method_missing(name, *args, **kwargs, &block)
|
152
133
|
if @router.command_exists?(name)
|
153
134
|
args.unshift(name)
|
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.9.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-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- lib/redis_client/cluster/node_key.rb
|
51
51
|
- lib/redis_client/cluster/normalized_cmd_name.rb
|
52
52
|
- lib/redis_client/cluster/optimistic_locking.rb
|
53
|
-
- lib/redis_client/cluster/pinning_node.rb
|
54
53
|
- lib/redis_client/cluster/pipeline.rb
|
55
54
|
- lib/redis_client/cluster/pub_sub.rb
|
56
55
|
- lib/redis_client/cluster/router.rb
|
@@ -78,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
77
|
- !ruby/object:Gem::Version
|
79
78
|
version: '0'
|
80
79
|
requirements: []
|
81
|
-
rubygems_version: 3.5.
|
80
|
+
rubygems_version: 3.5.9
|
82
81
|
signing_key:
|
83
82
|
specification_version: 4
|
84
83
|
summary: A Redis cluster client for Ruby
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class RedisClient
|
4
|
-
class Cluster
|
5
|
-
class PinningNode
|
6
|
-
def initialize(client)
|
7
|
-
@client = client
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(*args, **kwargs, &block)
|
11
|
-
@client.call(*args, **kwargs, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def call_v(args, &block)
|
15
|
-
@client.call_v(args, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def call_once(*args, **kwargs, &block)
|
19
|
-
@client.call_once(*args, **kwargs, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
def call_once_v(args, &block)
|
23
|
-
@client.call_once_v(args, &block)
|
24
|
-
end
|
25
|
-
|
26
|
-
def blocking_call(timeout, *args, **kwargs, &block)
|
27
|
-
@client.blocking_call(timeout, *args, **kwargs, &block)
|
28
|
-
end
|
29
|
-
|
30
|
-
def blocking_call_v(timeout, args, &block)
|
31
|
-
@client.blocking_call_v(timeout, args, &block)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|