redis 4.8.1 → 6.0.0
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 +138 -1
- data/README.md +285 -169
- data/lib/redis/client.rb +116 -611
- 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 +109 -7
- data/lib/redis/commands/hashes.rb +179 -8
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +32 -24
- data/lib/redis/commands/lists.rb +167 -25
- data/lib/redis/commands/modules/json.rb +530 -0
- data/lib/redis/commands/modules/search/aggregation.rb +418 -0
- data/lib/redis/commands/modules/search/dialect.rb +14 -0
- data/lib/redis/commands/modules/search/field.rb +306 -0
- data/lib/redis/commands/modules/search/hybrid.rb +359 -0
- data/lib/redis/commands/modules/search/index.rb +351 -0
- data/lib/redis/commands/modules/search/index_definition.rb +114 -0
- data/lib/redis/commands/modules/search/miscellaneous.rb +607 -0
- data/lib/redis/commands/modules/search/query.rb +738 -0
- data/lib/redis/commands/modules/search/result.rb +488 -0
- data/lib/redis/commands/modules/search/schema.rb +211 -0
- data/lib/redis/commands/modules/search.rb +19 -0
- data/lib/redis/commands/pubsub.rb +34 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +76 -40
- data/lib/redis/commands/sorted_sets.rb +128 -19
- data/lib/redis/commands/streams.rb +75 -28
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +39 -20
- data/lib/redis/distributed.rb +407 -73
- data/lib/redis/errors.rb +20 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/lib_identity.rb +105 -0
- data/lib/redis/pipeline.rb +47 -222
- data/lib/redis/subscribe.rb +51 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +213 -188
- metadata +25 -59
- 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/cluster/slot.rb
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Redis
|
|
4
|
-
class Cluster
|
|
5
|
-
# Keep slot and node key map for Redis Cluster Client
|
|
6
|
-
class Slot
|
|
7
|
-
ROLE_SLAVE = 'slave'
|
|
8
|
-
|
|
9
|
-
def initialize(available_slots, node_flags = {}, with_replica = false)
|
|
10
|
-
@with_replica = with_replica
|
|
11
|
-
@node_flags = node_flags
|
|
12
|
-
@map = build_slot_node_key_map(available_slots)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def exists?(slot)
|
|
16
|
-
@map.key?(slot)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def find_node_key_of_master(slot)
|
|
20
|
-
return nil unless exists?(slot)
|
|
21
|
-
|
|
22
|
-
@map[slot][:master]
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def find_node_key_of_slave(slot)
|
|
26
|
-
return nil unless exists?(slot)
|
|
27
|
-
return find_node_key_of_master(slot) if replica_disabled?
|
|
28
|
-
|
|
29
|
-
@map[slot][:slaves].sample
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def put(slot, node_key)
|
|
33
|
-
# Since we're sharing a hash for build_slot_node_key_map, duplicate it
|
|
34
|
-
# if it already exists instead of preserving as-is.
|
|
35
|
-
@map[slot] = @map[slot] ? @map[slot].dup : { master: nil, slaves: [] }
|
|
36
|
-
|
|
37
|
-
if master?(node_key)
|
|
38
|
-
@map[slot][:master] = node_key
|
|
39
|
-
elsif !@map[slot][:slaves].include?(node_key)
|
|
40
|
-
@map[slot][:slaves] << node_key
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
nil
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
def replica_disabled?
|
|
49
|
-
!@with_replica
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def master?(node_key)
|
|
53
|
-
!slave?(node_key)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def slave?(node_key)
|
|
57
|
-
@node_flags[node_key] == ROLE_SLAVE
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# available_slots is mapping of node_key to list of slot ranges
|
|
61
|
-
def build_slot_node_key_map(available_slots)
|
|
62
|
-
by_ranges = {}
|
|
63
|
-
available_slots.each do |node_key, slots_arr|
|
|
64
|
-
by_ranges[slots_arr] ||= { master: nil, slaves: [] }
|
|
65
|
-
|
|
66
|
-
if master?(node_key)
|
|
67
|
-
by_ranges[slots_arr][:master] = node_key
|
|
68
|
-
elsif !by_ranges[slots_arr][:slaves].include?(node_key)
|
|
69
|
-
by_ranges[slots_arr][:slaves] << node_key
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
by_slot = {}
|
|
74
|
-
by_ranges.each do |slots_arr, nodes|
|
|
75
|
-
slots_arr.each do |slots|
|
|
76
|
-
slots.each do |slot|
|
|
77
|
-
by_slot[slot] = nodes
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
by_slot
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'redis/errors'
|
|
4
|
-
require 'redis/cluster/node_key'
|
|
5
|
-
|
|
6
|
-
class Redis
|
|
7
|
-
class Cluster
|
|
8
|
-
# Load and hashify slot info for Redis Cluster Client
|
|
9
|
-
module SlotLoader
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
def load(nodes)
|
|
13
|
-
errors = nodes.map do |node|
|
|
14
|
-
begin
|
|
15
|
-
return fetch_slot_info(node)
|
|
16
|
-
rescue CannotConnectError, ConnectionError, CommandError => error
|
|
17
|
-
error
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
raise InitialSetupError, errors
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def fetch_slot_info(node)
|
|
25
|
-
hash_with_default_arr = Hash.new { |h, k| h[k] = [] }
|
|
26
|
-
node.call(%i[cluster slots])
|
|
27
|
-
.flat_map { |arr| parse_slot_info(arr, default_ip: node.host) }
|
|
28
|
-
.each_with_object(hash_with_default_arr) { |arr, h| h[arr[0]] << arr[1] }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def parse_slot_info(arr, default_ip:)
|
|
32
|
-
first_slot, last_slot = arr[0..1]
|
|
33
|
-
slot_range = (first_slot..last_slot).freeze
|
|
34
|
-
arr[2..-1].map { |addr| [stringify_node_key(addr, default_ip), slot_range] }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def stringify_node_key(arr, default_ip)
|
|
38
|
-
ip, port = arr
|
|
39
|
-
ip = default_ip if ip.empty? # When cluster is down
|
|
40
|
-
NodeKey.build_from_host_port(ip, port)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
private_class_method :fetch_slot_info, :parse_slot_info, :stringify_node_key
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
data/lib/redis/cluster.rb
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'errors'
|
|
4
|
-
require_relative 'client'
|
|
5
|
-
require_relative 'cluster/command'
|
|
6
|
-
require_relative 'cluster/command_loader'
|
|
7
|
-
require_relative 'cluster/key_slot_converter'
|
|
8
|
-
require_relative 'cluster/node'
|
|
9
|
-
require_relative 'cluster/node_key'
|
|
10
|
-
require_relative 'cluster/node_loader'
|
|
11
|
-
require_relative 'cluster/option'
|
|
12
|
-
require_relative 'cluster/slot'
|
|
13
|
-
require_relative 'cluster/slot_loader'
|
|
14
|
-
|
|
15
|
-
class Redis
|
|
16
|
-
# Redis Cluster client
|
|
17
|
-
#
|
|
18
|
-
# @see https://github.com/antirez/redis-rb-cluster POC implementation
|
|
19
|
-
# @see https://redis.io/topics/cluster-spec Redis Cluster specification
|
|
20
|
-
# @see https://redis.io/topics/cluster-tutorial Redis Cluster tutorial
|
|
21
|
-
#
|
|
22
|
-
# Copyright (C) 2013 Salvatore Sanfilippo <antirez@gmail.com>
|
|
23
|
-
class Cluster
|
|
24
|
-
def initialize(options = {})
|
|
25
|
-
@option = Option.new(options)
|
|
26
|
-
@node, @slot = fetch_cluster_info!(@option)
|
|
27
|
-
@command = fetch_command_details(@node)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def id
|
|
31
|
-
@node.map(&:id).sort.join(' ')
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# db feature is disabled in cluster mode
|
|
35
|
-
def db
|
|
36
|
-
0
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# db feature is disabled in cluster mode
|
|
40
|
-
def db=(_db); end
|
|
41
|
-
|
|
42
|
-
def timeout
|
|
43
|
-
@node.first.timeout
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def connected?
|
|
47
|
-
@node.any?(&:connected?)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def disconnect
|
|
51
|
-
@node.each(&:disconnect)
|
|
52
|
-
true
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def connection_info
|
|
56
|
-
@node.sort_by(&:id).map do |client|
|
|
57
|
-
{
|
|
58
|
-
host: client.host,
|
|
59
|
-
port: client.port,
|
|
60
|
-
db: client.db,
|
|
61
|
-
id: client.id,
|
|
62
|
-
location: client.location
|
|
63
|
-
}
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def with_reconnect(val = true, &block)
|
|
68
|
-
try_send(@node.sample, :with_reconnect, val, &block)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def call(command, &block)
|
|
72
|
-
send_command(command, &block)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def call_loop(command, timeout = 0, &block)
|
|
76
|
-
node = assign_node(command)
|
|
77
|
-
try_send(node, :call_loop, command, timeout, &block)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def call_pipeline(pipeline)
|
|
81
|
-
node_keys = pipeline.commands.map { |cmd| find_node_key(cmd, primary_only: true) }.compact.uniq
|
|
82
|
-
if node_keys.size > 1
|
|
83
|
-
raise(CrossSlotPipeliningError,
|
|
84
|
-
pipeline.commands.map { |cmd| @command.extract_first_key(cmd) }.reject(&:empty?).uniq)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
try_send(find_node(node_keys.first), :call_pipeline, pipeline)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def call_with_timeout(command, timeout, &block)
|
|
91
|
-
node = assign_node(command)
|
|
92
|
-
try_send(node, :call_with_timeout, command, timeout, &block)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def call_without_timeout(command, &block)
|
|
96
|
-
call_with_timeout(command, 0, &block)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def process(commands, &block)
|
|
100
|
-
if commands.size == 1 &&
|
|
101
|
-
%w[unsubscribe punsubscribe].include?(commands.first.first.to_s.downcase) &&
|
|
102
|
-
commands.first.size == 1
|
|
103
|
-
|
|
104
|
-
# Node is indeterminate. We do just a best-effort try here.
|
|
105
|
-
@node.process_all(commands, &block)
|
|
106
|
-
else
|
|
107
|
-
node = assign_node(commands.first)
|
|
108
|
-
try_send(node, :process, commands, &block)
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
private
|
|
113
|
-
|
|
114
|
-
def fetch_cluster_info!(option)
|
|
115
|
-
node = Node.new(option.per_node_key)
|
|
116
|
-
available_slots = SlotLoader.load(node)
|
|
117
|
-
node_flags = NodeLoader.load_flags(node)
|
|
118
|
-
option.update_node(available_slots.keys.map { |k| NodeKey.optionize(k) })
|
|
119
|
-
[Node.new(option.per_node_key, node_flags, option.use_replica?),
|
|
120
|
-
Slot.new(available_slots, node_flags, option.use_replica?)]
|
|
121
|
-
ensure
|
|
122
|
-
node&.each(&:disconnect)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def fetch_command_details(nodes)
|
|
126
|
-
details = CommandLoader.load(nodes)
|
|
127
|
-
Command.new(details)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def send_command(command, &block)
|
|
131
|
-
cmd = command.first.to_s.downcase
|
|
132
|
-
case cmd
|
|
133
|
-
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
|
134
|
-
@node.call_all(command, &block).first
|
|
135
|
-
when 'flushall', 'flushdb'
|
|
136
|
-
@node.call_master(command, &block).first
|
|
137
|
-
when 'wait' then @node.call_master(command, &block).reduce(:+)
|
|
138
|
-
when 'keys' then @node.call_slave(command, &block).flatten.sort
|
|
139
|
-
when 'dbsize' then @node.call_slave(command, &block).reduce(:+)
|
|
140
|
-
when 'scan' then _scan(command, &block)
|
|
141
|
-
when 'lastsave' then @node.call_all(command, &block).sort
|
|
142
|
-
when 'role' then @node.call_all(command, &block)
|
|
143
|
-
when 'config' then send_config_command(command, &block)
|
|
144
|
-
when 'client' then send_client_command(command, &block)
|
|
145
|
-
when 'cluster' then send_cluster_command(command, &block)
|
|
146
|
-
when 'readonly', 'readwrite', 'shutdown'
|
|
147
|
-
raise OrchestrationCommandNotSupported, cmd
|
|
148
|
-
when 'memory' then send_memory_command(command, &block)
|
|
149
|
-
when 'script' then send_script_command(command, &block)
|
|
150
|
-
when 'pubsub' then send_pubsub_command(command, &block)
|
|
151
|
-
when 'discard', 'exec', 'multi', 'unwatch'
|
|
152
|
-
raise AmbiguousNodeError, cmd
|
|
153
|
-
else
|
|
154
|
-
node = assign_node(command)
|
|
155
|
-
try_send(node, :call, command, &block)
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def send_config_command(command, &block)
|
|
160
|
-
case command[1].to_s.downcase
|
|
161
|
-
when 'resetstat', 'rewrite', 'set'
|
|
162
|
-
@node.call_all(command, &block).first
|
|
163
|
-
else assign_node(command).call(command, &block)
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def send_memory_command(command, &block)
|
|
168
|
-
case command[1].to_s.downcase
|
|
169
|
-
when 'stats' then @node.call_all(command, &block)
|
|
170
|
-
when 'purge' then @node.call_all(command, &block).first
|
|
171
|
-
else assign_node(command).call(command, &block)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def send_client_command(command, &block)
|
|
176
|
-
case command[1].to_s.downcase
|
|
177
|
-
when 'list' then @node.call_all(command, &block).flatten
|
|
178
|
-
when 'pause', 'reply', 'setname'
|
|
179
|
-
@node.call_all(command, &block).first
|
|
180
|
-
else assign_node(command).call(command, &block)
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def send_cluster_command(command, &block)
|
|
185
|
-
subcommand = command[1].to_s.downcase
|
|
186
|
-
case subcommand
|
|
187
|
-
when 'addslots', 'delslots', 'failover', 'forget', 'meet', 'replicate',
|
|
188
|
-
'reset', 'set-config-epoch', 'setslot'
|
|
189
|
-
raise OrchestrationCommandNotSupported, 'cluster', subcommand
|
|
190
|
-
when 'saveconfig' then @node.call_all(command, &block).first
|
|
191
|
-
else assign_node(command).call(command, &block)
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def send_script_command(command, &block)
|
|
196
|
-
case command[1].to_s.downcase
|
|
197
|
-
when 'debug', 'kill'
|
|
198
|
-
@node.call_all(command, &block).first
|
|
199
|
-
when 'flush', 'load'
|
|
200
|
-
@node.call_master(command, &block).first
|
|
201
|
-
else assign_node(command).call(command, &block)
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def send_pubsub_command(command, &block)
|
|
206
|
-
case command[1].to_s.downcase
|
|
207
|
-
when 'channels' then @node.call_all(command, &block).flatten.uniq.sort
|
|
208
|
-
when 'numsub'
|
|
209
|
-
@node.call_all(command, &block).reject(&:empty?).map { |e| Hash[*e] }
|
|
210
|
-
.reduce({}) { |a, e| a.merge(e) { |_, v1, v2| v1 + v2 } }
|
|
211
|
-
when 'numpat' then @node.call_all(command, &block).reduce(:+)
|
|
212
|
-
else assign_node(command).call(command, &block)
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# @see https://redis.io/topics/cluster-spec#redirection-and-resharding
|
|
217
|
-
# Redirection and resharding
|
|
218
|
-
def try_send(node, method_name, *args, retry_count: 3, &block)
|
|
219
|
-
node.public_send(method_name, *args, &block)
|
|
220
|
-
rescue CommandError => err
|
|
221
|
-
if err.message.start_with?('MOVED')
|
|
222
|
-
raise if retry_count <= 0
|
|
223
|
-
|
|
224
|
-
node = assign_redirection_node(err.message)
|
|
225
|
-
retry_count -= 1
|
|
226
|
-
retry
|
|
227
|
-
elsif err.message.start_with?('ASK')
|
|
228
|
-
raise if retry_count <= 0
|
|
229
|
-
|
|
230
|
-
node = assign_asking_node(err.message)
|
|
231
|
-
node.call(%i[asking])
|
|
232
|
-
retry_count -= 1
|
|
233
|
-
retry
|
|
234
|
-
else
|
|
235
|
-
raise
|
|
236
|
-
end
|
|
237
|
-
rescue CannotConnectError
|
|
238
|
-
update_cluster_info!
|
|
239
|
-
raise
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def _scan(command, &block)
|
|
243
|
-
input_cursor = Integer(command[1])
|
|
244
|
-
|
|
245
|
-
client_index = input_cursor % 256
|
|
246
|
-
raw_cursor = input_cursor >> 8
|
|
247
|
-
|
|
248
|
-
clients = @node.scale_reading_clients
|
|
249
|
-
|
|
250
|
-
client = clients[client_index]
|
|
251
|
-
return ['0', []] unless client
|
|
252
|
-
|
|
253
|
-
command[1] = raw_cursor.to_s
|
|
254
|
-
|
|
255
|
-
result_cursor, result_keys = client.call(command, &block)
|
|
256
|
-
result_cursor = Integer(result_cursor)
|
|
257
|
-
|
|
258
|
-
if result_cursor == 0
|
|
259
|
-
client_index += 1
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
[((result_cursor << 8) + client_index).to_s, result_keys]
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def assign_redirection_node(err_msg)
|
|
266
|
-
_, slot, node_key = err_msg.split(' ')
|
|
267
|
-
slot = slot.to_i
|
|
268
|
-
@slot.put(slot, node_key)
|
|
269
|
-
find_node(node_key)
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
def assign_asking_node(err_msg)
|
|
273
|
-
_, _, node_key = err_msg.split(' ')
|
|
274
|
-
find_node(node_key)
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
def assign_node(command)
|
|
278
|
-
node_key = find_node_key(command)
|
|
279
|
-
find_node(node_key)
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def find_node_key(command, primary_only: false)
|
|
283
|
-
key = @command.extract_first_key(command)
|
|
284
|
-
return if key.empty?
|
|
285
|
-
|
|
286
|
-
slot = KeySlotConverter.convert(key)
|
|
287
|
-
return unless @slot.exists?(slot)
|
|
288
|
-
|
|
289
|
-
if @command.should_send_to_master?(command) || primary_only
|
|
290
|
-
@slot.find_node_key_of_master(slot)
|
|
291
|
-
else
|
|
292
|
-
@slot.find_node_key_of_slave(slot)
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def find_node(node_key)
|
|
297
|
-
return @node.sample if node_key.nil?
|
|
298
|
-
|
|
299
|
-
@node.find_by(node_key)
|
|
300
|
-
rescue Node::ReloadNeeded
|
|
301
|
-
update_cluster_info!(node_key)
|
|
302
|
-
@node.find_by(node_key)
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def update_cluster_info!(node_key = nil)
|
|
306
|
-
unless node_key.nil?
|
|
307
|
-
host, port = NodeKey.split(node_key)
|
|
308
|
-
@option.add_node(host, port)
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
@node.map(&:disconnect)
|
|
312
|
-
@node, @slot = fetch_cluster_info!(@option)
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
end
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Redis
|
|
4
|
-
module Connection
|
|
5
|
-
module CommandHelper
|
|
6
|
-
COMMAND_DELIMITER = "\r\n"
|
|
7
|
-
|
|
8
|
-
def build_command(args)
|
|
9
|
-
command = [nil]
|
|
10
|
-
|
|
11
|
-
args.each do |i|
|
|
12
|
-
if i.is_a? Array
|
|
13
|
-
i.each do |j|
|
|
14
|
-
j = j.to_s
|
|
15
|
-
j = j.encoding == Encoding::BINARY ? j : j.b
|
|
16
|
-
command << "$#{j.bytesize}"
|
|
17
|
-
command << j
|
|
18
|
-
end
|
|
19
|
-
else
|
|
20
|
-
i = i.to_s
|
|
21
|
-
i = i.encoding == Encoding::BINARY ? i : i.b
|
|
22
|
-
command << "$#{i.bytesize}"
|
|
23
|
-
command << i
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
command[0] = "*#{(command.length - 1) / 2}"
|
|
28
|
-
|
|
29
|
-
# Trailing delimiter
|
|
30
|
-
command << ""
|
|
31
|
-
command.join(COMMAND_DELIMITER)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
protected
|
|
35
|
-
|
|
36
|
-
def encode(string)
|
|
37
|
-
string.force_encoding(Encoding.default_external)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "redis/connection/registry"
|
|
4
|
-
require "redis/errors"
|
|
5
|
-
|
|
6
|
-
require "hiredis/connection"
|
|
7
|
-
require "timeout"
|
|
8
|
-
|
|
9
|
-
class Redis
|
|
10
|
-
module Connection
|
|
11
|
-
class Hiredis
|
|
12
|
-
def self.connect(config)
|
|
13
|
-
connection = ::Hiredis::Connection.new
|
|
14
|
-
connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
|
|
15
|
-
|
|
16
|
-
if config[:scheme] == "unix"
|
|
17
|
-
connection.connect_unix(config[:path], connect_timeout)
|
|
18
|
-
elsif config[:scheme] == "rediss" || config[:ssl]
|
|
19
|
-
raise NotImplementedError, "SSL not supported by hiredis driver"
|
|
20
|
-
else
|
|
21
|
-
connection.connect(config[:host], config[:port], connect_timeout)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
instance = new(connection)
|
|
25
|
-
instance.timeout = config[:read_timeout]
|
|
26
|
-
instance
|
|
27
|
-
rescue Errno::ETIMEDOUT
|
|
28
|
-
raise TimeoutError
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def initialize(connection)
|
|
32
|
-
@connection = connection
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def connected?
|
|
36
|
-
@connection&.connected?
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def timeout=(timeout)
|
|
40
|
-
# Hiredis works with microsecond timeouts
|
|
41
|
-
@connection.timeout = Integer(timeout * 1_000_000)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def disconnect
|
|
45
|
-
@connection.disconnect
|
|
46
|
-
@connection = nil
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def write(command)
|
|
50
|
-
@connection.write(command.flatten(1))
|
|
51
|
-
rescue Errno::EAGAIN
|
|
52
|
-
raise TimeoutError
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def read
|
|
56
|
-
reply = @connection.read
|
|
57
|
-
reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
|
|
58
|
-
reply
|
|
59
|
-
rescue Errno::EAGAIN
|
|
60
|
-
raise TimeoutError
|
|
61
|
-
rescue RuntimeError => err
|
|
62
|
-
raise ProtocolError, err.message
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
Redis::Connection.drivers << Redis::Connection::Hiredis
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Redis
|
|
4
|
-
module Connection
|
|
5
|
-
# Store a list of loaded connection drivers in the Connection module.
|
|
6
|
-
# Redis::Client uses the last required driver by default, and will be aware
|
|
7
|
-
# of the loaded connection drivers if the user chooses to override the
|
|
8
|
-
# default connection driver.
|
|
9
|
-
def self.drivers
|
|
10
|
-
@drivers ||= []
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|