redis-cluster-client 0.7.8 → 0.7.10

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 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