redis-cluster-client 0.7.8 → 0.7.10

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: 41d87ce45a108ff8ec7d3c17805276d5ba7df11d577de3f7d6b1176bdd297ed0
4
- data.tar.gz: 7118539907bb755225ba908cf160ad8af73aeb5204820682ca3fc3a67813f3cb
3
+ metadata.gz: b591c92886bf877147317dd04695d2d22354958443f83e386b061b45b0407b28
4
+ data.tar.gz: 40a46369e32c60a3c165aff646d3dbd53c3ef427fef6220d4bacc17fc6a97232
5
5
  SHA512:
6
- metadata.gz: 96e3c0f9c2860002642e079b756065e32f04891cd793dce9efcb74bb87a13683b14fee13c039693d99599549fee7ace68d54561b8c730d5e9eb7bb937a82c57d
7
- data.tar.gz: 2e512b774b5778e3f7a2a3557bb45d97971d209c787494a19d81e0d8146f5d51bbef7940f37fa38f7587e1037185e23fa27ca8d48a46225ced6640be8425198e
6
+ metadata.gz: 0e8eda475d22314feb84d16c2d5d75dfe714abecf2c6482a7600c012d02705110c40a0ed7717029a7e8ad154040c6cd44978ffd6b9a2c0350ec33e45d1e1b81e
7
+ data.tar.gz: a8fc2bb1febdac9e44c23aaab93ddce567d9ea1fe4ff09f74aa3ebac7eba56efceff44b5f13fea0284d4bec8b2677bd58dfee0eedfebe9cdc4ed9e7d4f6cb6df
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'redis_client'
4
- require 'redis_client/cluster/key_slot_converter'
5
4
  require 'redis_client/cluster/transaction'
6
5
 
7
6
  class RedisClient
@@ -12,46 +11,31 @@ class RedisClient
12
11
  end
13
12
 
14
13
  def watch(keys)
15
- ensure_safe_keys(keys)
16
- node = find_node(keys)
17
- cnt = 0 # We assume redirects occurred when incrementing it.
14
+ slot = find_slot(keys)
15
+ raise ::RedisClient::Cluster::Transaction::ConsistencyError, "unsafe watch: #{keys.join(' ')}" if slot.nil?
18
16
 
17
+ node = @router.find_primary_node_by_slot(slot)
19
18
  @router.handle_redirection(node, retry_count: 1) do |nd|
20
- cnt += 1
21
19
  nd.with do |c|
22
20
  c.call('WATCH', *keys)
23
- reply = yield(c, cnt > 1)
21
+ yield(c, slot)
22
+ rescue StandardError
24
23
  c.call('UNWATCH')
25
- reply
24
+ raise
26
25
  end
27
26
  end
28
27
  end
29
28
 
30
29
  private
31
30
 
32
- def ensure_safe_keys(keys)
33
- return if safe?(keys)
31
+ def find_slot(keys)
32
+ return if keys.empty?
33
+ return if keys.any? { |k| k.nil? || k.empty? }
34
34
 
35
- raise ::RedisClient::Cluster::Transaction::ConsistencyError, "unsafe watch: #{keys.join(' ')}"
36
- end
37
-
38
- def safe?(keys)
39
- return false if keys.empty?
40
-
41
- slots = keys.map do |k|
42
- return false if k.nil? || k.empty?
43
-
44
- ::RedisClient::Cluster::KeySlotConverter.convert(k)
45
- end
46
-
47
- slots.uniq.size == 1
48
- end
49
-
50
- def find_node(keys)
51
- node_key = @router.find_primary_node_key(['WATCH', *keys])
52
- return @router.find_node(node_key) unless node_key.nil?
35
+ slots = keys.map { |k| @router.find_slot_by_key(k) }
36
+ return if slots.uniq.size != 1
53
37
 
54
- raise ::RedisClient::Cluster::Transaction::ConsistencyError, "couldn't determine the node"
38
+ slots.first
55
39
  end
56
40
  end
57
41
  end
@@ -8,6 +8,8 @@ require 'redis_client/cluster/key_slot_converter'
8
8
  require 'redis_client/cluster/node'
9
9
  require 'redis_client/cluster/node_key'
10
10
  require 'redis_client/cluster/normalized_cmd_name'
11
+ require 'redis_client/cluster/transaction'
12
+ require 'redis_client/cluster/optimistic_locking'
11
13
 
12
14
  class RedisClient
13
15
  class Cluster
@@ -44,6 +46,7 @@ class RedisClient
44
46
  when 'memory' then send_memory_command(method, command, args, &block)
45
47
  when 'script' then send_script_command(method, command, args, &block)
46
48
  when 'pubsub' then send_pubsub_command(method, command, args, &block)
49
+ when 'watch' then send_watch_command(command, &block)
47
50
  when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
48
51
  @node.call_all(method, command, args).first.then(&TSF.call(block))
49
52
  when 'flushall', 'flushdb'
@@ -179,6 +182,16 @@ class RedisClient
179
182
  find_node_key_by_key(key, primary: true)
180
183
  end
181
184
 
