redis 4.5.1 → 5.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +120 -0
  3. data/README.md +82 -153
  4. data/lib/redis/client.rb +77 -615
  5. data/lib/redis/commands/bitmaps.rb +66 -0
  6. data/lib/redis/commands/cluster.rb +28 -0
  7. data/lib/redis/commands/connection.rb +53 -0
  8. data/lib/redis/commands/geo.rb +84 -0
  9. data/lib/redis/commands/hashes.rb +254 -0
  10. data/lib/redis/commands/hyper_log_log.rb +37 -0
  11. data/lib/redis/commands/keys.rb +437 -0
  12. data/lib/redis/commands/lists.rb +285 -0
  13. data/lib/redis/commands/pubsub.rb +54 -0
  14. data/lib/redis/commands/scripting.rb +114 -0
  15. data/lib/redis/commands/server.rb +188 -0
  16. data/lib/redis/commands/sets.rb +214 -0
  17. data/lib/redis/commands/sorted_sets.rb +818 -0
  18. data/lib/redis/commands/streams.rb +402 -0
  19. data/lib/redis/commands/strings.rb +314 -0
  20. data/lib/redis/commands/transactions.rb +115 -0
  21. data/lib/redis/commands.rb +237 -0
  22. data/lib/redis/distributed.rb +140 -70
  23. data/lib/redis/errors.rb +15 -41
  24. data/lib/redis/hash_ring.rb +26 -26
  25. data/lib/redis/pipeline.rb +66 -120
  26. data/lib/redis/subscribe.rb +23 -15
  27. data/lib/redis/version.rb +1 -1
  28. data/lib/redis.rb +106 -3736
  29. metadata +26 -53
  30. data/lib/redis/cluster/command.rb +0 -81
  31. data/lib/redis/cluster/command_loader.rb +0 -33
  32. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  33. data/lib/redis/cluster/node.rb +0 -108
  34. data/lib/redis/cluster/node_key.rb +0 -31
  35. data/lib/redis/cluster/node_loader.rb +0 -37
  36. data/lib/redis/cluster/option.rb +0 -93
  37. data/lib/redis/cluster/slot.rb +0 -86
  38. data/lib/redis/cluster/slot_loader.rb +0 -49
  39. data/lib/redis/cluster.rb +0 -291
  40. data/lib/redis/connection/command_helper.rb +0 -41
  41. data/lib/redis/connection/hiredis.rb +0 -67
  42. data/lib/redis/connection/registry.rb +0 -13
  43. data/lib/redis/connection/ruby.rb +0 -428
  44. data/lib/redis/connection/synchrony.rb +0 -146
  45. 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.5.1
4
+ version: 5.0.6
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: 2021-10-15 00:00:00.000000000 Z
19
+ date: 2023-01-16 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: em-synchrony
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: :development
27
+ version: 0.9.0
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.9.0
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,22 +46,23 @@ 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
- - lib/redis/connection.rb
88
- - lib/redis/connection/command_helper.rb
89
- - lib/redis/connection/hiredis.rb
90
- - lib/redis/connection/registry.rb
91
- - lib/redis/connection/ruby.rb
92
- - lib/redis/connection/synchrony.rb
49
+ - lib/redis/commands.rb
50
+ - lib/redis/commands/bitmaps.rb
51
+ - lib/redis/commands/cluster.rb
52
+ - lib/redis/commands/connection.rb
53
+ - lib/redis/commands/geo.rb
54
+ - lib/redis/commands/hashes.rb
55
+ - lib/redis/commands/hyper_log_log.rb
56
+ - lib/redis/commands/keys.rb
57
+ - lib/redis/commands/lists.rb
58
+ - lib/redis/commands/pubsub.rb
59
+ - lib/redis/commands/scripting.rb
60
+ - lib/redis/commands/server.rb
61
+ - lib/redis/commands/sets.rb
62
+ - lib/redis/commands/sorted_sets.rb
63
+ - lib/redis/commands/streams.rb
64
+ - lib/redis/commands/strings.rb
65
+ - lib/redis/commands/transactions.rb
93
66
  - lib/redis/distributed.rb
94
67
  - lib/redis/errors.rb
95
68
  - lib/redis/hash_ring.rb
@@ -102,9 +75,9 @@ licenses:
102
75
  metadata:
103
76
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
104
77
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
105
- documentation_uri: https://www.rubydoc.info/gems/redis/4.5.1
78
+ documentation_uri: https://www.rubydoc.info/gems/redis/5.0.6
106
79
  homepage_uri: https://github.com/redis/redis-rb
107
- source_code_uri: https://github.com/redis/redis-rb/tree/v4.5.1
80
+ source_code_uri: https://github.com/redis/redis-rb/tree/v5.0.6
108
81
  post_install_message:
109
82
  rdoc_options: []
110
83
  require_paths:
@@ -113,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
113
86
  requirements:
114
87
  - - ">="
115
88
  - !ruby/object:Gem::Version
116
- version: 2.4.0
89
+ version: 2.5.0
117
90
  required_rubygems_version: !ruby/object:Gem::Requirement
118
91
  requirements:
119
92
  - - ">="
