redis-cluster-client 0.7.6 → 0.7.7
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 158cfc3693b4057ae42249cbddcca2e5bd53bb19bb62416e44f1d1358b55c711
|
4
|
+
data.tar.gz: 59917a893698b9d0fec7235821e4f9680b9e3ab4ebfd74554c48c50455a87186
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 116c7f397e557fc0b6a336e3481cc3e5458bac590afe454ecbfbfcafddc67ea3641f9cd020ab7b9f2cb41f3fe54188a13d4324b9496e43a27b1f58f97163363d
|
7
|
+
data.tar.gz: e7ada90bdb11f0d113093792b627853a429d182c1e531d6c968fff530bbd34ed8df76655fd40223b91bc3c5d6524316302fa435438e731a8de1dcb0bc5c4ad24
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redis_client'
|
4
|
+
require 'redis_client/cluster/key_slot_converter'
|
5
|
+
require 'redis_client/cluster/transaction'
|
6
|
+
|
7
|
+
class RedisClient
|
8
|
+
class Cluster
|
9
|
+
class OptimisticLocking
|
10
|
+
def initialize(keys, router)
|
11
|
+
@node = find_node!(keys, router)
|
12
|
+
@keys = keys
|
13
|
+
end
|
14
|
+
|
15
|
+
def watch
|
16
|
+
@node.with do |c|
|
17
|
+
c.call('WATCH', *@keys)
|
18
|
+
reply = yield(c)
|
19
|
+
c.call('UNWATCH')
|
20
|
+
reply
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def find_node!(keys, router)
|
27
|
+
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "unsafe watch: #{keys.join(' ')}" unless safe?(keys)
|
28
|
+
|
29
|
+
node_key = router.find_primary_node_key(['WATCH', *keys])
|
30
|
+
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "couldn't determine the node" if node_key.nil?
|
31
|
+
|
32
|
+
router.find_node(node_key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def safe?(keys)
|
36
|
+
return false if keys.empty?
|
37
|
+
|
38
|
+
slots = keys.map do |k|
|
39
|
+
return false if k.nil? || k.empty?
|
40
|
+
|
41
|
+
::RedisClient::Cluster::KeySlotConverter.convert(k)
|
42
|
+
end
|
43
|
+
|
44
|
+
slots.uniq.size == 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -2,21 +2,21 @@
|
|
2
2
|
|
3
3
|
require 'redis_client'
|
4
4
|
require 'redis_client/cluster/pipeline'
|
5
|
-
require 'redis_client/cluster/
|
5
|
+
require 'redis_client/cluster/node_key'
|
6
6
|
|
7
7
|
class RedisClient
|
8
8
|
class Cluster
|
9
9
|
class Transaction
|
10
10
|
ConsistencyError = Class.new(::RedisClient::Error)
|
11
11
|
|
12
|
-
def initialize(router, command_builder,
|
12
|
+
def initialize(router, command_builder, node = nil)
|
13
13
|
@router = router
|
14
14
|
@command_builder = command_builder
|
15
|
-
@watch = watch
|
16
15
|
@retryable = true
|
17
16
|
@pipeline = ::RedisClient::Pipeline.new(@command_builder)
|
18
|
-
@
|
19
|
-
@node =
|
17
|
+
@pending_commands = []
|
18
|
+
@node = node
|
19
|
+
prepare_tx unless @node.nil?
|
20
20
|
end
|
21
21
|
|
22
22
|
def call(*command, **kwargs, &block)
|
@@ -24,7 +24,7 @@ class RedisClient
|
|
24
24
|
if prepare(command)
|
25
25
|
@pipeline.call_v(command, &block)
|
26
26
|
else
|
27
|
-
|
27
|
+
defer { @pipeline.call_v(command, &block) }
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -33,7 +33,7 @@ class RedisClient
|
|
33
33
|
if prepare(command)
|
34
34
|
@pipeline.call_v(command, &block)
|
35
35
|
else
|
36
|
-
|
36
|
+
defer { @pipeline.call_v(command, &block) }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -43,7 +43,7 @@ class RedisClient
|
|
43
43
|
if prepare(command)
|
44
44
|
@pipeline.call_once_v(command, &block)
|
45
45
|
else
|
46
|
-
|
46
|
+
defer { @pipeline.call_once_v(command, &block) }
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -53,39 +53,24 @@ class RedisClient
|
|
53
53
|
if prepare(command)
|
54
54
|
@pipeline.call_once_v(command, &block)
|
55
55
|
else
|
56
|
-
|
56
|
+
defer { @pipeline.call_once_v(command, &block) }
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def execute
|
61
|
-
@
|
61
|
+
@pending_commands.each(&:call)
|
62
62
|
|
63
63
|
raise ArgumentError, 'empty transaction' if @pipeline._empty?
|
64
64
|
raise ConsistencyError, "couldn't determine the node: #{@pipeline._commands}" if @node.nil?
|
65
|
-
raise ConsistencyError, "unsafe watch: #{@watch.join(' ')}" unless safe_watch?
|
66
65
|
|
67
66
|
settle
|
68
67
|
end
|
69
68
|
|
70
69
|
private
|
71
70
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
def safe_watch?
|
77
|
-
return true unless watch?
|
78
|
-
return false if @node.nil?
|
79
|
-
|
80
|
-
slots = @watch.map do |k|
|
81
|
-
return false if k.nil? || k.empty?
|
82
|
-
|
83
|
-
::RedisClient::Cluster::KeySlotConverter.convert(k)
|
84
|
-
end
|
85
|
-
|
86
|
-
return false if slots.uniq.size != 1
|
87
|
-
|
88
|
-
@router.find_primary_node_by_slot(slots.first) == @node
|
71
|
+
def defer(&block)
|
72
|
+
@pending_commands << block
|
73
|
+
nil
|
89
74
|
end
|
90
75
|
|
91
76
|
def prepare(command)
|
@@ -95,16 +80,18 @@ class RedisClient
|
|
95
80
|
return false if node_key.nil?
|
96
81
|
|
97
82
|
@node = @router.find_node(node_key)
|
98
|
-
|
99
|
-
@pipeline.call('MULTI')
|
100
|
-
@buffer.each(&:call)
|
101
|
-
@buffer.clear
|
83
|
+
prepare_tx
|
102
84
|
true
|
103
85
|
end
|
104
86
|
|
87
|
+
def prepare_tx
|
88
|
+
@pipeline.call('MULTI')
|
89
|
+
@pending_commands.each(&:call)
|
90
|
+
@pending_commands.clear
|
91
|
+
end
|
92
|
+
|
105
93
|
def settle
|
106
94
|
@pipeline.call('EXEC')
|
107
|
-
@pipeline.call('UNWATCH') if watch?
|
108
95
|
send_transaction(@node, redirect: true)
|
109
96
|
end
|
110
97
|
|
@@ -128,11 +115,12 @@ class RedisClient
|
|
128
115
|
end
|
129
116
|
end
|
130
117
|
|
131
|
-
|
132
|
-
|
118
|
+
return if replies.last.nil?
|
119
|
+
|
120
|
+
coerce_results!(replies.last)
|
133
121
|
end
|
134
122
|
|
135
|
-
def coerce_results!(results, offset)
|
123
|
+
def coerce_results!(results, offset: 1)
|
136
124
|
results.each_with_index do |result, index|
|
137
125
|
if result.is_a?(::RedisClient::CommandError)
|
138
126
|
result._set_command(@pipeline._commands[index + offset])
|
@@ -162,12 +150,12 @@ class RedisClient
|
|
162
150
|
end
|
163
151
|
|
164
152
|
def ensure_the_same_node!(commands)
|
153
|
+
expected_node_key = NodeKey.build_from_client(@node)
|
154
|
+
|
165
155
|
commands.each do |command|
|
166
156
|
node_key = @router.find_primary_node_key(command)
|
167
157
|
next if node_key.nil?
|
168
|
-
|
169
|
-
node = @router.find_node(node_key)
|
170
|
-
next if @node == node
|
158
|
+
next if node_key == expected_node_key
|
171
159
|
|
172
160
|
raise ConsistencyError, "the transaction should be executed to a slot in a node: #{commands}"
|
173
161
|
end
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -6,6 +6,7 @@ require 'redis_client/cluster/pub_sub'
|
|
6
6
|
require 'redis_client/cluster/router'
|
7
7
|
require 'redis_client/cluster/transaction'
|
8
8
|
require 'redis_client/cluster/pinning_node'
|
9
|
+
require 'redis_client/cluster/optimistic_locking'
|
9
10
|
|
10
11
|
class RedisClient
|
11
12
|
class Cluster
|
@@ -91,9 +92,18 @@ class RedisClient
|
|
91
92
|
end
|
92
93
|
|
93
94
|
def multi(watch: nil)
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
if watch.nil? || watch.empty?
|
96
|
+
transaction = ::RedisClient::Cluster::Transaction.new(@router, @command_builder)
|
97
|
+
yield transaction
|
98
|
+
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
|
+
end
|
97
107
|
end
|
98
108
|
|
99
109
|
def pubsub
|
@@ -102,12 +112,11 @@ class RedisClient
|
|
102
112
|
|
103
113
|
# TODO: This isn't an official public interface yet. Don't use in your production environment.
|
104
114
|
# @see https://github.com/redis-rb/redis-cluster-client/issues/299
|
105
|
-
def with(key: nil, hashtag: nil, write: true
|
115
|
+
def with(key: nil, hashtag: nil, write: true)
|
106
116
|
key = process_with_arguments(key, hashtag)
|
107
|
-
|
108
117
|
node_key = @router.find_node_key_by_key(key, primary: write)
|
109
118
|
node = @router.find_node(node_key)
|
110
|
-
yield ::RedisClient::Cluster::PinningNode.new(
|
119
|
+
node.with { |c| yield ::RedisClient::Cluster::PinningNode.new(c) }
|
111
120
|
end
|
112
121
|
|
113
122
|
def close
|
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.
|
4
|
+
version: 0.7.7
|
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-
|
11
|
+
date: 2024-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/redis_client/cluster/node/random_replica_or_primary.rb
|
50
50
|
- lib/redis_client/cluster/node_key.rb
|
51
51
|
- lib/redis_client/cluster/normalized_cmd_name.rb
|
52
|
+
- lib/redis_client/cluster/optimistic_locking.rb
|
52
53
|
- lib/redis_client/cluster/pinning_node.rb
|
53
54
|
- lib/redis_client/cluster/pipeline.rb
|
54
55
|
- lib/redis_client/cluster/pub_sub.rb
|