185
+ def find_slot(command)
186
+ find_slot_by_key(@command.extract_first_key(command))
187
+ end
188
+
189
+ def find_slot_by_key(key)
190
+ return if key.empty?
191
+
192
+ ::RedisClient::Cluster::KeySlotConverter.convert(key)
193
+ end
194
+
182
195
  def find_node(node_key, retry_count: 3)
183
196
  @node.find_by(node_key)
184
197
  rescue ::RedisClient::Cluster::Node::ReloadNeeded
@@ -298,6 +311,17 @@ class RedisClient
298
311
  end
299
312
  end
300
313
 
314
+ # for redis-rb
315
+ def send_watch_command(command)
316
+ ::RedisClient::Cluster::OptimisticLocking.new(self).watch(command[1..]) do |c, slot|
317
+ transaction = ::RedisClient::Cluster::Transaction.new(
318
+ self, @command_builder, node: c, slot: slot
319
+ )
320
+ yield transaction
321
+ transaction.execute
322
+ end
323
+ end
324
+
301
325
  def update_cluster_info!
302
326
  @node.reload!
303
327
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'redis_client'
4
4
  require 'redis_client/cluster/pipeline'
5
- require 'redis_client/cluster/node_key'
6
5
 
7
6
  class RedisClient
8
7
  class Cluster
@@ -10,7 +9,7 @@ class RedisClient
10
9
  ConsistencyError = Class.new(::RedisClient::Error)
11
10
  MAX_REDIRECTION = 2
12
11
 
13
- def initialize(router, command_builder, node: nil, resharding: false)
12
+ def initialize(router, command_builder, node: nil, slot: nil)
14
13
  @router = router
15
14
  @command_builder = command_builder
16
15
  @retryable = true
@@ -18,7 +17,7 @@ class RedisClient
18
17
  @pending_commands = []
19
18
  @node = node
20
19
  prepare_tx unless @node.nil?
21
- @resharding_state = resharding
20
+ @watching_slot = slot
22
21
  end
23
22
 
24
23
  def call(*command, **kwargs, &block)
@@ -111,7 +110,7 @@ class RedisClient
111
110
  client.middlewares.call_pipelined(commands, client.config) do
112
111
  connection.call_pipelined(commands, nil)
113
112
  rescue ::RedisClient::CommandError => e
114
- return handle_command_error!(client, commands, e, redirect: redirect) unless redirect.zero?
113
+ return handle_command_error!(commands, e, redirect: redirect) unless redirect.zero?
115
114
 
116
115
  raise
117
116
  end
@@ -140,15 +139,15 @@ class RedisClient
140
139
  results
141
140
  end
142
141
 
143
- def handle_command_error!(client, commands, err, redirect:) # rubocop:disable Metrics/AbcSize
142
+ def handle_command_error!(commands, err, redirect:) # rubocop:disable Metrics/AbcSize
144
143
  if err.message.start_with?('CROSSSLOT')
145
144
  raise ConsistencyError, "#{err.message}: #{err.command}"
146
145
  elsif err.message.start_with?('MOVED')
147
- ensure_the_same_node!(client, commands)
146
+ ensure_the_same_slot!(commands)
148
147
  node = @router.assign_redirection_node(err.message)
149
148
  send_transaction(node, redirect: redirect - 1)
150
149
  elsif err.message.start_with?('ASK')
151
- ensure_the_same_node!(client, commands)
150
+ ensure_the_same_slot!(commands)
152
151
  node = @router.assign_asking_node(err.message)
153
152
  try_asking(node) ? send_transaction(node, redirect: redirect - 1) : err
154
153
  else
@@ -156,12 +155,10 @@ class RedisClient
156
155
  end
157
156
  end
158
157
 
159
- def ensure_the_same_node!(client, commands)
160
- node_keys = commands.map { |command| @router.find_primary_node_key(command) }.compact.uniq
161
- expected_node_key = ::RedisClient::Cluster::NodeKey.build_from_client(client)
162
-
163
- return if !@resharding_state && node_keys.size == 1 && node_keys.first == expected_node_key
164
- return if @resharding_state && node_keys.size == 1
158
+ def ensure_the_same_slot!(commands)
159
+ slots = commands.map { |command| @router.find_slot(command) }.compact.uniq
160
+ return if slots.size == 1 && @watching_slot.nil?
161
+ return if slots.size == 1 && @watching_slot == slots.first
165
162
 
166
163
  raise(ConsistencyError, "the transaction should be executed to a slot in a node: #{commands}")
167
164
  end
@@ -98,9 +98,9 @@ class RedisClient
98
98
  return transaction.execute
99
99
  end
100
100
 
101
- ::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, resharding|
101
+ ::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, slot|
102
102
  transaction = ::RedisClient::Cluster::Transaction.new(
103
- @router, @command_builder, node: c, resharding: resharding
103
+ @router, @command_builder, node: c, slot: slot
104
104
  )
105
105
  yield transaction
106
106
  transaction.execute
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.7.8
4
+ version: 0.7.10
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-02-18 00:00:00.000000000 Z
11
+ date: 2024-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client