redis 4.2.1 → 4.3.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 +25 -0
- data/README.md +17 -11
- data/lib/redis.rb +30 -17
- data/lib/redis/client.rb +16 -4
- data/lib/redis/cluster.rb +1 -1
- data/lib/redis/cluster/option.rb +5 -2
- data/lib/redis/connection/ruby.rb +53 -48
- data/lib/redis/distributed.rb +37 -8
- data/lib/redis/version.rb +1 -1
- metadata +8 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5d173abb7a6c08e1feb87c9fd5ba33a2a0d907c6d045f6959d55f3234e56ceeb
         | 
| 4 | 
            +
              data.tar.gz: 7463d58522a3db5262eeea4b95834d82ede95cf102d2375e051cf4ada1b235c3
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0b34ab14e41e1bd63a99319f3ee5e1e7ea0c1e89581e525dfd82b77968a834525807b025f02d8ff5df4e7a994f19cc7ee4098103c70abd78ab6c22ec435a055c
         | 
| 7 | 
            +
              data.tar.gz: 84da776467bebb7fd59333084787e484203e55b81be5031c78b44741f2b79342cc1f6f48c1f9663b15f360a3af590783ee2f403da07a3e04486e35ba70e49e01
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,29 @@ | |
| 1 1 | 
             
            # Unreleased
         | 
| 2 2 |  | 
| 3 | 
            +
            # 4.3.0
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Add the TYPE argument to scan and scan_each. See #985.
         | 
| 6 | 
            +
            * Support AUTH command for ACL. See #967.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # 4.2.5
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            * Optimize the ruby connector write buffering. See #964.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # 4.2.4
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            * Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            # 4.2.3
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            * Use io/wait instead of IO.select in the ruby connector. See #960.
         | 
| 19 | 
            +
            * Use exception free non blocking IOs in the ruby connector. See #926.
         | 
| 20 | 
            +
            * Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # 4.2.2
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            * Fix `WATCH` support for `Redis::Distributed`. See #941.
         | 
| 25 | 
            +
            * Fix handling of empty stream responses. See #905, #929.
         | 
| 26 | 
            +
             | 
| 3 27 | 
             
            # 4.2.1
         | 
| 4 28 |  | 
| 5 29 | 
             
            * Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
         | 
| @@ -17,6 +41,7 @@ | |
| 17 41 | 
             
            * Optimized initialization of Redis::Cluster. See #912.
         | 
| 18 42 | 
             
            * Accept sentinel options even with string key. See #599.
         | 
| 19 43 | 
             
            * Verify TLS connections by default. See #900.
         | 
| 44 | 
            +
            * Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
         | 
| 20 45 |  | 
| 21 46 | 
             
            # 4.1.4
         | 
| 22 47 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # redis-rb [![Build Status][ | 
| 1 | 
            +
            # redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
         | 
| 2 2 |  | 
| 3 3 | 
             
            A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
         | 
| 4 4 | 
             
            providing an idiomatic interface.
         | 
| @@ -54,6 +54,12 @@ To connect to a password protected Redis instance, use: | |
| 54 54 | 
             
            redis = Redis.new(password: "mysecret")
         | 
| 55 55 | 
             
            ```
         | 
| 56 56 |  | 
| 57 | 
            +
            To connect a Redis instance using [ACL](https://redis.io/topics/acl), use:
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            ```ruby
         | 
| 60 | 
            +
            redis = Redis.new(username: 'myname', password: 'mysecret')
         | 
| 61 | 
            +
            ```
         | 
| 62 | 
            +
             | 
| 57 63 | 
             
            The Redis class exports methods that are named identical to the commands
         | 
| 58 64 | 
             
            they execute. The arguments these methods accept are often identical to
         | 
| 59 65 | 
             
            the arguments specified on the [Redis website][redis-commands]. For
         | 
| @@ -265,6 +271,7 @@ All timeout values are specified in seconds. | |
| 265 271 | 
             
            When using pub/sub, you can subscribe to a channel using a timeout as well:
         | 
| 266 272 |  | 
| 267 273 | 
             
            ```ruby
         | 
| 274 | 
            +
            redis = Redis.new(reconnect_attempts: 0)
         | 
| 268 275 | 
             
            redis.subscribe_with_timeout(5, "news") do |on|
         | 
| 269 276 | 
             
              on.message do |channel, message|
         | 
| 270 277 | 
             
                # ...
         | 
| @@ -439,7 +446,7 @@ redis = Redis.new(:driver => :synchrony) | |
| 439 446 | 
             
            ## Testing
         | 
| 440 447 |  | 
| 441 448 | 
             
            This library is tested against recent Ruby and Redis versions.
         | 