@@ -1,81 +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.map do |command, detail|
35
- [command, {
36
- first_key_position: detail[:first],
37
- write: detail[:flags].include?('write'),
38
- readonly: detail[:flags].include?('readonly')
39
- }]
40
- end.to_h
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 'scan', 'sscan', 'hscan', 'zscan'
57
- determine_optional_key_position(command, 'match')
58
- when 'xread', 'xreadgroup'
59
- determine_optional_key_position(command, 'streams')
60
- else
61
- dig_details(command, :first_key_position).to_i
62
- end
63
- end
64
-
65
- def determine_optional_key_position(command, option_name)
66
- idx = command.map(&:to_s).map(&:downcase).index(option_name)
67
- idx.nil? ? 0 : idx + 1
68
- end
69
-
70
- # @see https://redis.io/topics/cluster-spec#keys-hash-tags Keys hash tags
71
- def extract_hash_tag(key)
72
- s = key.index('{')
73
- e = key.index('}', s.to_i + 1)
74
-
75
- return '' if s.nil? || e.nil?
76
-
77
- key[s + 1..e - 1]
78
- end
79
- end
80
- end
81
- 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
@@ -1,108 +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
- private
62
-
63
- def replica_disabled?
64
- !@with_replica
65
- end
66
-
67
- def master?(node_key)
68
- !slave?(node_key)
69
- end
70
-
71
- def slave?(node_key)
72
- @node_flags[node_key] == ROLE_SLAVE
73
- end
74
-
75
- def build_clients(options)
76
- clients = options.map do |node_key, option|
77
- next if replica_disabled? && slave?(node_key)
78
-
79
- option = option.merge(readonly: true) if slave?(node_key)
80
-
81
- client = Client.new(option)
82
- [node_key, client]
83
- end
84
-
85
- clients.compact.to_h
86
- end
87
-
88
- def try_map
89
- errors = {}
90
- results = {}
91
-
92
- @clients.each do |node_key, client|
93
- begin
94
- reply = yield(node_key, client)
95
- results[node_key] = reply unless reply.nil?
96
- rescue CommandError => err
97
- errors[node_key] = err
98
- next
99
- end
100
- end
101
-
102
- return results if errors.empty?
103
-
104
- raise CommandErrorCollection, errors
105
- end
106
- end
107
- end
108
- 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,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../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
- info = {}
13
-
14
- nodes.each do |node|
15
- info = fetch_node_info(node)
16
- info.empty? ? next : break
17
- end
18
-
19
- return info unless info.empty?
20
-
21
- raise CannotConnectError, 'Redis client could not connect to any cluster nodes'
22
- end
23
-
24
- def fetch_node_info(node)
25
- node.call(%i[cluster nodes])
26
- .split("\n")
27
- .map { |str| str.split(' ') }
28
- .map { |arr| [arr[1].split('@').first, (arr[2].split(',') & %w[master slave]).first] }
29
- .to_h
30
- rescue CannotConnectError, ConnectionError, CommandError
31
- {} # can retry on another node
32
- end
33
-
34
- private_class_method :fetch_node_info
35
- end
36
- end
37
- end
@@ -1,93 +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
- add_common_node_option_if_needed(options, @node_opts, :scheme)
21
- add_common_node_option_if_needed(options, @node_opts, :username)
22
- add_common_node_option_if_needed(options, @node_opts, :password)
23
- @options = options
24
- end
25
-
26
- def per_node_key
27
- @node_opts.map { |opt| [NodeKey.build_from_host_port(opt[:host], opt[:port]), @options.merge(opt)] }
28
- .to_h
29
- end
30
-
31
- def use_replica?
32
- @replica
33
- end
34
-
35
- def update_node(addrs)
36
- @node_opts = build_node_options(addrs)
37
- end
38
-
39
- def add_node(host, port)
40
- @node_opts << { host: host, port: port }
41
- end
42
-
43
- private
44
-
45
- def build_node_options(addrs)
46
- raise InvalidClientOptionError, 'Redis option of `cluster` must be an Array' unless addrs.is_a?(Array)
47
-
48
- addrs.map { |addr| parse_node_addr(addr) }
49
- end
50
-
51
- def parse_node_addr(addr)
52
- case addr
53
- when String
54
- parse_node_url(addr)
55
- when Hash
56
- parse_node_option(addr)
57
- else
58
- raise InvalidClientOptionError, 'Redis option of `cluster` must includes String or Hash'
59
- end
60
- end
61
-
62
- def parse_node_url(addr)
63
- uri = URI(addr)
64
- raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
65
-
66
- db = uri.path.split('/')[1]&.to_i
67
-
68
- { scheme: uri.scheme, username: uri.user, password: uri.password, host: uri.host, port: uri.port, db: db }
69
- .reject { |_, v| v.nil? || v == '' }
70
- rescue URI::InvalidURIError => err
71
- raise InvalidClientOptionError, err.message
72
- end
73
-
74
- def parse_node_option(addr)
75
- addr = addr.map { |k, v| [k.to_sym, v] }.to_h
76
- if addr.values_at(:host, :port).any?(&:nil?)
77
- raise InvalidClientOptionError, 'Redis option of `cluster` must includes `:host` and `:port` keys'
78
- end
79
-
80
- addr
81
- end
82
-
83
- # Redis cluster node returns only host and port information.
84
- # So we should complement additional information such as:
85
- # scheme, username, password and so on.
86
- def add_common_node_option_if_needed(options, node_opts, key)
87
- return options if options[key].nil? && node_opts.first[key].nil?
88
-
89
- options[key] ||= node_opts.first[key]
90
- end
91
- end
92
- end
93
- end
@@ -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