redis 4.8.0 → 5.0.8
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 +64 -1
 - data/README.md +101 -161
 - data/lib/redis/client.rb +82 -625
 - data/lib/redis/commands/bitmaps.rb +4 -1
 - data/lib/redis/commands/cluster.rb +1 -18
 - data/lib/redis/commands/connection.rb +5 -10
 - data/lib/redis/commands/geo.rb +3 -3
 - data/lib/redis/commands/hashes.rb +9 -6
 - data/lib/redis/commands/hyper_log_log.rb +1 -1
 - data/lib/redis/commands/keys.rb +5 -23
 - data/lib/redis/commands/lists.rb +74 -25
 - data/lib/redis/commands/pubsub.rb +28 -25
 - data/lib/redis/commands/server.rb +15 -15
 - data/lib/redis/commands/sets.rb +31 -40
 - data/lib/redis/commands/sorted_sets.rb +84 -12
 - data/lib/redis/commands/streams.rb +39 -19
 - data/lib/redis/commands/strings.rb +18 -17
 - data/lib/redis/commands/transactions.rb +7 -31
 - data/lib/redis/commands.rb +4 -7
 - data/lib/redis/distributed.rb +114 -64
 - data/lib/redis/errors.rb +15 -50
 - data/lib/redis/hash_ring.rb +26 -26
 - data/lib/redis/pipeline.rb +43 -222
 - data/lib/redis/subscribe.rb +50 -14
 - data/lib/redis/version.rb +1 -1
 - data/lib/redis.rb +76 -184
 - metadata +10 -54
 - 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/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
         
     | 
    
        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
         
     |