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
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: 6.0.0
|
|
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: 2026-07-31 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.30.1
|
|
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.30.1
|
|
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
|
|
@@ -93,6 +54,18 @@ files:
|
|
|
93
54
|
- lib/redis/commands/hyper_log_log.rb
|
|
94
55
|
- lib/redis/commands/keys.rb
|
|
95
56
|
- lib/redis/commands/lists.rb
|
|
57
|
+
- lib/redis/commands/modules/json.rb
|
|
58
|
+
- lib/redis/commands/modules/search.rb
|
|
59
|
+
- lib/redis/commands/modules/search/aggregation.rb
|
|
60
|
+
- lib/redis/commands/modules/search/dialect.rb
|
|
61
|
+
- lib/redis/commands/modules/search/field.rb
|
|
62
|
+
- lib/redis/commands/modules/search/hybrid.rb
|
|
63
|
+
- lib/redis/commands/modules/search/index.rb
|
|
64
|
+
- lib/redis/commands/modules/search/index_definition.rb
|
|
65
|
+
- lib/redis/commands/modules/search/miscellaneous.rb
|
|
66
|
+
- lib/redis/commands/modules/search/query.rb
|
|
67
|
+
- lib/redis/commands/modules/search/result.rb
|
|
68
|
+
- lib/redis/commands/modules/search/schema.rb
|
|
96
69
|
- lib/redis/commands/pubsub.rb
|
|
97
70
|
- lib/redis/commands/scripting.rb
|
|
98
71
|
- lib/redis/commands/server.rb
|
|
@@ -101,15 +74,10 @@ files:
|
|
|
101
74
|
- lib/redis/commands/streams.rb
|
|
102
75
|
- lib/redis/commands/strings.rb
|
|
103
76
|
- 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
77
|
- lib/redis/distributed.rb
|
|
111
78
|
- lib/redis/errors.rb
|
|
112
79
|
- lib/redis/hash_ring.rb
|
|
80
|
+
- lib/redis/lib_identity.rb
|
|
113
81
|
- lib/redis/pipeline.rb
|
|
114
82
|
- lib/redis/subscribe.rb
|
|
115
83
|
- lib/redis/version.rb
|
|
@@ -119,10 +87,9 @@ licenses:
|
|
|
119
87
|
metadata:
|
|
120
88
|
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
|
121
89
|
changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
|
|
122
|
-
documentation_uri: https://www.rubydoc.info/gems/redis/
|
|
90
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/6.0.0
|
|
123
91
|
homepage_uri: https://github.com/redis/redis-rb
|
|
124
|
-
source_code_uri: https://github.com/redis/redis-rb/tree/
|
|
125
|
-
post_install_message:
|
|
92
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v6.0.0
|
|
126
93
|
rdoc_options: []
|
|
127
94
|
require_paths:
|
|
128
95
|
- lib
|
|
@@ -130,15 +97,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
130
97
|
requirements:
|
|
131
98
|
- - ">="
|
|
132
99
|
- !ruby/object:Gem::Version
|
|
133
|
-
version: 2.
|
|
100
|
+
version: 3.2.0
|
|
134
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
102
|
requirements:
|
|
136
103
|
- - ">="
|
|
137
104
|
- !ruby/object:Gem::Version
|
|
138
105
|
version: '0'
|
|
139
106
|
requirements: []
|
|
140
|
-
rubygems_version: 3.
|
|
141
|
-
signing_key:
|
|
107
|
+
rubygems_version: 3.6.2
|
|
142
108
|
specification_version: 4
|
|
143
109
|
summary: A Ruby client library for Redis
|
|
144
110
|
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
|
data/lib/redis/cluster/node.rb
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../errors'
|
|
4
|
-
|
|
5
|
-
class Redis
|
|
6
|
-
class Cluster
|
|
7
|
-
# Keep client list of node for Redis Cluster Client
|
|
8
|
-
class Node
|
|
9
|
-
include Enumerable
|
|
10
|
-
|
|
11
|
-
ReloadNeeded = Class.new(StandardError)
|
|
12
|
-
|
|
13
|
-
ROLE_SLAVE = 'slave'
|
|
14
|
-
|
|
15
|
-
def initialize(options, node_flags = {}, with_replica = false)
|
|
16
|
-
@with_replica = with_replica
|
|
17
|
-
@node_flags = node_flags
|
|
18
|
-
@clients = build_clients(options)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def each(&block)
|
|
22
|
-
@clients.values.each(&block)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def sample
|
|
26
|
-
@clients.values.sample
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def find_by(node_key)
|
|
30
|
-
@clients.fetch(node_key)
|
|
31
|
-
rescue KeyError
|
|
32
|
-
raise ReloadNeeded
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def call_all(command, &block)
|
|
36
|
-
try_map { |_, client| client.call(command, &block) }.values
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def call_master(command, &block)
|
|
40
|
-
try_map do |node_key, client|
|
|
41
|
-
next if slave?(node_key)
|
|
42
|
-
|
|
43
|
-
client.call(command, &block)
|
|
44
|
-
end.values
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def call_slave(command, &block)
|
|
48
|
-
return call_master(command, &block) if replica_disabled?
|
|
49
|
-
|
|
50
|
-
try_map do |node_key, client|
|
|
51
|
-
next if master?(node_key)
|
|
52
|
-
|
|
53
|
-
client.call(command, &block)
|
|
54
|
-
end.values
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def process_all(commands, &block)
|
|
58
|
-
try_map { |_, client| client.process(commands, &block) }.values
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def scale_reading_clients
|
|
62
|
-
reading_clients = []
|
|
63
|
-
|
|
64
|
-
@clients.each do |node_key, client|
|
|
65
|
-
next unless replica_disabled? ? master?(node_key) : slave?(node_key)
|
|
66
|
-
|
|
67
|
-
reading_clients << client
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
reading_clients
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
def replica_disabled?
|
|
76
|
-
!@with_replica
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def master?(node_key)
|
|
80
|
-
!slave?(node_key)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def slave?(node_key)
|
|
84
|
-
@node_flags[node_key] == ROLE_SLAVE
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def build_clients(options)
|
|
88
|
-
clients = options.map do |node_key, option|
|
|
89
|
-
next if replica_disabled? && slave?(node_key)
|
|
90
|
-
|
|
91
|
-
option = option.merge(readonly: true) if slave?(node_key)
|
|
92
|
-
|
|
93
|
-
client = Client.new(option)
|
|
94
|
-
[node_key, client]
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
clients.compact.to_h
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def try_map
|
|
101
|
-
errors = {}
|
|
102
|
-
results = {}
|
|
103
|
-
|
|
104
|
-
@clients.each do |node_key, client|
|
|
105
|
-
begin
|
|
106
|
-
reply = yield(node_key, client)
|
|
107
|
-
results[node_key] = reply unless reply.nil?
|
|
108
|
-
rescue CommandError => err
|
|
109
|
-
errors[node_key] = err
|
|
110
|
-
next
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
return results if errors.empty?
|
|
115
|
-
|
|
116
|
-
raise CommandErrorCollection, errors
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Redis
|
|
4
|
-
class Cluster
|
|
5
|
-
# Node key's format is `<ip>:<port>`.
|
|
6
|
-
# It is different from node id.
|
|
7
|
-
# Node id is internal identifying code in Redis Cluster.
|
|
8
|
-
module NodeKey
|
|
9
|
-
DELIMITER = ':'
|
|
10
|
-
|
|
11
|
-
module_function
|
|
12
|
-
|
|
13
|
-
def optionize(node_key)
|
|
14
|
-
host, port = split(node_key)
|
|
15
|
-
{ host: host, port: port }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def split(node_key)
|
|
19
|
-
node_key.split(DELIMITER)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def build_from_uri(uri)
|
|
23
|
-
"#{uri.host}#{DELIMITER}#{uri.port}"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def build_from_host_port(host, port)
|
|
27
|
-
"#{host}#{DELIMITER}#{port}"
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'redis/errors'
|
|
4
|
-
|
|
5
|
-
class Redis
|
|
6
|
-
class Cluster
|
|
7
|
-
# Load and hashify node info for Redis Cluster Client
|
|
8
|
-
module NodeLoader
|
|
9
|
-
module_function
|
|
10
|
-
|
|
11
|
-
def load_flags(nodes)
|
|
12
|
-
errors = nodes.map do |node|
|
|
13
|
-
begin
|
|
14
|
-
return fetch_node_info(node)
|
|
15
|
-
rescue CannotConnectError, ConnectionError, CommandError => error
|
|
16
|
-
error
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
raise InitialSetupError, errors
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def fetch_node_info(node)
|
|
24
|
-
node.call(%i[cluster nodes])
|
|
25
|
-
.split("\n")
|
|
26
|
-
.map { |str| str.split(' ') }
|
|
27
|
-
.map { |arr| [arr[1].split('@').first, (arr[2].split(',') & %w[master slave]).first] }
|
|
28
|
-
.to_h
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private_class_method :fetch_node_info
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
data/lib/redis/cluster/option.rb
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../errors'
|
|
4
|
-
require_relative 'node_key'
|
|
5
|
-
require 'uri'
|
|
6
|
-
|
|
7
|
-
class Redis
|
|
8
|
-
class Cluster
|
|
9
|
-
# Keep options for Redis Cluster Client
|
|
10
|
-
class Option
|
|
11
|
-
DEFAULT_SCHEME = 'redis'
|
|
12
|
-
SECURE_SCHEME = 'rediss'
|
|
13
|
-
VALID_SCHEMES = [DEFAULT_SCHEME, SECURE_SCHEME].freeze
|
|
14
|
-
|
|
15
|
-
def initialize(options)
|
|
16
|
-
options = options.dup
|
|
17
|
-
node_addrs = options.delete(:cluster)
|
|
18
|
-
@node_opts = build_node_options(node_addrs)
|
|
19
|
-
@replica = options.delete(:replica) == true
|
|
20
|
-
@fixed_hostname = options.delete(:fixed_hostname)
|
|
21
|
-
add_common_node_option_if_needed(options, @node_opts, :scheme)
|
|
22
|
-
add_common_node_option_if_needed(options, @node_opts, :username)
|
|
23
|
-
add_common_node_option_if_needed(options, @node_opts, :password)
|
|
24
|
-
@options = options
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def per_node_key
|
|
28
|
-
@node_opts.map do |opt|
|
|
29
|
-
node_key = NodeKey.build_from_host_port(opt[:host], opt[:port])
|
|
30
|
-
options = @options.merge(opt)
|
|
31
|
-
options = options.merge(host: @fixed_hostname) if @fixed_hostname && !@fixed_hostname.empty?
|
|
32
|
-
[node_key, options]
|
|
33
|
-
end.to_h
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def use_replica?
|
|
37
|
-
@replica
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def update_node(addrs)
|
|
41
|
-
@node_opts = build_node_options(addrs)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def add_node(host, port)
|
|
45
|
-
@node_opts << { host: host, port: port }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def build_node_options(addrs)
|
|
51
|
-
raise InvalidClientOptionError, 'Redis option of `cluster` must be an Array' unless addrs.is_a?(Array)
|
|
52
|
-
|
|
53
|
-
addrs.map { |addr| parse_node_addr(addr) }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def parse_node_addr(addr)
|
|
57
|
-
case addr
|
|
58
|
-
when String
|
|
59
|
-
parse_node_url(addr)
|
|
60
|
-
when Hash
|
|
61
|
-
parse_node_option(addr)
|
|
62
|
-
else
|
|
63
|
-
raise InvalidClientOptionError, 'Redis option of `cluster` must includes String or Hash'
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def parse_node_url(addr)
|
|
68
|
-
uri = URI(addr)
|
|
69
|
-
raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
|
|
70
|
-
|
|
71
|
-
db = uri.path.split('/')[1]&.to_i
|
|
72
|
-
username = uri.user ? URI.decode_www_form_component(uri.user) : nil
|
|
73
|
-
password = uri.password ? URI.decode_www_form_component(uri.password) : nil
|
|
74
|
-
|
|
75
|
-
{ scheme: uri.scheme, username: username, password: password, host: uri.host, port: uri.port, db: db }
|
|
76
|
-
.reject { |_, v| v.nil? || v == '' }
|
|
77
|
-
rescue URI::InvalidURIError => err
|
|
78
|
-
raise InvalidClientOptionError, err.message
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def parse_node_option(addr)
|
|
82
|
-
addr = addr.map { |k, v| [k.to_sym, v] }.to_h
|
|
83
|
-
if addr.values_at(:host, :port).any?(&:nil?)
|
|
84
|
-
raise InvalidClientOptionError, 'Redis option of `cluster` must includes `:host` and `:port` keys'
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
addr
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Redis cluster node returns only host and port information.
|
|
91
|
-
# So we should complement additional information such as:
|
|
92
|
-
# scheme, username, password and so on.
|
|
93
|
-
def add_common_node_option_if_needed(options, node_opts, key)
|
|
94
|
-
return options if options[key].nil? && node_opts.first[key].nil?
|
|
95
|
-
|
|
96
|
-
options[key] ||= node_opts.first[key]
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|