redis 4.8.1 → 5.4.1
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 +86 -0
- data/README.md +125 -162
- data/lib/redis/client.rb +81 -608
- data/lib/redis/commands/bitmaps.rb +14 -4
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +3 -3
- data/lib/redis/commands/hashes.rb +13 -6
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +27 -23
- data/lib/redis/commands/lists.rb +74 -25
- data/lib/redis/commands/pubsub.rb +34 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +35 -40
- data/lib/redis/commands/sorted_sets.rb +128 -18
- data/lib/redis/commands/streams.rb +48 -21
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +11 -12
- data/lib/redis/distributed.rb +136 -72
- data/lib/redis/errors.rb +20 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +47 -222
- data/lib/redis/subscribe.rb +50 -14
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +79 -184
- metadata +10 -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 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- 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 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
data/lib/redis.rb
CHANGED
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "redis-client"
|
|
4
|
+
|
|
3
5
|
require "monitor"
|
|
4
6
|
require "redis/errors"
|
|
5
7
|
require "redis/commands"
|
|
6
8
|
|
|
7
9
|
class Redis
|
|
8
10
|
BASE_PATH = __dir__
|
|
9
|
-
@exists_returns_integer = true
|
|
10
|
-
@sadd_returns_boolean = true
|
|
11
|
-
|
|
12
11
|
Deprecated = Class.new(StandardError)
|
|
13
12
|
|
|
14
13
|
class << self
|
|
15
|
-
|
|
16
|
-
attr_accessor :silence_deprecations, :raise_deprecations, :sadd_returns_boolean
|
|
17
|
-
|
|
18
|
-
def exists_returns_integer=(value)
|
|
19
|
-
unless value
|
|
20
|
-
deprecate!(
|
|
21
|
-
"`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
|
|
22
|
-
"disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
|
|
23
|
-
"`exists?` instead."
|
|
24
|
-
)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
@exists_returns_integer = value
|
|
28
|
-
end
|
|
14
|
+
attr_accessor :silence_deprecations, :raise_deprecations
|
|
29
15
|
|
|
30
16
|
def deprecate!(message)
|
|
31
17
|
unless silence_deprecations
|
|
@@ -36,20 +22,22 @@ class Redis
|
|
|
36
22
|
end
|
|
37
23
|
end
|
|
38
24
|
end
|
|
25
|
+
end
|
|
39
26
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@current = redis
|
|
27
|
+
# soft-deprecated
|
|
28
|
+
# We added this back for older sidekiq releases
|
|
29
|
+
module Connection
|
|
30
|
+
class << self
|
|
31
|
+
def drivers
|
|
32
|
+
[RedisClient.default_driver]
|
|
33
|
+
end
|
|
48
34
|
end
|
|
49
35
|
end
|
|
50
36
|
|
|
51
37
|
include Commands
|
|
52
38
|
|
|
39
|
+
SERVER_URL_OPTIONS = %i(url host port path).freeze
|
|
40
|
+
|
|
53
41
|
# Create a new client instance
|
|
54
42
|
#
|
|
55
43
|
# @param [Hash] options
|
|
@@ -59,56 +47,49 @@ class Redis
|
|
|
59
47
|
# @option options [String] :host ("127.0.0.1") server hostname
|
|
60
48
|
# @option options [Integer] :port (6379) server port
|
|
61
49
|
# @option options [String] :path path to server socket (overrides host and port)
|
|
62
|
-
# @option options [Float] :timeout (
|
|
50
|
+
# @option options [Float] :timeout (1.0) timeout in seconds
|
|
63
51
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
|
64
52
|
# @option options [String] :username Username to authenticate against server
|
|
65
53
|
# @option options [String] :password Password to authenticate against server
|
|
66
|
-
# @option options [Integer] :db (0) Database to select after
|
|
67
|
-
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis
|
|
54
|
+
# @option options [Integer] :db (0) Database to select after connect and on reconnects
|
|
55
|
+
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`
|
|
68
56
|
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
|
69
57
|
# `CLIENT SETNAME`
|
|
70
|
-
# @option options [
|
|
71
|
-
#
|
|
72
|
-
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
|
58
|
+
# @option options [Integer, Array<Integer, Float>] :reconnect_attempts Number of attempts trying to connect,
|
|
59
|
+
# or a list of sleep duration between attempts.
|
|
73
60
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
|
61
|
+
# @option options [String] :name The name of the server group to connect to.
|
|
74
62
|
# @option options [Array] :sentinels List of sentinels to contact
|
|
75
|
-
# @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
|
|
76
|
-
# @option options [Array<String, Hash{Symbol => String, Integer}>] :cluster List of cluster nodes to contact
|
|
77
|
-
# @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
|
|
78
|
-
# @option options [String] :fixed_hostname Specify a FQDN if cluster mode enabled and
|
|
79
|
-
# client has to connect nodes via single endpoint with SSL/TLS
|
|
80
|
-
# @option options [Class] :connector Class of custom connector
|
|
81
63
|
#
|
|
82
64
|
# @return [Redis] a new client instance
|
|
83
65
|
def initialize(options = {})
|
|
84
|
-
@options = options.dup
|
|
85
|
-
@cluster_mode = options.key?(:cluster)
|
|
86
|
-
client = @cluster_mode ? Cluster : Client
|
|
87
|
-
@original_client = @client = client.new(options)
|
|
88
|
-
@queue = Hash.new { |h, k| h[k] = [] }
|
|
89
66
|
@monitor = Monitor.new
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
synchronize do |client|
|
|
95
|
-
client.with_reconnect(val, &blk)
|
|
67
|
+
@options = options.dup
|
|
68
|
+
@options[:reconnect_attempts] = 1 unless @options.key?(:reconnect_attempts)
|
|
69
|
+
if ENV["REDIS_URL"] && SERVER_URL_OPTIONS.none? { |o| @options.key?(o) }
|
|
70
|
+
@options[:url] = ENV["REDIS_URL"]
|
|
96
71
|
end
|
|
72
|
+
inherit_socket = @options.delete(:inherit_socket)
|
|
73
|
+
@subscription_client = nil
|
|
74
|
+
|
|
75
|
+
@client = initialize_client(@options)
|
|
76
|
+
@client.inherit_socket! if inherit_socket
|
|
97
77
|
end
|
|
98
78
|
|
|
99
79
|
# Run code without the client reconnecting
|
|
100
|
-
def without_reconnect(&
|
|
101
|
-
|
|
80
|
+
def without_reconnect(&block)
|
|
81
|
+
@client.disable_reconnection(&block)
|
|
102
82
|
end
|
|
103
83
|
|
|
104
84
|
# Test whether or not the client is connected
|
|
105
85
|
def connected?
|
|
106
|
-
@
|
|
86
|
+
@client.connected? || @subscription_client&.connected?
|
|
107
87
|
end
|
|
108
88
|
|
|
109
89
|
# Disconnect the client as quickly and silently as possible.
|
|
110
90
|
def close
|
|
111
|
-
@
|
|
91
|
+
@client.close
|
|
92
|
+
@subscription_client&.close
|
|
112
93
|
end
|
|
113
94
|
alias disconnect! close
|
|
114
95
|
|
|
@@ -116,127 +97,20 @@ class Redis
|
|
|
116
97
|
yield self
|
|
117
98
|
end
|
|
118
99
|
|
|
119
|
-
# @deprecated Queues a command for pipelining.
|
|
120
|
-
#
|
|
121
|
-
# Commands in the queue are executed with the Redis#commit method.
|
|
122
|
-
#
|
|
123
|
-
# See http://redis.io/topics/pipelining for more details.
|
|
124
|
-
#
|
|
125
|
-
def queue(*command)
|
|
126
|
-
::Redis.deprecate!(
|
|
127
|
-
"Redis#queue is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead." \
|
|
128
|
-
"(called from: #{caller(1, 1).first})"
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
synchronize do
|
|
132
|
-
@queue[Thread.current.object_id] << command
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# @deprecated Sends all commands in the queue.
|
|
137
|
-
#
|
|
138
|
-
# See http://redis.io/topics/pipelining for more details.
|
|
139
|
-
#
|
|
140
|
-
def commit
|
|
141
|
-
::Redis.deprecate!(
|
|
142
|
-
"Redis#commit is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead. " \
|
|
143
|
-
"(called from: #{Kernel.caller(1, 1).first})"
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
synchronize do |client|
|
|
147
|
-
begin
|
|
148
|
-
pipeline = Pipeline.new(client)
|
|
149
|
-
@queue[Thread.current.object_id].each do |command|
|
|
150
|
-
pipeline.call(command)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
client.call_pipelined(pipeline)
|
|
154
|
-
ensure
|
|
155
|
-
@queue.delete(Thread.current.object_id)
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
100
|
def _client
|
|
161
101
|
@client
|
|
162
102
|
end
|
|
163
103
|
|
|
164
|
-
def pipelined(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
deprecation_displayed = true
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
synchronize do |prior_client|
|
|
172
|
-
begin
|
|
173
|
-
pipeline = Pipeline.new(prior_client)
|
|
174
|
-
@client = deprecation_displayed ? pipeline : DeprecatedPipeline.new(pipeline)
|
|
175
|
-
pipelined_connection = PipelinedConnection.new(pipeline)
|
|
176
|
-
yield pipelined_connection
|
|
177
|
-
prior_client.call_pipeline(pipeline)
|
|
178
|
-
ensure
|
|
179
|
-
@client = prior_client
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Mark the start of a transaction block.
|
|
185
|
-
#
|
|
186
|
-
# Passing a block is optional.
|
|
187
|
-
#
|
|
188
|
-
# @example With a block
|
|
189
|
-
# redis.multi do |multi|
|
|
190
|
-
# multi.set("key", "value")
|
|
191
|
-
# multi.incr("counter")
|
|
192
|
-
# end # => ["OK", 6]
|
|
193
|
-
#
|
|
194
|
-
# @example Without a block
|
|
195
|
-
# redis.multi
|
|
196
|
-
# # => "OK"
|
|
197
|
-
# redis.set("key", "value")
|
|
198
|
-
# # => "QUEUED"
|
|
199
|
-
# redis.incr("counter")
|
|
200
|
-
# # => "QUEUED"
|
|
201
|
-
# redis.exec
|
|
202
|
-
# # => ["OK", 6]
|
|
203
|
-
#
|
|
204
|
-
# @yield [multi] the commands that are called inside this block are cached
|
|
205
|
-
# and written to the server upon returning from it
|
|
206
|
-
# @yieldparam [Redis] multi `self`
|
|
207
|
-
#
|
|
208
|
-
# @return [String, Array<...>]
|
|
209
|
-
# - when a block is not given, `OK`
|
|
210
|
-
# - when a block is given, an array with replies
|
|
211
|
-
#
|
|
212
|
-
# @see #watch
|
|
213
|
-
# @see #unwatch
|
|
214
|
-
def multi(&block)
|
|
215
|
-
if block_given?
|
|
216
|
-
deprecation_displayed = false
|
|
217
|
-
if block&.arity == 0
|
|
218
|
-
Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 5))
|
|
219
|
-
deprecation_displayed = true
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
synchronize do |prior_client|
|
|
223
|
-
begin
|
|
224
|
-
pipeline = Pipeline::Multi.new(prior_client)
|
|
225
|
-
@client = deprecation_displayed ? pipeline : DeprecatedMulti.new(pipeline)
|
|
226
|
-
pipelined_connection = PipelinedConnection.new(pipeline)
|
|
227
|
-
yield pipelined_connection
|
|
228
|
-
prior_client.call_pipeline(pipeline)
|
|
229
|
-
ensure
|
|
230
|
-
@client = prior_client
|
|
231
|
-
end
|
|
104
|
+
def pipelined(exception: true)
|
|
105
|
+
synchronize do |client|
|
|
106
|
+
client.pipelined(exception: exception) do |raw_pipeline|
|
|
107
|
+
yield PipelinedConnection.new(raw_pipeline, exception: exception)
|
|
232
108
|
end
|
|
233
|
-
else
|
|
234
|
-
send_command([:multi])
|
|
235
109
|
end
|
|
236
110
|
end
|
|
237
111
|
|
|
238
112
|
def id
|
|
239
|
-
@
|
|
113
|
+
@client.id || @client.server_url
|
|
240
114
|
end
|
|
241
115
|
|
|
242
116
|
def inspect
|
|
@@ -248,54 +122,75 @@ class Redis
|
|
|
248
122
|
end
|
|
249
123
|
|
|
250
124
|
def connection
|
|
251
|
-
return @original_client.connection_info if @cluster_mode
|
|
252
|
-
|
|
253
125
|
{
|
|
254
|
-
host: @
|
|
255
|
-
port: @
|
|
256
|
-
db: @
|
|
257
|
-
id:
|
|
258
|
-
location: @
|
|
126
|
+
host: @client.host,
|
|
127
|
+
port: @client.port,
|
|
128
|
+
db: @client.db,
|
|
129
|
+
id: id,
|
|
130
|
+
location: "#{@client.host}:#{@client.port}"
|
|
259
131
|
}
|
|
260
132
|
end
|
|
261
133
|
|
|
262
134
|
private
|
|
263
135
|
|
|
136
|
+
def initialize_client(options)
|
|
137
|
+
if options.key?(:cluster)
|
|
138
|
+
raise "Redis Cluster support was moved to the `redis-clustering` gem."
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
if options.key?(:sentinels)
|
|
142
|
+
Client.sentinel(**options).new_client
|
|
143
|
+
else
|
|
144
|
+
Client.config(**options).new_client
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
264
148
|
def synchronize
|
|
265
149
|
@monitor.synchronize { yield(@client) }
|
|
266
150
|
end
|
|
267
151
|
|
|
268
152
|
def send_command(command, &block)
|
|
269
153
|
@monitor.synchronize do
|
|
270
|
-
@client.
|
|
154
|
+
@client.call_v(command, &block)
|
|
271
155
|
end
|
|
156
|
+
rescue ::RedisClient::Error => error
|
|
157
|
+
Client.translate_error!(error)
|
|
272
158
|
end
|
|
273
159
|
|
|
274
160
|
def send_blocking_command(command, timeout, &block)
|
|
275
161
|
@monitor.synchronize do
|
|
276
|
-
@client.
|
|
162
|
+
@client.blocking_call_v(timeout, command, &block)
|
|
277
163
|
end
|
|
278
164
|
end
|
|
279
165
|
|
|
280
166
|
def _subscription(method, timeout, channels, block)
|
|
281
|
-
|
|
167
|
+
if block
|
|
168
|
+
if @subscription_client
|
|
169
|
+
raise SubscriptionError, "This client is already subscribed"
|
|
170
|
+
end
|
|
282
171
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
172
|
+
begin
|
|
173
|
+
@subscription_client = SubscribedClient.new(@client.pubsub)
|
|
174
|
+
if timeout > 0
|
|
175
|
+
@subscription_client.send(method, timeout, *channels, &block)
|
|
176
|
+
else
|
|
177
|
+
@subscription_client.send(method, *channels, &block)
|
|
178
|
+
end
|
|
179
|
+
ensure
|
|
180
|
+
@subscription_client&.close
|
|
181
|
+
@subscription_client = nil
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
unless @subscription_client
|
|
185
|
+
raise SubscriptionError, "This client is not subscribed"
|
|
289
186
|
end
|
|
290
|
-
|
|
291
|
-
@
|
|
187
|
+
|
|
188
|
+
@subscription_client.call_v([method].concat(channels))
|
|
292
189
|
end
|
|
293
190
|
end
|
|
294
191
|
end
|
|
295
192
|
|
|
296
193
|
require "redis/version"
|
|
297
|
-
require "redis/connection"
|
|
298
194
|
require "redis/client"
|
|
299
|
-
require "redis/cluster"
|
|
300
195
|
require "redis/pipeline"
|
|
301
196
|
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.
|
|
4
|
+
version: 5.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ezra Zygmuntowicz
|
|
@@ -13,53 +13,24 @@ authors:
|
|
|
13
13
|
- Michel Martens
|
|
14
14
|
- Damian Janowski
|
|
15
15
|
- Pieter Noordhuis
|
|
16
|
-
autorequire:
|
|
17
16
|
bindir: bin
|
|
18
17
|
cert_chain: []
|
|
19
|
-
date:
|
|
18
|
+
date: 2025-07-17 00:00:00.000000000 Z
|
|
20
19
|
dependencies:
|
|
21
20
|
- !ruby/object:Gem::Dependency
|
|
22
|
-
name:
|
|
21
|
+
name: redis-client
|
|
23
22
|
requirement: !ruby/object:Gem::Requirement
|
|
24
23
|
requirements:
|
|
25
24
|
- - ">="
|
|
26
25
|
- !ruby/object:Gem::Version
|
|
27
|
-
version:
|
|
28
|
-
type: :
|
|
26
|
+
version: 0.22.0
|
|
27
|
+
type: :runtime
|
|
29
28
|
prerelease: false
|
|
30
29
|
version_requirements: !ruby/object:Gem::Requirement
|
|
31
30
|
requirements:
|
|
32
31
|
- - ">="
|
|
33
32
|
- !ruby/object:Gem::Version
|
|
34
|
-
version:
|
|
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'
|
|
33
|
+
version: 0.22.0
|
|
63
34
|
description: |2
|
|
64
35
|
A Ruby client that tries to match Redis' API one-to-one, while still
|
|
65
36
|
providing an idiomatic interface.
|
|
@@ -74,16 +45,6 @@ files:
|
|
|
74
45
|
- README.md
|
|
75
46
|
- lib/redis.rb
|
|
76
47
|
- 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
48
|
- lib/redis/commands.rb
|
|
88
49
|
- lib/redis/commands/bitmaps.rb
|
|
89
50
|
- lib/redis/commands/cluster.rb
|
|
@@ -101,12 +62,6 @@ files:
|
|
|
101
62
|
- lib/redis/commands/streams.rb
|
|
102
63
|
- lib/redis/commands/strings.rb
|
|
103
64
|
- 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
65
|
- lib/redis/distributed.rb
|
|
111
66
|
- lib/redis/errors.rb
|
|
112
67
|
- lib/redis/hash_ring.rb
|
|
@@ -119,10 +74,9 @@ licenses:
|
|
|
119
74
|
metadata:
|
|
120
75
|
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
|
121
76
|
changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
|
|
122
|
-
documentation_uri: https://www.rubydoc.info/gems/redis/4.
|
|
77
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/5.4.1
|
|
123
78
|
homepage_uri: https://github.com/redis/redis-rb
|
|
124
|
-
source_code_uri: https://github.com/redis/redis-rb/tree/
|
|
125
|
-
post_install_message:
|
|
79
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v5.4.1
|
|
126
80
|
rdoc_options: []
|
|
127
81
|
require_paths:
|
|
128
82
|
- lib
|
|
@@ -130,15 +84,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
130
84
|
requirements:
|
|
131
85
|
- - ">="
|
|
132
86
|
- !ruby/object:Gem::Version
|
|
133
|
-
version: 2.
|
|
87
|
+
version: 2.6.0
|
|
134
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
89
|
requirements:
|
|
136
90
|
- - ">="
|
|
137
91
|
- !ruby/object:Gem::Version
|
|
138
92
|
version: '0'
|
|
139
93
|
requirements: []
|
|
140
|
-
rubygems_version: 3.
|
|
141
|
-
signing_key:
|
|
94
|
+
rubygems_version: 3.6.2
|
|
142
95
|
specification_version: 4
|
|
143
96
|
summary: A Ruby client library for Redis
|
|
144
97
|
test_files: []
|
|
@@ -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 'redis/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
|
-
errors = nodes.map do |node|
|
|
14
|
-
begin
|
|
15
|
-
return fetch_command_details(node)
|
|
16
|
-
rescue CannotConnectError, ConnectionError, CommandError => error
|
|
17
|
-
error
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
raise InitialSetupError, errors
|
|
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
|