redis-cluster-client 0.7.7 → 0.7.8
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/optimistic_locking.rb +25 -15
- data/lib/redis_client/cluster/transaction.rb +20 -27
- data/lib/redis_client/cluster.rb +8 -7
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41d87ce45a108ff8ec7d3c17805276d5ba7df11d577de3f7d6b1176bdd297ed0
|
4
|
+
data.tar.gz: 7118539907bb755225ba908cf160ad8af73aeb5204820682ca3fc3a67813f3cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96e3c0f9c2860002642e079b756065e32f04891cd793dce9efcb74bb87a13683b14fee13c039693d99599549fee7ace68d54561b8c730d5e9eb7bb937a82c57d
|
7
|
+
data.tar.gz: 2e512b774b5778e3f7a2a3557bb45d97971d209c787494a19d81e0d8146f5d51bbef7940f37fa38f7587e1037185e23fa27ca8d48a46225ced6640be8425198e
|
@@ -7,29 +7,32 @@ require 'redis_client/cluster/transaction'
|
|
7
7
|
class RedisClient
|
8
8
|
class Cluster
|
9
9
|
class OptimisticLocking
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
@keys = keys
|
10
|
+
def initialize(router)
|
11
|
+
@router = router
|
13
12
|
end
|
14
13
|
|
15
|
-
def watch
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
def watch(keys)
|
15
|
+
ensure_safe_keys(keys)
|
16
|
+
node = find_node(keys)
|
17
|
+
cnt = 0 # We assume redirects occurred when incrementing it.
|
18
|
+
|
19
|
+
@router.handle_redirection(node, retry_count: 1) do |nd|
|
20
|
+
cnt += 1
|
21
|
+
nd.with do |c|
|
22
|
+
c.call('WATCH', *keys)
|
23
|
+
reply = yield(c, cnt > 1)
|
24
|
+
c.call('UNWATCH')
|
25
|
+
reply
|
26
|
+
end
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
24
30
|
private
|
25
31
|
|
26
|
-
def
|
27
|
-
|
32
|
+
def ensure_safe_keys(keys)
|
33
|
+
return if safe?(keys)
|
28
34
|
|
29
|
-
|
30
|
-
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "couldn't determine the node" if node_key.nil?
|
31
|
-
|
32
|
-
router.find_node(node_key)
|
35
|
+
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "unsafe watch: #{keys.join(' ')}"
|
33
36
|
end
|
34
37
|
|
35
38
|
def safe?(keys)
|
@@ -43,6 +46,13 @@ class RedisClient
|
|
43
46
|
|
44
47
|
slots.uniq.size == 1
|
45
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?
|
53
|
+
|
54
|
+
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "couldn't determine the node"
|
55
|
+
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
@@ -8,8 +8,9 @@ class RedisClient
|
|
8
8
|
class Cluster
|
9
9
|
class Transaction
|
10
10
|
ConsistencyError = Class.new(::RedisClient::Error)
|
11
|
+
MAX_REDIRECTION = 2
|
11
12
|
|
12
|
-
def initialize(router, command_builder, node
|
13
|
+
def initialize(router, command_builder, node: nil, resharding: false)
|
13
14
|
@router = router
|
14
15
|
@command_builder = command_builder
|
15
16
|
@retryable = true
|
@@ -17,6 +18,7 @@ class RedisClient
|
|
17
18
|
@pending_commands = []
|
18
19
|
@node = node
|
19
20
|
prepare_tx unless @node.nil?
|
21
|
+
@resharding_state = resharding
|
20
22
|
end
|
21
23
|
|
22
24
|
def call(*command, **kwargs, &block)
|
@@ -92,7 +94,7 @@ class RedisClient
|
|
92
94
|
|
93
95
|
def settle
|
94
96
|
@pipeline.call('EXEC')
|
95
|
-
send_transaction(@node, redirect:
|
97
|
+
send_transaction(@node, redirect: MAX_REDIRECTION)
|
96
98
|
end
|
97
99
|
|
98
100
|
def send_transaction(client, redirect:)
|
@@ -109,7 +111,7 @@ class RedisClient
|
|
109
111
|
client.middlewares.call_pipelined(commands, client.config) do
|
110
112
|
connection.call_pipelined(commands, nil)
|
111
113
|
rescue ::RedisClient::CommandError => e
|
112
|
-
return handle_command_error!(commands, e)
|
114
|
+
return handle_command_error!(client, commands, e, redirect: redirect) unless redirect.zero?
|
113
115
|
|
114
116
|
raise
|
115
117
|
end
|
@@ -138,39 +140,30 @@ class RedisClient
|
|
138
140
|
results
|
139
141
|
end
|
140
142
|
|
141
|
-
def handle_command_error!(commands, err)
|
143
|
+
def handle_command_error!(client, commands, err, redirect:) # rubocop:disable Metrics/AbcSize
|
142
144
|
if err.message.start_with?('CROSSSLOT')
|
143
145
|
raise ConsistencyError, "#{err.message}: #{err.command}"
|
144
|
-
elsif err.message.start_with?('MOVED'
|
145
|
-
ensure_the_same_node!(commands)
|
146
|
-
|
146
|
+
elsif err.message.start_with?('MOVED')
|
147
|
+
ensure_the_same_node!(client, commands)
|
148
|
+
node = @router.assign_redirection_node(err.message)
|
149
|
+
send_transaction(node, redirect: redirect - 1)
|
150
|
+
elsif err.message.start_with?('ASK')
|
151
|
+
ensure_the_same_node!(client, commands)
|
152
|
+
node = @router.assign_asking_node(err.message)
|
153
|
+
try_asking(node) ? send_transaction(node, redirect: redirect - 1) : err
|
147
154
|
else
|
148
155
|
raise err
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
|
-
def ensure_the_same_node!(commands)
|
153
|
-
|
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)
|
154
162
|
|
155
|
-
|
156
|
-
|
157
|
-
next if node_key.nil?
|
158
|
-
next if node_key == expected_node_key
|
159
|
-
|
160
|
-
raise ConsistencyError, "the transaction should be executed to a slot in a node: #{commands}"
|
161
|
-
end
|
162
|
-
end
|
163
|
+
return if !@resharding_state && node_keys.size == 1 && node_keys.first == expected_node_key
|
164
|
+
return if @resharding_state && node_keys.size == 1
|
163
165
|
|
164
|
-
|
165
|
-
if err.message.start_with?('MOVED')
|
166
|
-
node = @router.assign_redirection_node(err.message)
|
167
|
-
send_transaction(node, redirect: false)
|
168
|
-
elsif err.message.start_with?('ASK')
|
169
|
-
node = @router.assign_asking_node(err.message)
|
170
|
-
try_asking(node) ? send_transaction(node, redirect: false) : err
|
171
|
-
else
|
172
|
-
raise err
|
173
|
-
end
|
166
|
+
raise(ConsistencyError, "the transaction should be executed to a slot in a node: #{commands}")
|
174
167
|
end
|
175
168
|
|
176
169
|
def try_asking(node)
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -95,14 +95,15 @@ class RedisClient
|
|
95
95
|
if watch.nil? || watch.empty?
|
96
96
|
transaction = ::RedisClient::Cluster::Transaction.new(@router, @command_builder)
|
97
97
|
yield transaction
|
98
|
+
return transaction.execute
|
99
|
+
end
|
100
|
+
|
101
|
+
::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, resharding|
|
102
|
+
transaction = ::RedisClient::Cluster::Transaction.new(
|
103
|
+
@router, @command_builder, node: c, resharding: resharding
|
104
|
+
)
|
105
|
+
yield transaction
|
98
106
|
transaction.execute
|
99
|
-
else
|
100
|
-
locking = ::RedisClient::Cluster::OptimisticLocking.new(watch, @router)
|
101
|
-
locking.watch do |c|
|
102
|
-
transaction = ::RedisClient::Cluster::Transaction.new(@router, @command_builder, c)
|
103
|
-
yield transaction
|
104
|
-
transaction.execute
|
105
|
-
end
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|