| 442 | 
            -
            Check [ | 
| 449 | 
            +
            Check [Github Actions][gh-actions-link] for the exact versions supported.
         | 
| 443 450 |  | 
| 444 451 | 
             
            ## See Also
         | 
| 445 452 |  | 
| @@ -458,12 +465,11 @@ client and evangelized Redis in Rubyland. Thank you, Ezra. | |
| 458 465 | 
             
            requests.
         | 
| 459 466 |  | 
| 460 467 |  | 
| 461 | 
            -
            [inchpages-image]: | 
| 462 | 
            -
            [inchpages-link]: | 
| 463 | 
            -
            [redis-commands]: | 
| 464 | 
            -
            [redis-home]: | 
| 465 | 
            -
            [redis-url]: | 
| 466 | 
            -
            [ | 
| 467 | 
            -
            [ | 
| 468 | 
            -
            [ | 
| 469 | 
            -
            [rubydoc]:         http://www.rubydoc.info/gems/redis
         | 
| 468 | 
            +
            [inchpages-image]:  https://inch-ci.org/github/redis/redis-rb.svg
         | 
| 469 | 
            +
            [inchpages-link]:   https://inch-ci.org/github/redis/redis-rb
         | 
| 470 | 
            +
            [redis-commands]:   https://redis.io/commands
         | 
| 471 | 
            +
            [redis-home]:       https://redis.io
         | 
| 472 | 
            +
            [redis-url]:        http://www.iana.org/assignments/uri-schemes/prov/redis
         | 
| 473 | 
            +
            [gh-actions-image]: https://github.com/redis/redis-rb/workflows/Test/badge.svg
         | 
| 474 | 
            +
            [gh-actions-link]:  https://github.com/redis/redis-rb/actions
         | 
| 475 | 
            +
            [rubydoc]:          http://www.rubydoc.info/gems/redis
         | 
    
        data/lib/redis.rb
    CHANGED
    
    | @@ -39,6 +39,7 @@ class Redis | |
| 39 39 | 
             
              # @option options [String] :path path to server socket (overrides host and port)
         | 
| 40 40 | 
             
              # @option options [Float] :timeout (5.0) timeout in seconds
         | 
| 41 41 | 
             
              # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
         | 
| 42 | 
            +
              # @option options [String] :username Username to authenticate against server
         | 
| 42 43 | 
             
              # @option options [String] :password Password to authenticate against server
         | 
| 43 44 | 
             
              # @option options [Integer] :db (0) Database to select after initial connect
         | 
| 44 45 | 
             
              # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
         | 
| @@ -143,12 +144,13 @@ class Redis | |
| 143 144 |  | 
| 144 145 | 
             
              # Authenticate to the server.
         | 
| 145 146 | 
             
              #
         | 
| 146 | 
            -
              # @param [String]  | 
| 147 | 
            -
              #    | 
| 147 | 
            +
              # @param [Array<String>] args includes both username and password
         | 
| 148 | 
            +
              #   or only password
         | 
| 148 149 | 
             
              # @return [String] `OK`
         | 
| 149 | 
            -
               | 
| 150 | 
            +
              # @see https://redis.io/commands/auth AUTH command
         | 
| 151 | 
            +
              def auth(*args)
         | 
| 150 152 | 
             
                synchronize do |client|
         | 
| 151 | 
            -
                  client.call([:auth,  | 
| 153 | 
            +
                  client.call([:auth, *args])
         | 
| 152 154 | 
             
                end
         | 
| 153 155 | 
             
              end
         | 
| 154 156 |  | 
| @@ -2438,14 +2440,13 @@ class Redis | |
| 2438 2440 | 
             
              end
         | 
| 2439 2441 |  | 
| 2440 2442 | 
             
              def pipelined
         | 
| 2441 | 
            -
                synchronize do | | 
| 2443 | 
            +
                synchronize do |prior_client|
         | 
| 2442 2444 | 
             
                  begin
         | 
| 2443 | 
            -
                     | 
| 2444 | 
            -
                    original, @client = @client, pipeline
         | 
| 2445 | 
            +
                    @client = Pipeline.new(prior_client)
         | 
| 2445 2446 | 
             
                    yield(self)
         | 
| 2446 | 
            -
                     | 
| 2447 | 
            +
                    prior_client.call_pipeline(@client)
         | 
| 2447 2448 | 
             
                  ensure
         | 
| 2448 | 
            -
                    @client =  | 
| 2449 | 
            +
                    @client = prior_client
         | 
| 2449 2450 | 
             
                  end
         | 
| 2450 2451 | 
             
                end
         | 
| 2451 2452 | 
             
              end
         | 
| @@ -2481,17 +2482,16 @@ class Redis | |
| 2481 2482 | 
             
              # @see #watch
         | 
| 2482 2483 | 
             
              # @see #unwatch
         | 
| 2483 2484 | 
             
              def multi
         | 
| 2484 | 
            -
                synchronize do | | 
| 2485 | 
            +
                synchronize do |prior_client|
         | 
| 2485 2486 | 
             
                  if !block_given?
         | 
| 2486 | 
            -
                     | 
| 2487 | 
            +
                    prior_client.call([:multi])
         | 
| 2487 2488 | 
             
                  else
         | 
| 2488 2489 | 
             
                    begin
         | 
| 2489 | 
            -
                       | 
| 2490 | 
            -
                      original, @client = @client, pipeline
         | 
| 2490 | 
            +
                      @client = Pipeline::Multi.new(prior_client)
         | 
| 2491 2491 | 
             
                      yield(self)
         | 
| 2492 | 
            -
                       | 
| 2492 | 
            +
                      prior_client.call_pipeline(@client)
         | 
| 2493 2493 | 
             
                    ensure
         | 
| 2494 | 
            -
                      @client =  | 
| 2494 | 
            +
                      @client = prior_client
         | 
| 2495 2495 | 
             
                    end
         | 
| 2496 2496 | 
             
                  end
         | 
| 2497 2497 | 
             
                end
         | 
| @@ -2638,12 +2638,13 @@ class Redis | |
| 2638 2638 | 
             
                _eval(:evalsha, args)
         | 
| 2639 2639 | 
             
              end
         | 
| 2640 2640 |  | 
| 2641 | 
            -
              def _scan(command, cursor, args, match: nil, count: nil, &block)
         | 
| 2641 | 
            +
              def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
         | 
| 2642 2642 | 
             
                # SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
         | 
| 2643 2643 |  | 
| 2644 2644 | 
             
                args << cursor
         | 
| 2645 2645 | 
             
                args << "MATCH" << match if match
         | 
| 2646 2646 | 
             
                args << "COUNT" << count if count
         | 
| 2647 | 
            +
                args << "TYPE" << type if type
         | 
| 2647 2648 |  | 
| 2648 2649 | 
             
                synchronize do |client|
         | 
| 2649 2650 | 
             
                  client.call([command] + args, &block)
         | 
| @@ -2658,11 +2659,15 @@ class Redis | |
| 2658 2659 | 
             
              # @example Retrieve a batch of keys matching a pattern
         | 
| 2659 2660 | 
             
              #   redis.scan(4, :match => "key:1?")
         | 
| 2660 2661 | 
             
              #     # => ["92", ["key:13", "key:18"]]
         | 
| 2662 | 
            +
              # @example Retrieve a batch of keys of a certain type
         | 
| 2663 | 
            +
              #   redis.scan(92, :type => "zset")
         | 
| 2664 | 
            +
              #     # => ["173", ["sortedset:14", "sortedset:78"]]
         | 
| 2661 2665 | 
             
              #
         | 
| 2662 2666 | 
             
              # @param [String, Integer] cursor the cursor of the iteration
         | 
| 2663 2667 | 
             
              # @param [Hash] options
         | 
| 2664 2668 | 
             
              #   - `:match => String`: only return keys matching the pattern
         | 
| 2665 2669 | 
             
              #   - `:count => Integer`: return count keys at most per iteration
         | 
| 2670 | 
            +
              #   - `:type => String`: return keys only of the given type
         | 
| 2666 2671 | 
             
              #
         | 
| 2667 2672 | 
             
              # @return [String, Array<String>] the next cursor and all found keys
         | 
| 2668 2673 | 
             
              def scan(cursor, **options)
         | 
| @@ -2678,10 +2683,15 @@ class Redis | |
| 2678 2683 | 
             
              #   redis.scan_each(:match => "key:1?") {|key| puts key}
         | 
| 2679 2684 | 
             
              #     # => key:13
         | 
| 2680 2685 | 
             
              #     # => key:18
         | 
| 2686 | 
            +
              # @example Execute block for each key of a type
         | 
| 2687 | 
            +
              #   redis.scan_each(:type => "hash") {|key| puts redis.type(key)}
         | 
| 2688 | 
            +
              #     # => "hash"
         | 
| 2689 | 
            +
              #     # => "hash"
         | 
| 2681 2690 | 
             
              #
         | 
| 2682 2691 | 
             
              # @param [Hash] options
         | 
| 2683 2692 | 
             
              #   - `:match => String`: only return keys matching the pattern
         | 
| 2684 2693 | 
             
              #   - `:count => Integer`: return count keys at most per iteration
         | 
| 2694 | 
            +
              #   - `:type => String`: return keys only of the given type
         | 
| 2685 2695 | 
             
              #
         | 
| 2686 2696 | 
             
              # @return [Enumerator] an enumerator for all found keys
         | 
| 2687 2697 | 
             
              def scan_each(**options, &block)
         | 
| @@ -3423,8 +3433,11 @@ class Redis | |
| 3423 3433 | 
             
                end
         | 
| 3424 3434 | 
             
              }
         | 
| 3425 3435 |  | 
| 3436 | 
            +
              EMPTY_STREAM_RESPONSE = [nil].freeze
         | 
| 3437 | 
            +
              private_constant :EMPTY_STREAM_RESPONSE
         | 
| 3438 | 
            +
             | 
| 3426 3439 | 
             
              HashifyStreamEntries = lambda { |reply|
         | 
| 3427 | 
            -
                reply.map do |entry_id, values|
         | 
| 3440 | 
            +
                reply.compact.map do |entry_id, values|
         | 
| 3428 3441 | 
             
                  [entry_id, values.each_slice(2).to_h]
         | 
| 3429 3442 | 
             
                end
         | 
| 3430 3443 | 
             
              }
         | 
    
        data/lib/redis/client.rb
    CHANGED
    
    | @@ -6,13 +6,18 @@ require "cgi" | |
| 6 6 |  | 
| 7 7 | 
             
            class Redis
         | 
| 8 8 | 
             
              class Client
         | 
| 9 | 
            +
                # Defaults are also used for converting string keys to symbols.
         | 
| 9 10 | 
             
                DEFAULTS = {
         | 
| 10 11 | 
             
                  url: -> { ENV["REDIS_URL"] },
         | 
| 11 12 | 
             
                  scheme: "redis",
         | 
| 12 13 | 
             
                  host: "127.0.0.1",
         | 
| 13 14 | 
             
                  port: 6379,
         | 
| 14 15 | 
             
                  path: nil,
         | 
| 16 | 
            +
                  read_timeout: nil,
         | 
| 17 | 
            +
                  write_timeout: nil,
         | 
| 18 | 
            +
                  connect_timeout: nil,
         | 
| 15 19 | 
             
                  timeout: 5.0,
         | 
| 20 | 
            +
                  username: nil,
         | 
| 16 21 | 
             
                  password: nil,
         | 
| 17 22 | 
             
                  db: 0,
         | 
| 18 23 | 
             
                  driver: nil,
         | 
| @@ -22,6 +27,7 @@ class Redis | |
| 22 27 | 
             
                  reconnect_delay: 0,
         | 
| 23 28 | 
             
                  reconnect_delay_max: 0.5,
         | 
| 24 29 | 
             
                  inherit_socket: false,
         | 
| 30 | 
            +
                  logger: nil,
         | 
| 25 31 | 
             
                  sentinels: nil,
         | 
| 26 32 | 
             
                  role: nil
         | 
| 27 33 | 
             
                }.freeze
         | 
| @@ -56,6 +62,10 @@ class Redis | |
| 56 62 | 
             
                  @options[:read_timeout]
         | 
| 57 63 | 
             
                end
         | 
| 58 64 |  | 
| 65 | 
            +
                def username
         | 
| 66 | 
            +
                  @options[:username]
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 59 69 | 
             
                def password
         | 
| 60 70 | 
             
                  @options[:password]
         | 
| 61 71 | 
             
                end
         | 
| @@ -105,7 +115,7 @@ class Redis | |
| 105 115 | 
             
                  # Don't try to reconnect when the connection is fresh
         | 
| 106 116 | 
             
                  with_reconnect(false) do
         | 
| 107 117 | 
             
                    establish_connection
         | 
| 108 | 
            -
                    call [:auth, password] if password
         | 
| 118 | 
            +
                    call [:auth, username, password].compact if username || password
         | 
| 109 119 | 
             
                    call [:select, db] if db != 0
         | 
| 110 120 | 
             
                    call [:client, :setname, @options[:id]] if @options[:id]
         | 
| 111 121 | 
             
                    @connector.check(self)
         | 
| @@ -126,7 +136,7 @@ class Redis | |
| 126 136 | 
             
                  reply = process([command]) { read }
         | 
| 127 137 | 
             
                  raise reply if reply.is_a?(CommandError)
         | 
| 128 138 |  | 
| 129 | 
            -
                  if block_given?
         | 
| 139 | 
            +
                  if block_given? && reply != 'QUEUED'
         | 
| 130 140 | 
             
                    yield reply
         | 
| 131 141 | 
             
                  else
         | 
| 132 142 | 
             
                    reply
         | 
| @@ -429,7 +439,8 @@ class Redis | |
| 429 439 | 
             
                      defaults[:scheme]   = uri.scheme
         | 
| 430 440 | 
             
                      defaults[:host]     = uri.host if uri.host
         | 
| 431 441 | 
             
                      defaults[:port]     = uri.port if uri.port
         | 
| 432 | 
            -
                      defaults[: | 
| 442 | 
            +
                      defaults[:username] = CGI.unescape(uri.user) if uri.user && !uri.user.empty?
         | 
| 443 | 
            +
                      defaults[:password] = CGI.unescape(uri.password) if uri.password && !uri.password.empty?
         | 
| 433 444 | 
             
                      defaults[:db]       = uri.path[1..-1].to_i if uri.path
         | 
| 434 445 | 
             
                      defaults[:role] = :master
         | 
| 435 446 | 
             
                    else
         | 
| @@ -505,7 +516,7 @@ class Redis | |
| 505 516 | 
             
                      require_relative "connection/#{driver}"
         | 
| 506 517 | 
             
                    rescue LoadError, NameError
         | 
| 507 518 | 
             
                      begin
         | 
| 508 | 
            -
                        require "connection/#{driver}"
         | 
| 519 | 
            +
                        require "redis/connection/#{driver}"
         | 
| 509 520 | 
             
                      rescue LoadError, NameError => error
         | 
| 510 521 | 
             
                        raise "Cannot load driver #{driver.inspect}: #{error.message}"
         | 
| 511 522 | 
             
                      end
         | 
| @@ -574,6 +585,7 @@ class Redis | |
| 574 585 | 
             
                        client = Client.new(@options.merge({
         | 
| 575 586 | 
             
                                                             host: sentinel[:host] || sentinel["host"],
         | 
| 576 587 | 
             
                                                             port: sentinel[:port] || sentinel["port"],
         | 
| 588 | 
            +
                                                             username: sentinel[:username] || sentinel["username"],
         | 
| 577 589 | 
             
                                                             password: sentinel[:password] || sentinel["password"],
         | 
| 578 590 | 
             
                                                             reconnect_attempts: 0
         | 
| 579 591 | 
             
                                                           }))
         | 
    
        data/lib/redis/cluster.rb
    CHANGED
    
    | @@ -128,7 +128,7 @@ class Redis | |
| 128 128 | 
             
                def send_command(command, &block)
         | 
| 129 129 | 
             
                  cmd = command.first.to_s.downcase
         | 
| 130 130 | 
             
                  case cmd
         | 
| 131 | 
            -
                  when 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
         | 
| 131 | 
            +
                  when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
         | 
| 132 132 | 
             
                    @node.call_all(command, &block).first
         | 
| 133 133 | 
             
                  when 'flushall', 'flushdb'
         | 
| 134 134 | 
             
                    @node.call_master(command, &block).first
         | 
    
        data/lib/redis/cluster/option.rb
    CHANGED
    
    | @@ -18,6 +18,7 @@ class Redis | |
| 18 18 | 
             
                    @node_opts = build_node_options(node_addrs)
         | 
| 19 19 | 
             
                    @replica = options.delete(:replica) == true
         | 
| 20 20 | 
             
                    add_common_node_option_if_needed(options, @node_opts, :scheme)
         | 
| 21 | 
            +
                    add_common_node_option_if_needed(options, @node_opts, :username)
         | 
| 21 22 | 
             
                    add_common_node_option_if_needed(options, @node_opts, :password)
         | 
| 22 23 | 
             
                    @options = options
         | 
| 23 24 | 
             
                  end
         | 
| @@ -63,7 +64,9 @@ class Redis | |
| 63 64 | 
             
                    raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
         | 
| 64 65 |  | 
| 65 66 | 
             
                    db = uri.path.split('/')[1]&.to_i
         | 
| 66 | 
            -
             | 
| 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 == '' }
         | 
| 67 70 | 
             
                  rescue URI::InvalidURIError => err
         | 
| 68 71 | 
             
                    raise InvalidClientOptionError, err.message
         | 
| 69 72 | 
             
                  end
         | 
| @@ -79,7 +82,7 @@ class Redis | |
| 79 82 |  | 
| 80 83 | 
             
                  # Redis cluster node returns only host and port information.
         | 
| 81 84 | 
             
                  # So we should complement additional information such as:
         | 
| 82 | 
            -
                  #   scheme, password and so on.
         | 
| 85 | 
            +
                  #   scheme, username, password and so on.
         | 
| 83 86 | 
             
                  def add_common_node_option_if_needed(options, node_opts, key)
         | 
| 84 87 | 
             
                    return options if options[key].nil? && node_opts.first[key].nil?
         | 
| 85 88 |  | 
| @@ -49,57 +49,50 @@ class Redis | |
| 49 49 | 
             
                  end
         | 
| 50 50 |  | 
| 51 51 | 
             
                  def _read_from_socket(nbytes)
         | 
| 52 | 
            -
                     | 
| 53 | 
            -
                      read_nonblock(nbytes)
         | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
                    end
         | 
| 67 | 
            -
                  rescue EOFError
         | 
| 68 | 
            -
                    raise Errno::ECONNRESET
         | 
| 69 | 
            -
                  end
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                  def _write_to_socket(data)
         | 
| 72 | 
            -
                    begin
         | 
| 73 | 
            -
                      write_nonblock(data)
         | 
| 74 | 
            -
                    rescue IO::WaitWritable
         | 
| 75 | 
            -
                      if IO.select(nil, [self], nil, @write_timeout)
         | 
| 76 | 
            -
                        retry
         | 
| 77 | 
            -
                      else
         | 
| 78 | 
            -
                        raise Redis::TimeoutError
         | 
| 79 | 
            -
                      end
         | 
| 80 | 
            -
                    rescue IO::WaitReadable
         | 
| 81 | 
            -
                      if IO.select([self], nil, nil, @write_timeout)
         | 
| 82 | 
            -
                        retry
         | 
| 83 | 
            -
                      else
         | 
| 84 | 
            -
                        raise Redis::TimeoutError
         | 
| 52 | 
            +
                    loop do
         | 
| 53 | 
            +
                      case chunk = read_nonblock(nbytes, exception: false)
         | 
| 54 | 
            +
                      when :wait_readable
         | 
| 55 | 
            +
                        unless wait_readable(@timeout)
         | 
| 56 | 
            +
                          raise Redis::TimeoutError
         | 
| 57 | 
            +
                        end
         | 
| 58 | 
            +
                      when :wait_writable
         | 
| 59 | 
            +
                        unless wait_writable(@timeout)
         | 
| 60 | 
            +
                          raise Redis::TimeoutError
         | 
| 61 | 
            +
                        end
         | 
| 62 | 
            +
                      when nil
         | 
| 63 | 
            +
                        raise Errno::ECONNRESET
         | 
| 64 | 
            +
                      when String
         | 
| 65 | 
            +
                        return chunk
         | 
| 85 66 | 
             
                      end
         | 
| 86 67 | 
             
                    end
         | 
| 87 | 
            -
                  rescue EOFError
         | 
| 88 | 
            -
                    raise Errno::ECONNRESET
         | 
| 89 68 | 
             
                  end
         | 
| 90 69 |  | 
| 91 | 
            -
                  def write( | 
| 92 | 
            -
                    return super( | 
| 70 | 
            +
                  def write(buffer)
         | 
| 71 | 
            +
                    return super(buffer) unless @write_timeout
         | 
| 93 72 |  | 
| 94 | 
            -
                     | 
| 95 | 
            -
                     | 
| 73 | 
            +
                    bytes_to_write = buffer.bytesize
         | 
| 74 | 
            +
                    total_bytes_written = 0
         | 
| 96 75 | 
             
                    loop do
         | 
| 97 | 
            -
                       | 
| 76 | 
            +
                      case bytes_written = write_nonblock(buffer, exception: false)
         | 
| 77 | 
            +
                      when :wait_readable
         | 
| 78 | 
            +
                        unless wait_readable(@write_timeout)
         | 
| 79 | 
            +
                          raise Redis::TimeoutError
         | 
| 80 | 
            +
                        end
         | 
| 81 | 
            +
                      when :wait_writable
         | 
| 82 | 
            +
                        unless wait_writable(@write_timeout)
         | 
| 83 | 
            +
                          raise Redis::TimeoutError
         | 
| 84 | 
            +
                        end
         | 
| 85 | 
            +
                      when nil
         | 
| 86 | 
            +
                        raise Errno::ECONNRESET
         | 
| 87 | 
            +
                      when Integer
         | 
| 88 | 
            +
                        total_bytes_written += bytes_written
         | 
| 98 89 |  | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 90 | 
            +
                        if total_bytes_written >= bytes_to_write
         | 
| 91 | 
            +
                          return total_bytes_written
         | 
| 92 | 
            +
                        end
         | 
| 101 93 |  | 
| 102 | 
            -
             | 
| 94 | 
            +
                        buffer = buffer.byteslice(bytes_written..-1)
         | 
| 95 | 
            +
                      end
         | 
| 103 96 | 
             
                    end
         | 
| 104 97 | 
             
                  end
         | 
| 105 98 | 
             
                end
         | 
| @@ -135,7 +128,7 @@ class Redis | |
| 135 128 | 
             
                        raise TimeoutError
         | 
| 136 129 | 
             
                      end
         | 
| 137 130 |  | 
| 138 | 
            -
                      # JRuby raises Errno::EAGAIN on #read_nonblock even when  | 
| 131 | 
            +
                      # JRuby raises Errno::EAGAIN on #read_nonblock even when it
         | 
| 139 132 | 
             
                      # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
         | 
| 140 133 | 
             
                      # Use the blocking #readpartial method instead.
         | 
| 141 134 |  | 
| @@ -160,7 +153,7 @@ class Redis | |
| 160 153 | 
             
                      begin
         | 
| 161 154 | 
             
                        sock.connect_nonblock(sockaddr)
         | 
| 162 155 | 
             
                      rescue Errno::EINPROGRESS
         | 
| 163 | 
            -
                        raise TimeoutError  | 
| 156 | 
            +
                        raise TimeoutError unless sock.wait_writable(timeout)
         | 
| 164 157 |  | 
| 165 158 | 
             
                        begin
         | 
| 166 159 | 
             
                          sock.connect_nonblock(sockaddr)
         | 
| @@ -215,7 +208,7 @@ class Redis | |
| 215 208 | 
             
                      begin
         | 
| 216 209 | 
             
                        sock.connect_nonblock(sockaddr)
         | 
| 217 210 | 
             
                      rescue Errno::EINPROGRESS
         | 
| 218 | 
            -
                        raise TimeoutError  | 
| 211 | 
            +
                        raise TimeoutError unless sock.wait_writable(timeout)
         | 
| 219 212 |  | 
| 220 213 | 
             
                        begin
         | 
| 221 214 | 
             
                          sock.connect_nonblock(sockaddr)
         | 
| @@ -233,6 +226,18 @@ class Redis | |
| 233 226 | 
             
                  class SSLSocket < ::OpenSSL::SSL::SSLSocket
         | 
| 234 227 | 
             
                    include SocketMixin
         | 
| 235 228 |  | 
| 229 | 
            +
                    unless method_defined?(:wait_readable)
         | 
| 230 | 
            +
                      def wait_readable(timeout = nil)
         | 
| 231 | 
            +
                        to_io.wait_readable(timeout)
         | 
| 232 | 
            +
                      end
         | 
| 233 | 
            +
                    end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                    unless method_defined?(:wait_writable)
         | 
| 236 | 
            +
                      def wait_writable(timeout = nil)
         | 
| 237 | 
            +
                        to_io.wait_writable(timeout)
         | 
| 238 | 
            +
                      end
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
             | 
| 236 241 | 
             
                    def self.connect(host, port, timeout, ssl_params)
         | 
| 237 242 | 
             
                      # Note: this is using Redis::Connection::TCPSocket
         | 
| 238 243 | 
             
                      tcp_sock = TCPSocket.connect(host, port, timeout)
         | 
| @@ -254,13 +259,13 @@ class Redis | |
| 254 259 | 
             
                        # Instead, you have to retry.
         | 
| 255 260 | 
             
                        ssl_sock.connect_nonblock
         | 
| 256 261 | 
             
                      rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
         | 
| 257 | 
            -
                        if  | 
| 262 | 
            +
                        if ssl_sock.wait_readable(timeout)
         | 
| 258 263 | 
             
                          retry
         | 
| 259 264 | 
             
                        else
         | 
| 260 265 | 
             
                          raise TimeoutError
         | 
| 261 266 | 
             
                        end
         | 
| 262 267 | 
             
                      rescue IO::WaitWritable
         | 
| 263 | 
            -
                        if  | 
| 268 | 
            +
                        if ssl_sock.wait_writable(timeout)
         | 
| 264 269 | 
             
                          retry
         | 
| 265 270 | 
             
                        else
         | 
| 266 271 | 
             
                          raise TimeoutError
         | 
    
        data/lib/redis/distributed.rb
    CHANGED
    
    | @@ -24,10 +24,14 @@ class Redis | |
| 24 24 | 
             
                  @default_options = options.dup
         | 
| 25 25 | 
             
                  node_configs.each { |node_config| add_node(node_config) }
         | 
| 26 26 | 
             
                  @subscribed_node = nil
         | 
| 27 | 
            +
                  @watch_key = nil
         | 
| 27 28 | 
             
                end
         | 
| 28 29 |  | 
| 29 30 | 
             
                def node_for(key)
         | 
| 30 | 
            -
                   | 
| 31 | 
            +
                  key = key_tag(key.to_s) || key.to_s
         | 
| 32 | 
            +
                  raise CannotDistribute, :watch if @watch_key && @watch_key != key
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  @ring.get_node(key)
         | 
| 31 35 | 
             
                end
         | 
| 32 36 |  | 
| 33 37 | 
             
                def nodes
         | 
| @@ -799,13 +803,26 @@ class Redis | |
| 799 803 | 
             
                end
         | 
| 800 804 |  | 
| 801 805 | 
             
                # Watch the given keys to determine execution of the MULTI/EXEC block.
         | 
| 802 | 
            -
                def watch(* | 
| 803 | 
            -
                   | 
| 806 | 
            +
                def watch(*keys, &block)
         | 
| 807 | 
            +
                  ensure_same_node(:watch, keys) do |node|
         | 
| 808 | 
            +
                    @watch_key = key_tag(keys.first) || keys.first.to_s
         | 
| 809 | 
            +
             | 
| 810 | 
            +
                    begin
         | 
| 811 | 
            +
                      node.watch(*keys, &block)
         | 
| 812 | 
            +
                    rescue StandardError
         | 
| 813 | 
            +
                      @watch_key = nil
         | 
| 814 | 
            +
                      raise
         | 
| 815 | 
            +
                    end
         | 
| 816 | 
            +
                  end
         | 
| 804 817 | 
             
                end
         | 
| 805 818 |  | 
| 806 819 | 
             
                # Forget about all watched keys.
         | 
| 807 820 | 
             
                def unwatch
         | 
| 808 | 
            -
                  raise CannotDistribute, :unwatch
         | 
| 821 | 
            +
                  raise CannotDistribute, :unwatch unless @watch_key
         | 
| 822 | 
            +
             | 
| 823 | 
            +
                  result = node_for(@watch_key).unwatch
         | 
| 824 | 
            +
                  @watch_key = nil
         | 
| 825 | 
            +
                  result
         | 
| 809 826 | 
             
                end
         | 
| 810 827 |  | 
| 811 828 | 
             
                def pipelined
         | 
| @@ -813,18 +830,30 @@ class Redis | |
| 813 830 | 
             
                end
         | 
| 814 831 |  | 
| 815 832 | 
             
                # Mark the start of a transaction block.
         | 
| 816 | 
            -
                def multi
         | 
| 817 | 
            -
                  raise CannotDistribute, :multi
         | 
| 833 | 
            +
                def multi(&block)
         | 
| 834 | 
            +
                  raise CannotDistribute, :multi unless @watch_key
         | 
| 835 | 
            +
             | 
| 836 | 
            +
                  result = node_for(@watch_key).multi(&block)
         | 
| 837 | 
            +
                  @watch_key = nil if block_given?
         | 
| 838 | 
            +
                  result
         | 
| 818 839 | 
             
                end
         | 
| 819 840 |  | 
| 820 841 | 
             
                # Execute all commands issued after MULTI.
         | 
| 821 842 | 
             
                def exec
         | 
| 822 | 
            -
                  raise CannotDistribute, :exec
         | 
| 843 | 
            +
                  raise CannotDistribute, :exec unless @watch_key
         | 
| 844 | 
            +
             | 
| 845 | 
            +
                  result = node_for(@watch_key).exec
         | 
| 846 | 
            +
                  @watch_key = nil
         | 
| 847 | 
            +
                  result
         | 
| 823 848 | 
             
                end
         | 
| 824 849 |  | 
| 825 850 | 
             
                # Discard all commands issued after MULTI.
         | 
| 826 851 | 
             
                def discard
         | 
| 827 | 
            -
                  raise CannotDistribute, :discard
         | 
| 852 | 
            +
                  raise CannotDistribute, :discard unless @watch_key
         | 
| 853 | 
            +
             | 
| 854 | 
            +
                  result = node_for(@watch_key).discard
         | 
| 855 | 
            +
                  @watch_key = nil
         | 
| 856 | 
            +
                  result
         | 
| 828 857 | 
             
                end
         | 
| 829 858 |  | 
| 830 859 | 
             
                # Control remote script registry.
         | 
    
        data/lib/redis/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: redis
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4. | 
| 4 | 
            +
              version: 4.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ezra Zygmuntowicz
         | 
| @@ -13,10 +13,10 @@ authors: | |
| 13 13 | 
             
            - Michel Martens
         | 
| 14 14 | 
             
            - Damian Janowski
         | 
| 15 15 | 
             
            - Pieter Noordhuis
         | 
| 16 | 
            -
            autorequire: | 
| 16 | 
            +
            autorequire:
         | 
| 17 17 | 
             
            bindir: bin
         | 
| 18 18 | 
             
            cert_chain: []
         | 
| 19 | 
            -
            date:  | 
| 19 | 
            +
            date: 2021-06-11 00:00:00.000000000 Z
         | 
| 20 20 | 
             
            dependencies:
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 22 22 | 
             
              name: em-synchrony
         | 
| @@ -102,10 +102,10 @@ licenses: | |
| 102 102 | 
             
            metadata:
         | 
| 103 103 | 
             
              bug_tracker_uri: https://github.com/redis/redis-rb/issues
         | 
| 104 104 | 
             
              changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
         | 
| 105 | 
            -
              documentation_uri: https://www.rubydoc.info/gems/redis/4. | 
| 105 | 
            +
              documentation_uri: https://www.rubydoc.info/gems/redis/4.3.0
         | 
| 106 106 | 
             
              homepage_uri: https://github.com/redis/redis-rb
         | 
| 107 | 
            -
              source_code_uri: https://github.com/redis/redis-rb/tree/v4. | 
| 108 | 
            -
            post_install_message: | 
| 107 | 
            +
              source_code_uri: https://github.com/redis/redis-rb/tree/v4.3.0
         | 
| 108 | 
            +
            post_install_message:
         | 
| 109 109 | 
             
            rdoc_options: []
         | 
| 110 110 | 
             
            require_paths:
         | 
| 111 111 | 
             
            - lib
         | 
| @@ -120,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 120 120 | 
             
                - !ruby/object:Gem::Version
         | 
| 121 121 | 
             
                  version: '0'
         | 
| 122 122 | 
             
            requirements: []
         | 
| 123 | 
            -
            rubygems_version: 3. | 
| 124 | 
            -
            signing_key: | 
| 123 | 
            +
            rubygems_version: 3.1.2
         | 
| 124 | 
            +
            signing_key:
         | 
| 125 125 | 
             
            specification_version: 4
         | 
| 126 126 | 
             
            summary: A Ruby client library for Redis
         | 
| 127 127 | 
             
            test_files: []
         |