redis 4.6.0 → 5.0.0.beta3
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/CHANGELOG.md +35 -1
- data/README.md +77 -146
- data/lib/redis/client.rb +78 -615
- data/lib/redis/commands/bitmaps.rb +4 -1
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/hashes.rb +6 -3
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +52 -26
- data/lib/redis/commands/lists.rb +10 -14
- data/lib/redis/commands/pubsub.rb +7 -9
- data/lib/redis/commands/server.rb +14 -14
- data/lib/redis/commands/sets.rb +42 -35
- data/lib/redis/commands/sorted_sets.rb +13 -3
- data/lib/redis/commands/streams.rb +12 -10
- data/lib/redis/commands/strings.rb +1 -0
- data/lib/redis/commands/transactions.rb +26 -3
- data/lib/redis/commands.rb +1 -8
- data/lib/redis/distributed.rb +99 -66
- data/lib/redis/errors.rb +10 -43
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +56 -203
- data/lib/redis/subscribe.rb +15 -9
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +69 -175
- metadata +13 -57
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -37
- data/lib/redis/cluster/option.rb +0 -93
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -49
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -431
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
data/lib/redis.rb
CHANGED
@@ -6,26 +6,11 @@ require "redis/commands"
|
|
6
6
|
|
7
7
|
class Redis
|
8
8
|
BASE_PATH = __dir__
|
9
|
-
@exists_returns_integer = true
|
10
|
-
|
11
9
|
Deprecated = Class.new(StandardError)
|
12
10
|
|
13
11
|
class << self
|
14
|
-
attr_reader :exists_returns_integer
|
15
12
|
attr_accessor :silence_deprecations, :raise_deprecations
|
16
13
|
|
17
|
-
def exists_returns_integer=(value)
|
18
|
-
unless value
|
19
|
-
deprecate!(
|
20
|
-
"`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
|
21
|
-
"disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
|
22
|
-
"`exists?` instead."
|
23
|
-
)
|
24
|
-
end
|
25
|
-
|
26
|
-
@exists_returns_integer = value
|
27
|
-
end
|
28
|
-
|
29
14
|
def deprecate!(message)
|
30
15
|
unless silence_deprecations
|
31
16
|
if raise_deprecations
|
@@ -35,20 +20,12 @@ class Redis
|
|
35
20
|
end
|
36
21
|
end
|
37
22
|
end
|
38
|
-
|
39
|
-
def current
|
40
|
-
deprecate!("`Redis.current=` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
|
41
|
-
@current ||= Redis.new
|
42
|
-
end
|
43
|
-
|
44
|
-
def current=(redis)
|
45
|
-
deprecate!("`Redis.current=` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
|
46
|
-
@current = redis
|
47
|
-
end
|
48
23
|
end
|
49
24
|
|
50
25
|
include Commands
|
51
26
|
|
27
|
+
SERVER_URL_OPTIONS = %i(url host port path).freeze
|
28
|
+
|
52
29
|
# Create a new client instance
|
53
30
|
#
|
54
31
|
# @param [Hash] options
|
@@ -62,174 +39,66 @@ class Redis
|
|
62
39
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
63
40
|
# @option options [String] :username Username to authenticate against server
|
64
41
|
# @option options [String] :password Password to authenticate against server
|
65
|
-
# @option options [Integer] :db (0) Database to select after
|
66
|
-
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis
|
42
|
+
# @option options [Integer] :db (0) Database to select after connect and on reconnects
|
43
|
+
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`
|
67
44
|
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
68
45
|
# `CLIENT SETNAME`
|
69
|
-
# @option options [
|
70
|
-
#
|
71
|
-
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
46
|
+
# @option options [Integer, Array<Integer, Float>] :reconnect_attempts Number of attempts trying to connect,
|
47
|
+
# or a list of sleep duration between attempts.
|
72
48
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
49
|
+
# @option options [String] :name The name of the server group to connect to.
|
73
50
|
# @option options [Array] :sentinels List of sentinels to contact
|
74
|
-
# @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
|
75
|
-
# @option options [Array<String, Hash{Symbol => String, Integer}>] :cluster List of cluster nodes to contact
|
76
|
-
# @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
|
77
|
-
# @option options [Class] :connector Class of custom connector
|
78
51
|
#
|
79
52
|
# @return [Redis] a new client instance
|
80
53
|
def initialize(options = {})
|
81
|
-
@options = options.dup
|
82
|
-
@cluster_mode = options.key?(:cluster)
|
83
|
-
client = @cluster_mode ? Cluster : Client
|
84
|
-
@original_client = @client = client.new(options)
|
85
|
-
@queue = Hash.new { |h, k| h[k] = [] }
|
86
54
|
@monitor = Monitor.new
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
synchronize do |client|
|
92
|
-
client.with_reconnect(val, &blk)
|
55
|
+
@options = options.dup
|
56
|
+
@options[:reconnect_attempts] = 1 unless @options.key?(:reconnect_attempts)
|
57
|
+
if ENV["REDIS_URL"] && SERVER_URL_OPTIONS.none? { |o| @options.key?(o) }
|
58
|
+
@options[:url] = ENV["REDIS_URL"]
|
93
59
|
end
|
60
|
+
inherit_socket = @options.delete(:inherit_socket)
|
61
|
+
@subscription_client = nil
|
62
|
+
|
63
|
+
@client = initialize_client(@options)
|
64
|
+
@client.inherit_socket! if inherit_socket
|
94
65
|
end
|
95
66
|
|
96
67
|
# Run code without the client reconnecting
|
97
|
-
def without_reconnect(&
|
98
|
-
|
68
|
+
def without_reconnect(&block)
|
69
|
+
@client.disable_reconnection(&block)
|
99
70
|
end
|
100
71
|
|
101
72
|
# Test whether or not the client is connected
|
102
73
|
def connected?
|
103
|
-
@
|
74
|
+
@client.connected? || @subscription_client&.connected?
|
104
75
|
end
|
105
76
|
|
106
77
|
# Disconnect the client as quickly and silently as possible.
|
107
78
|
def close
|
108
|
-
@
|
79
|
+
@client.close
|
80
|
+
@subscription_client&.close
|
109
81
|
end
|
110
82
|
alias disconnect! close
|
111
83
|
|
112
|
-
|
113
|
-
|
114
|
-
# Commands in the queue are executed with the Redis#commit method.
|
115
|
-
#
|
116
|
-
# See http://redis.io/topics/pipelining for more details.
|
117
|
-
#
|
118
|
-
def queue(*command)
|
119
|
-
::Redis.deprecate!(
|
120
|
-
"Redis#queue is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead." \
|
121
|
-
"(called from: #{caller(1, 1).first})"
|
122
|
-
)
|
123
|
-
|
124
|
-
synchronize do
|
125
|
-
@queue[Thread.current.object_id] << command
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# @deprecated Sends all commands in the queue.
|
130
|
-
#
|
131
|
-
# See http://redis.io/topics/pipelining for more details.
|
132
|
-
#
|
133
|
-
def commit
|
134
|
-
::Redis.deprecate!(
|
135
|
-
"Redis#commit is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead. " \
|
136
|
-
"(called from: #{Kernel.caller(1, 1).first})"
|
137
|
-
)
|
138
|
-
|
139
|
-
synchronize do |client|
|
140
|
-
begin
|
141
|
-
pipeline = Pipeline.new(client)
|
142
|
-
@queue[Thread.current.object_id].each do |command|
|
143
|
-
pipeline.call(command)
|
144
|
-
end
|
145
|
-
|
146
|
-
client.call_pipelined(pipeline)
|
147
|
-
ensure
|
148
|
-
@queue.delete(Thread.current.object_id)
|
149
|
-
end
|
150
|
-
end
|
84
|
+
def with
|
85
|
+
yield self
|
151
86
|
end
|
152
87
|
|
153
88
|
def _client
|
154
89
|
@client
|
155
90
|
end
|
156
91
|
|
157
|
-
def pipelined
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
deprecation_displayed = true
|
162
|
-
end
|
163
|
-
|
164
|
-
synchronize do |prior_client|
|
165
|
-
begin
|
166
|
-
pipeline = Pipeline.new(prior_client)
|
167
|
-
@client = deprecation_displayed ? pipeline : DeprecatedPipeline.new(pipeline)
|
168
|
-
pipelined_connection = PipelinedConnection.new(pipeline)
|
169
|
-
yield pipelined_connection
|
170
|
-
prior_client.call_pipeline(pipeline)
|
171
|
-
ensure
|
172
|
-
@client = prior_client
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Mark the start of a transaction block.
|
178
|
-
#
|
179
|
-
# Passing a block is optional.
|
180
|
-
#
|
181
|
-
# @example With a block
|
182
|
-
# redis.multi do |multi|
|
183
|
-
# multi.set("key", "value")
|
184
|
-
# multi.incr("counter")
|
185
|
-
# end # => ["OK", 6]
|
186
|
-
#
|
187
|
-
# @example Without a block
|
188
|
-
# redis.multi
|
189
|
-
# # => "OK"
|
190
|
-
# redis.set("key", "value")
|
191
|
-
# # => "QUEUED"
|
192
|
-
# redis.incr("counter")
|
193
|
-
# # => "QUEUED"
|
194
|
-
# redis.exec
|
195
|
-
# # => ["OK", 6]
|
196
|
-
#
|
197
|
-
# @yield [multi] the commands that are called inside this block are cached
|
198
|
-
# and written to the server upon returning from it
|
199
|
-
# @yieldparam [Redis] multi `self`
|
200
|
-
#
|
201
|
-
# @return [String, Array<...>]
|
202
|
-
# - when a block is not given, `OK`
|
203
|
-
# - when a block is given, an array with replies
|
204
|
-
#
|
205
|
-
# @see #watch
|
206
|
-
# @see #unwatch
|
207
|
-
def multi(&block)
|
208
|
-
if block_given?
|
209
|
-
deprecation_displayed = false
|
210
|
-
if block&.arity == 0
|
211
|
-
Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 5))
|
212
|
-
deprecation_displayed = true
|
213
|
-
end
|
214
|
-
|
215
|
-
synchronize do |prior_client|
|
216
|
-
begin
|
217
|
-
pipeline = Pipeline::Multi.new(prior_client)
|
218
|
-
@client = deprecation_displayed ? pipeline : DeprecatedMulti.new(pipeline)
|
219
|
-
pipelined_connection = PipelinedConnection.new(pipeline)
|
220
|
-
yield pipelined_connection
|
221
|
-
prior_client.call_pipeline(pipeline)
|
222
|
-
ensure
|
223
|
-
@client = prior_client
|
224
|
-
end
|
92
|
+
def pipelined
|
93
|
+
synchronize do |client|
|
94
|
+
client.pipelined do |raw_pipeline|
|
95
|
+
yield PipelinedConnection.new(raw_pipeline)
|
225
96
|
end
|
226
|
-
else
|
227
|
-
send_command([:multi])
|
228
97
|
end
|
229
98
|
end
|
230
99
|
|
231
100
|
def id
|
232
|
-
@
|
101
|
+
@client.id || @client.server_url
|
233
102
|
end
|
234
103
|
|
235
104
|
def inspect
|
@@ -241,54 +110,79 @@ class Redis
|
|
241
110
|
end
|
242
111
|
|
243
112
|
def connection
|
244
|
-
return @original_client.connection_info if @cluster_mode
|
245
|
-
|
246
113
|
{
|
247
|
-
host: @
|
248
|
-
port: @
|
249
|
-
db: @
|
250
|
-
id:
|
251
|
-
location: @
|
114
|
+
host: @client.host,
|
115
|
+
port: @client.port,
|
116
|
+
db: @client.db,
|
117
|
+
id: id,
|
118
|
+
location: "#{@client.host}:#{@client.port}"
|
252
119
|
}
|
253
120
|
end
|
254
121
|
|
255
122
|
private
|
256
123
|
|
124
|
+
def initialize_client(options)
|
125
|
+
if options.key?(:cluster)
|
126
|
+
raise "Redis Cluster support was moved to the `redis_cluster` gem."
|
127
|
+
end
|
128
|
+
|
129
|
+
if options.key?(:sentinels)
|
130
|
+
if url = options.delete(:url)
|
131
|
+
uri = URI.parse(url)
|
132
|
+
if !options.key?(:name) && uri.host
|
133
|
+
options[:name] = uri.host
|
134
|
+
end
|
135
|
+
|
136
|
+
if !options.key?(:password) && uri.password && !uri.password.empty?
|
137
|
+
options[:password] = uri.password
|
138
|
+
end
|
139
|
+
|
140
|
+
if !options.key?(:username) && uri.user && !uri.user.empty?
|
141
|
+
options[:username] = uri.user
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
Client.sentinel(**options).new_client
|
146
|
+
else
|
147
|
+
Client.config(**options).new_client
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
257
151
|
def synchronize
|
258
152
|
@monitor.synchronize { yield(@client) }
|
259
153
|
end
|
260
154
|
|
261
155
|
def send_command(command, &block)
|
262
156
|
@monitor.synchronize do
|
263
|
-
@client.
|
157
|
+
@client.call_v(command, &block)
|
264
158
|
end
|
265
159
|
end
|
266
160
|
|
267
161
|
def send_blocking_command(command, timeout, &block)
|
268
162
|
@monitor.synchronize do
|
269
|
-
@client.
|
163
|
+
@client.blocking_call_v(timeout, command, &block)
|
270
164
|
end
|
271
165
|
end
|
272
166
|
|
273
167
|
def _subscription(method, timeout, channels, block)
|
274
|
-
|
168
|
+
if @subscription_client
|
169
|
+
return @subscription_client.call_v([method] + channels)
|
170
|
+
end
|
275
171
|
|
276
172
|
begin
|
277
|
-
|
173
|
+
@subscription_client = SubscribedClient.new(@client.pubsub)
|
278
174
|
if timeout > 0
|
279
|
-
@
|
175
|
+
@subscription_client.send(method, timeout, *channels, &block)
|
280
176
|
else
|
281
|
-
@
|
177
|
+
@subscription_client.send(method, *channels, &block)
|
282
178
|
end
|
283
179
|
ensure
|
284
|
-
@
|
180
|
+
@subscription_client = nil
|
285
181
|
end
|
286
182
|
end
|
287
183
|
end
|
288
184
|
|
289
185
|
require "redis/version"
|
290
|
-
require "redis/connection"
|
291
186
|
require "redis/client"
|
292
|
-
require "redis/cluster"
|
293
187
|
require "redis/pipeline"
|
294
188
|
require "redis/subscribe"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0.beta3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -16,50 +16,22 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2022-
|
19
|
+
date: 2022-08-18 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: redis-client
|
23
23
|
requirement: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '0'
|
28
|
-
type: :
|
27
|
+
version: '0.7'
|
28
|
+
type: :runtime
|
29
29
|
prerelease: false
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: hiredis
|
37
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
42
|
-
type: :development
|
43
|
-
prerelease: false
|
44
|
-
version_requirements: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ">="
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: mocha
|
51
|
-
requirement: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
56
|
-
type: :development
|
57
|
-
prerelease: false
|
58
|
-
version_requirements: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
34
|
+
version: '0.7'
|
63
35
|
description: |2
|
64
36
|
A Ruby client that tries to match Redis' API one-to-one, while still
|
65
37
|
providing an idiomatic interface.
|
@@ -74,16 +46,6 @@ files:
|
|
74
46
|
- README.md
|
75
47
|
- lib/redis.rb
|
76
48
|
- lib/redis/client.rb
|
77
|
-
- lib/redis/cluster.rb
|
78
|
-
- lib/redis/cluster/command.rb
|
79
|
-
- lib/redis/cluster/command_loader.rb
|
80
|
-
- lib/redis/cluster/key_slot_converter.rb
|
81
|
-
- lib/redis/cluster/node.rb
|
82
|
-
- lib/redis/cluster/node_key.rb
|
83
|
-
- lib/redis/cluster/node_loader.rb
|
84
|
-
- lib/redis/cluster/option.rb
|
85
|
-
- lib/redis/cluster/slot.rb
|
86
|
-
- lib/redis/cluster/slot_loader.rb
|
87
49
|
- lib/redis/commands.rb
|
88
50
|
- lib/redis/commands/bitmaps.rb
|
89
51
|
- lib/redis/commands/cluster.rb
|
@@ -101,12 +63,6 @@ files:
|
|
101
63
|
- lib/redis/commands/streams.rb
|
102
64
|
- lib/redis/commands/strings.rb
|
103
65
|
- lib/redis/commands/transactions.rb
|
104
|
-
- lib/redis/connection.rb
|
105
|
-
- lib/redis/connection/command_helper.rb
|
106
|
-
- lib/redis/connection/hiredis.rb
|
107
|
-
- lib/redis/connection/registry.rb
|
108
|
-
- lib/redis/connection/ruby.rb
|
109
|
-
- lib/redis/connection/synchrony.rb
|
110
66
|
- lib/redis/distributed.rb
|
111
67
|
- lib/redis/errors.rb
|
112
68
|
- lib/redis/hash_ring.rb
|
@@ -119,9 +75,9 @@ licenses:
|
|
119
75
|
metadata:
|
120
76
|
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
121
77
|
changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
|
122
|
-
documentation_uri: https://www.rubydoc.info/gems/redis/
|
78
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/5.0.0.beta3
|
123
79
|
homepage_uri: https://github.com/redis/redis-rb
|
124
|
-
source_code_uri: https://github.com/redis/redis-rb/tree/
|
80
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v5.0.0.beta3
|
125
81
|
post_install_message:
|
126
82
|
rdoc_options: []
|
127
83
|
require_paths:
|
@@ -130,12 +86,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
86
|
requirements:
|
131
87
|
- - ">="
|
132
88
|
- !ruby/object:Gem::Version
|
133
|
-
version: 2.
|
89
|
+
version: 2.5.0
|
134
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
91
|
requirements:
|
136
|
-
- - "
|
92
|
+
- - ">"
|
137
93
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
94
|
+
version: 1.3.1
|
139
95
|
requirements: []
|
140
96
|
rubygems_version: 3.1.2
|
141
97
|
signing_key:
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../errors'
|
4
|
-
|
5
|
-
class Redis
|
6
|
-
class Cluster
|
7
|
-
# Keep details about Redis commands for Redis Cluster Client.
|
8
|
-
# @see https://redis.io/commands/command
|
9
|
-
class Command
|
10
|
-
def initialize(details)
|
11
|
-
@details = pick_details(details)
|
12
|
-
end
|
13
|
-
|
14
|
-
def extract_first_key(command)
|
15
|
-
i = determine_first_key_position(command)
|
16
|
-
return '' if i == 0
|
17
|
-
|
18
|
-
key = command[i].to_s
|
19
|
-
hash_tag = extract_hash_tag(key)
|
20
|
-
hash_tag.empty? ? key : hash_tag
|
21
|
-
end
|
22
|
-
|
23
|
-
def should_send_to_master?(command)
|
24
|
-
dig_details(command, :write)
|
25
|
-
end
|
26
|
-
|
27
|
-
def should_send_to_slave?(command)
|
28
|
-
dig_details(command, :readonly)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def pick_details(details)
|
34
|
-
details.transform_values do |detail|
|
35
|
-
{
|
36
|
-
first_key_position: detail[:first],
|
37
|
-
write: detail[:flags].include?('write'),
|
38
|
-
readonly: detail[:flags].include?('readonly')
|
39
|
-
}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def dig_details(command, key)
|
44
|
-
name = command.first.to_s
|
45
|
-
return unless @details.key?(name)
|
46
|
-
|
47
|
-
@details.fetch(name).fetch(key)
|
48
|
-
end
|
49
|
-
|
50
|
-
def determine_first_key_position(command)
|
51
|
-
case command.first.to_s.downcase
|
52
|
-
when 'eval', 'evalsha', 'migrate', 'zinterstore', 'zunionstore' then 3
|
53
|
-
when 'object' then 2
|
54
|
-
when 'memory'
|
55
|
-
command[1].to_s.casecmp('usage').zero? ? 2 : 0
|
56
|
-
when 'xread', 'xreadgroup'
|
57
|
-
determine_optional_key_position(command, 'streams')
|
58
|
-
else
|
59
|
-
dig_details(command, :first_key_position).to_i
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def determine_optional_key_position(command, option_name)
|
64
|
-
idx = command.map(&:to_s).map(&:downcase).index(option_name)
|
65
|
-
idx.nil? ? 0 : idx + 1
|
66
|
-
end
|
67
|
-
|
68
|
-
# @see https://redis.io/topics/cluster-spec#keys-hash-tags Keys hash tags
|
69
|
-
def extract_hash_tag(key)
|
70
|
-
s = key.index('{')
|
71
|
-
e = key.index('}', s.to_i + 1)
|
72
|
-
|
73
|
-
return '' if s.nil? || e.nil?
|
74
|
-
|
75
|
-
key[s + 1..e - 1]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../errors'
|
4
|
-
|
5
|
-
class Redis
|
6
|
-
class Cluster
|
7
|
-
# Load details about Redis commands for Redis Cluster Client
|
8
|
-
# @see https://redis.io/commands/command
|
9
|
-
module CommandLoader
|
10
|
-
module_function
|
11
|
-
|
12
|
-
def load(nodes)
|
13
|
-
nodes.each do |node|
|
14
|
-
begin
|
15
|
-
return fetch_command_details(node)
|
16
|
-
rescue CannotConnectError, ConnectionError, CommandError
|
17
|
-
next # can retry on another node
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
raise CannotConnectError, 'Redis client could not connect to any cluster nodes'
|
22
|
-
end
|
23
|
-
|
24
|
-
def fetch_command_details(node)
|
25
|
-
node.call(%i[command]).map do |reply|
|
26
|
-
[reply[0], { arity: reply[1], flags: reply[2], first: reply[3], last: reply[4], step: reply[5] }]
|
27
|
-
end.to_h
|
28
|
-
end
|
29
|
-
|
30
|
-
private_class_method :fetch_command_details
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Redis
|
4
|
-
class Cluster
|
5
|
-
# Key to slot converter for Redis Cluster Client
|
6
|
-
#
|
7
|
-
# We can test it by `CLUSTER KEYSLOT` command.
|
8
|
-
#
|
9
|
-
# @see https://github.com/antirez/redis-rb-cluster
|
10
|
-
# Reference implementation in Ruby
|
11
|
-
# @see https://redis.io/topics/cluster-spec#appendix
|
12
|
-
# Reference implementation in ANSI C
|
13
|
-
# @see https://redis.io/commands/cluster-keyslot
|
14
|
-
# CLUSTER KEYSLOT command reference
|
15
|
-
#
|
16
|
-
# Copyright (C) 2013 Salvatore Sanfilippo <antirez@gmail.com>
|
17
|
-
module KeySlotConverter
|
18
|
-
XMODEM_CRC16_LOOKUP = [
|
19
|
-
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
20
|
-
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
21
|
-
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
22
|
-
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
23
|
-
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
24
|
-
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
25
|
-
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
26
|
-
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
27
|
-
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
28
|
-
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
29
|
-
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
30
|
-
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
31
|
-
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
32
|
-
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
33
|
-
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
34
|
-
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
35
|
-
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
36
|
-
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
37
|
-
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
38
|
-
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
39
|
-
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
40
|
-
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
41
|
-
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
42
|
-
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
43
|
-
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
44
|
-
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
45
|
-
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
46
|
-
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
47
|
-
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
48
|
-
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
49
|
-
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
50
|
-
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
51
|
-
].freeze
|
52
|
-
|
53
|
-
HASH_SLOTS = 16_384
|
54
|
-
|
55
|
-
module_function
|
56
|
-
|
57
|
-
# Convert key into slot.
|
58
|
-
#
|
59
|
-
# @param key [String] the key of the redis command
|
60
|
-
#
|
61
|
-
# @return [Integer] slot number
|
62
|
-
def convert(key)
|
63
|
-
crc = 0
|
64
|
-
key.each_byte do |b|
|
65
|
-
crc = ((crc << 8) & 0xffff) ^ XMODEM_CRC16_LOOKUP[((crc >> 8) ^ b) & 0xff]
|
66
|
-
end
|
67
|
-
|
68
|
-
crc % HASH_SLOTS
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|