redis 4.0.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +17 -29
  4. data/.travis/Gemfile +5 -0
  5. data/CHANGELOG.md +29 -0
  6. data/Gemfile +5 -0
  7. data/README.md +1 -1
  8. data/bin/build +71 -0
  9. data/lib/redis.rb +198 -12
  10. data/lib/redis/client.rb +26 -12
  11. data/lib/redis/cluster.rb +285 -0
  12. data/lib/redis/cluster/command.rb +81 -0
  13. data/lib/redis/cluster/command_loader.rb +32 -0
  14. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  15. data/lib/redis/cluster/node.rb +104 -0
  16. data/lib/redis/cluster/node_key.rb +35 -0
  17. data/lib/redis/cluster/node_loader.rb +35 -0
  18. data/lib/redis/cluster/option.rb +76 -0
  19. data/lib/redis/cluster/slot.rb +69 -0
  20. data/lib/redis/cluster/slot_loader.rb +47 -0
  21. data/lib/redis/connection/ruby.rb +5 -2
  22. data/lib/redis/distributed.rb +10 -2
  23. data/lib/redis/errors.rb +46 -0
  24. data/lib/redis/pipeline.rb +9 -1
  25. data/lib/redis/version.rb +1 -1
  26. data/makefile +54 -22
  27. data/redis.gemspec +2 -1
  28. data/test/client_test.rb +17 -0
  29. data/test/cluster_abnormal_state_test.rb +38 -0
  30. data/test/cluster_blocking_commands_test.rb +15 -0
  31. data/test/cluster_client_internals_test.rb +77 -0
  32. data/test/cluster_client_key_hash_tags_test.rb +88 -0
  33. data/test/cluster_client_options_test.rb +147 -0
  34. data/test/cluster_client_pipelining_test.rb +59 -0
  35. data/test/cluster_client_replicas_test.rb +36 -0
  36. data/test/cluster_client_slots_test.rb +94 -0
  37. data/test/cluster_client_transactions_test.rb +71 -0
  38. data/test/cluster_commands_on_cluster_test.rb +165 -0
  39. data/test/cluster_commands_on_connection_test.rb +40 -0
  40. data/test/cluster_commands_on_geo_test.rb +74 -0
  41. data/test/cluster_commands_on_hashes_test.rb +11 -0
  42. data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
  43. data/test/cluster_commands_on_keys_test.rb +134 -0
  44. data/test/cluster_commands_on_lists_test.rb +15 -0
  45. data/test/cluster_commands_on_pub_sub_test.rb +101 -0
  46. data/test/cluster_commands_on_scripting_test.rb +56 -0
  47. data/test/cluster_commands_on_server_test.rb +221 -0
  48. data/test/cluster_commands_on_sets_test.rb +39 -0
  49. data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
  50. data/test/cluster_commands_on_streams_test.rb +196 -0
  51. data/test/cluster_commands_on_strings_test.rb +15 -0
  52. data/test/cluster_commands_on_transactions_test.rb +41 -0
  53. data/test/cluster_commands_on_value_types_test.rb +14 -0
  54. data/test/commands_on_geo_test.rb +116 -0
  55. data/test/commands_on_hashes_test.rb +2 -14
  56. data/test/commands_on_hyper_log_log_test.rb +2 -14
  57. data/test/commands_on_lists_test.rb +2 -13
  58. data/test/commands_on_sets_test.rb +2 -70
  59. data/test/commands_on_sorted_sets_test.rb +2 -145
  60. data/test/commands_on_strings_test.rb +2 -94
  61. data/test/commands_on_value_types_test.rb +36 -0
  62. data/test/distributed_blocking_commands_test.rb +8 -0
  63. data/test/distributed_commands_on_hashes_test.rb +16 -3
  64. data/test/distributed_commands_on_hyper_log_log_test.rb +8 -13
  65. data/test/distributed_commands_on_lists_test.rb +4 -5
  66. data/test/distributed_commands_on_sets_test.rb +45 -46
  67. data/test/distributed_commands_on_sorted_sets_test.rb +51 -8
  68. data/test/distributed_commands_on_strings_test.rb +10 -0
  69. data/test/distributed_commands_on_value_types_test.rb +36 -0
  70. data/test/helper.rb +176 -32
  71. data/test/internals_test.rb +20 -1
  72. data/test/lint/blocking_commands.rb +40 -16
  73. data/test/lint/hashes.rb +41 -0
  74. data/test/lint/hyper_log_log.rb +15 -1
  75. data/test/lint/lists.rb +16 -0
  76. data/test/lint/sets.rb +142 -0
  77. data/test/lint/sorted_sets.rb +183 -2
  78. data/test/lint/strings.rb +102 -0
  79. data/test/pipelining_commands_test.rb +8 -0
  80. data/test/support/cluster/orchestrator.rb +199 -0
  81. data/test/support/redis_mock.rb +1 -1
  82. data/test/transactions_test.rb +10 -0
  83. metadata +81 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e0d0ba2328aca583c0f487729779c2b10b12c7b
4
- data.tar.gz: 4a411cfa3512bafe7c2c12ac8a02c02bc87065aa
3
+ metadata.gz: 1ec178932a6874e8ac7a4f6cfa4390c8223367ec
4
+ data.tar.gz: 986e6c5d1729b9ec8f7d66900e5d9ad9437e29f9
5
5
  SHA512:
6
- metadata.gz: 3af7dc63dc7bdc243da306817583db9b6989c21a0714c6652b4a443bfd9c46b2afba0707b028d708a74148bbeedd09d4ec207a0459b3559cb19b95f2f030bb07
7
- data.tar.gz: 98d5aed456ebcd3ccdc50980879a3c14be4c8a1874c6febae95579d2fb3828bda2e82b05e62dc6a4966e178993d4a2a20dc3dedd9f8583cd731851eab2f8e164
6
+ metadata.gz: 14db8cb42f08014ebd942c39b5f119a68a8ec50fec046572bb3afc7708634589311b9bea0d4153bfd1d7cb1c46a94a00d77613872b2cb8c10c33f132755cd62d
7
+ data.tar.gz: efe0db683450fcb30b6d23b8c9448d6925b5c5d95b847f9563405a61cc7e667bbf8aea22642dcc9d8a1b716dc9c8cb55c562c86a08223e020991f69eff7df7f7
data/.gitignore CHANGED
@@ -5,6 +5,7 @@ Gemfile.lock
5
5
  /tmp/
6
6
  /.idea
7
7
  /.yardoc
8
+ /.bundle
8
9
  /coverage/*
9
10
  /doc/
10
11
  /examples/sentinel/sentinel.conf
@@ -14,3 +15,5 @@ Gemfile.lock
14
15
  /redis/*
15
16
  /test/db
16
17
  /test/test.conf
18
+ appendonly.aof
19
+ temp-rewriteaof-*.aof
@@ -1,13 +1,19 @@
1
1
  language: ruby
2
+ cache:
3
+ directories:
4
+ - tmp/cache
5
+ before_install:
6
+ - gem update --system 2.6.14
7
+ - gem --version
2
8
 
3
- script: make test
9
+ script: make
4
10
 
5
11
  rvm:
6
12
  - 2.2.2
7
13
  - 2.3.3
8
14
  - 2.4.1
9
- - jruby-9
10
- - rbx-3
15
+ - 2.5.0
16
+ - jruby-9.1.17.0
11
17
 
12
18
  gemfile: ".travis/Gemfile"
13
19
 
@@ -19,7 +25,7 @@ before_script:
19
25
  env:
20
26
  global:
21
27
  - VERBOSE=true
22
- - TIMEOUT=1
28
+ - TIMEOUT=9
23
29
  matrix:
24
30
  - DRIVER=ruby REDIS_BRANCH=3.0
25
31
  - DRIVER=ruby REDIS_BRANCH=3.2
@@ -27,7 +33,7 @@ env:
27
33
  - DRIVER=hiredis REDIS_BRANCH=3.2
28
34
  - DRIVER=synchrony REDIS_BRANCH=3.0
29
35
  - DRIVER=synchrony REDIS_BRANCH=3.2
30
- - DRIVER=ruby REDIS_BRANCH=unstable
36
+ - DRIVER=ruby REDIS_BRANCH=4.0
31
37
 
32
38
  branches:
33
39
  only:
@@ -38,34 +44,16 @@ branches:
38
44
  matrix:
39
45
  exclude:
40
46
  # hiredis
41
- - rvm: jruby-9
42
- gemfile: .travis/Gemfile
43
- env: DRIVER=hiredis REDIS_BRANCH=3.0
44
- - rvm: jruby-9
45
- gemfile: .travis/Gemfile
46
- env: DRIVER=hiredis REDIS_BRANCH=3.2
47
- - rvm: jruby-9
48
- gemfile: .travis/Gemfile
49
- env: DRIVER=hiredis REDIS_BRANCH=3.0
50
- - rvm: jruby-9
51
- gemfile: .travis/Gemfile
52
- env: DRIVER=hiredis REDIS_BRANCH=3.2
47
+ - rvm: jruby-9.1.17.0
48
+ env: DRIVER=hiredis REDIS_BRANCH=3.0
49
+ - rvm: jruby-9.1.17.0
50
+ env: DRIVER=hiredis REDIS_BRANCH=3.2
53
51
 
54
52
  # synchrony
55
- - rvm: jruby-9
56
- gemfile: .travis/Gemfile
53
+ - rvm: jruby-9.1.17.0
57
54
  env: DRIVER=synchrony REDIS_BRANCH=3.0
58
- - rvm: jruby-9
59
- gemfile: .travis/Gemfile
55
+ - rvm: jruby-9.1.17.0
60
56
  env: DRIVER=synchrony REDIS_BRANCH=3.2
61
- - rvm: jruby-9
62
- gemfile: .travis/Gemfile
63
- env: DRIVER=synchrony REDIS_BRANCH=3.0
64
- - rvm: jruby-9
65
- gemfile: .travis/Gemfile
66
- env: DRIVER=synchrony REDIS_BRANCH=3.2
67
- allow_failures:
68
- - rvm: rbx-3
69
57
 
70
58
  notifications:
71
59
  irc:
@@ -2,6 +2,11 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec :path => "../"
4
4
 
5
+ # Using jruby-openssl 0.10.0, we get NPEs in jruby tests: https://github.com/redis/redis-rb/issues/756
6
+ platform :jruby do
7
+ gem 'jruby-openssl', '<0.10.0'
8
+ end
9
+
5
10
  case ENV["DRIVER"]
6
11
  when "hiredis"
7
12
  gem "hiredis"
@@ -1,3 +1,23 @@
1
+ # 4.0.3
2
+
3
+ * Fix raising command error for first command in pipeline. See #788.
4
+ * Fix the gemspec to stop exposing a `build` executable. See #785.
5
+ * Add `:reconnect_delay` and `:reconnect_delay_max` options. See #778.
6
+
7
+ # 4.0.2
8
+
9
+ * Added `Redis#unlink`. See #766.
10
+
11
+ * `Redis.new` now accept a custom connector via `:connector`. See #591.
12
+
13
+ * `Redis#multi` no longer perform empty transactions. See #747.
14
+
15
+ * `Redis#hdel` now accepts hash keys as multiple arguments like `#del`. See #755.
16
+
17
+ * Allow to skip SSL verification. See #745.
18
+
19
+ * Add Geo commands: `geoadd`, `geohash`, `georadius`, `georadiusbymember`, `geopos`, `geodist`. See #730.
20
+
1
21
  # 4.0.1
2
22
 
3
23
  * `Redis::Distributed` now supports `mget` and `mapped_mget`. See #687.
@@ -21,6 +41,15 @@
21
41
 
22
42
  * Dropped official support for Ruby < 2.2.2.
23
43
 
44
+ # 3.3.5
45
+
46
+ * Fixed Ruby 1.8 compatibility after backporting `Redis#connection`. See #719.
47
+
48
+ # 3.3.4 (yanked)
49
+
50
+ * `Redis#connection` returns a hash with connection information.
51
+ You shouldn't need to call `Redis#_client`, ever.
52
+
24
53
  # 3.3.3
25
54
 
26
55
  * Improved timeout handling after dropping Timeout module.
data/Gemfile CHANGED
@@ -1,3 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ # Using jruby-openssl 0.10.0, we get NPEs in jruby tests: https://github.com/redis/redis-rb/issues/756
6
+ platform :jruby do
7
+ gem 'jruby-openssl', '<0.10.0'
8
+ end
data/README.md CHANGED
@@ -176,7 +176,7 @@ it can't connect to the server a `Redis::CannotConnectError` error will be raise
176
176
  ```ruby
177
177
  begin
178
178
  redis.ping
179
- rescue Exception => e
179
+ rescue StandardError => e
180
180
  e.inspect
181
181
  # => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
182
182
 
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ TARBALL = ARGV[0]
4
+
5
+ require 'digest/sha1'
6
+ require 'fileutils'
7
+
8
+ class Builder
9
+ def initialize(redis_branch, tmp_dir)
10
+ @redis_branch = redis_branch
11
+ @tmp_dir = tmp_dir
12
+ @build_dir = File.join(@tmp_dir, "cache", "redis-#{redis_branch}")
13
+ end
14
+
15
+ def run
16
+ download_tarball
17
+ if old_checkum != checksum
18
+ build
19
+ update_checksum
20
+ end
21
+ 0
22
+ end
23
+
24
+ def download_tarball
25
+ command!('wget', tarball_url, '-O', tarball_path)
26
+ end
27
+
28
+ def tarball_path
29
+ File.join(@tmp_dir, "redis-#{@redis_branch}.tar.gz")
30
+ end
31
+
32
+ def tarball_url
33
+ "https://github.com/antirez/redis/archive/#{@redis_branch}.tar.gz"
34
+ end
35
+
36
+ def build
37
+ FileUtils.rm_rf(@build_dir)
38
+ FileUtils.mkdir_p(@build_dir)
39
+ command!('tar', 'xf', tarball_path, '-C', File.expand_path('../', @build_dir))
40
+ Dir.chdir(@build_dir) do
41
+ command!('make')
42
+ end
43
+ end
44
+
45
+ def update_checksum
46
+ File.write(checksum_path, checksum)
47
+ end
48
+
49
+ def old_checkum
50
+ File.read(checksum_path)
51
+ rescue Errno::ENOENT
52
+ nil
53
+ end
54
+
55
+ def checksum_path
56
+ File.join(@build_dir, 'build.checksum')
57
+ end
58
+
59
+ def checksum
60
+ @checksum ||= Digest::SHA1.file(tarball_path).hexdigest
61
+ end
62
+
63
+ def command!(*args)
64
+ puts "$ #{args.join(' ')}"
65
+ unless system(*args)
66
+ raise "Command failed with status #{$?.exitstatus}"
67
+ end
68
+ end
69
+ end
70
+
71
+ exit Builder.new(ARGV[0], ARGV[1]).run
@@ -31,11 +31,16 @@ class Redis
31
31
  # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
32
32
  # @option options [Array] :sentinels List of sentinels to contact
33
33
  # @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
34
+ # @option options [Array<String, Hash{Symbol => String, Integer}>] :cluster List of cluster nodes to contact
35
+ # @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
36
+ # @option options [Class] :connector Class of custom connector
34
37
  #
35
38
  # @return [Redis] a new client instance
36
39
  def initialize(options = {})
37
40
  @options = options.dup
38
- @original_client = @client = Client.new(options)
41
+ @cluster_mode = options.key?(:cluster)
42
+ client = @cluster_mode ? Cluster : Client
43
+ @original_client = @client = client.new(options)
39
44
  @queue = Hash.new { |h, k| h[k] = [] }
40
45
 
41
46
  super() # Monitor#initialize
@@ -273,9 +278,7 @@ class Redis
273
278
  synchronize do |client|
274
279
  client.call([:info, cmd].compact) do |reply|
275
280
  if reply.kind_of?(String)
276
- reply = Hash[reply.split("\r\n").map do |line|
277
- line.split(":", 2) unless line =~ /^(#|$)/
278
- end.compact]
281
+ reply = HashifyInfo.call(reply)
279
282
 
280
283
  if cmd && cmd.to_s == "commandstats"
281
284
  # Extract nested hashes for INFO COMMANDSTATS
@@ -524,6 +527,16 @@ class Redis
524
527
  end
525
528
  end
526
529
 
530
+ # Unlink one or more keys.
531
+ #
532
+ # @param [String, Array<String>] keys
533
+ # @return [Fixnum] number of keys that were unlinked
534
+ def unlink(*keys)
535
+ synchronize do |client|
536
+ client.call([:unlink] + keys)
537
+ end
538
+ end
539
+
527
540
  # Determine if a key exists.
528
541
  #
529
542
  # @param [String] key
@@ -2102,9 +2115,9 @@ class Redis
2102
2115
  # @param [String] key
2103
2116
  # @param [String, Array<String>] field
2104
2117
  # @return [Fixnum] the number of fields that were removed from the hash
2105
- def hdel(key, field)
2118
+ def hdel(key, *fields)
2106
2119
  synchronize do |client|
2107
- client.call([:hdel, key, field])
2120
+ client.call([:hdel, key, *fields])
2108
2121
  end
2109
2122
  end
2110
2123
 
@@ -2710,6 +2723,86 @@ class Redis
2710
2723
  end
2711
2724
  end
2712
2725
 
2726
+ # Adds the specified geospatial items (latitude, longitude, name) to the specified key
2727
+ #
2728
+ # @param [String] key
2729
+ # @param [Array] member arguemnts for member or members: longitude, latitude, name
2730
+ # @return [Intger] number of elements added to the sorted set
2731
+ def geoadd(key, *member)
2732
+ synchronize do |client|
2733
+ client.call([:geoadd, key, member])
2734
+ end
2735
+ end
2736
+
2737
+ # Returns geohash string representing position for specified members of the specified key.
2738
+ #
2739
+ # @param [String] key
2740
+ # @param [String, Array<String>] member one member or array of members
2741
+ # @return [Array<String, nil>] returns array containg geohash string if member is present, nil otherwise
2742
+ def geohash(key, member)
2743
+ synchronize do |client|
2744
+ client.call([:geohash, key, member])
2745
+ end
2746
+ end
2747
+
2748
+
2749
+ # Query a sorted set representing a geospatial index to fetch members matching a
2750
+ # given maximum distance from a point
2751
+ #
2752
+ # @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
2753
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2754
+ # @param [Integer] count limit the results to the first N matching items
2755
+ # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2756
+ # @return [Array<String>] may be changed with `options`
2757
+
2758
+ def georadius(*args, **geoptions)
2759
+ geoarguments = _geoarguments(*args, **geoptions)
2760
+
2761
+ synchronize do |client|
2762
+ client.call([:georadius, *geoarguments])
2763
+ end
2764
+ end
2765
+
2766
+ # Query a sorted set representing a geospatial index to fetch members matching a
2767
+ # given maximum distance from an already existing member
2768
+ #
2769
+ # @param [Array] args key, member, radius, unit(m|km|ft|mi)
2770
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2771
+ # @param [Integer] count limit the results to the first N matching items
2772
+ # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2773
+ # @return [Array<String>] may be changed with `options`
2774
+
2775
+ def georadiusbymember(*args, **geoptions)
2776
+ geoarguments = _geoarguments(*args, **geoptions)
2777
+
2778
+ synchronize do |client|
2779
+ client.call([:georadiusbymember, *geoarguments])
2780
+ end
2781
+ end
2782
+
2783
+ # Returns longitude and latitude of members of a geospatial index
2784
+ #
2785
+ # @param [String] key
2786
+ # @param [String, Array<String>] member one member or array of members
2787
+ # @return [Array<Array<String>, nil>] returns array of elements, where each element is either array of longitude and latitude or nil
2788
+ def geopos(key, member)
2789
+ synchronize do |client|
2790
+ client.call([:geopos, key, member])
2791
+ end
2792
+ end
2793
+
2794
+ # Returns the distance between two members of a geospatial index
2795
+ #
2796
+ # @param [String ]key
2797
+ # @param [Array<String>] members
2798
+ # @param ['m', 'km', 'mi', 'ft'] unit
2799
+ # @return [String, nil] returns distance in spefied unit if both members present, nil otherwise.
2800
+ def geodist(key, member1, member2, unit = 'm')
2801
+ synchronize do |client|
2802
+ client.call([:geodist, key, member1, member2, unit])
2803
+ end
2804
+ end
2805
+
2713
2806
  # Interact with the sentinel command (masters, master, slaves, failover)
2714
2807
  #
2715
2808
  # @param [String] subcommand e.g. `masters`, `master`, `slaves`
@@ -2737,6 +2830,41 @@ class Redis
2737
2830
  end
2738
2831
  end
2739
2832
 
2833
+ # Sends `CLUSTER *` command to random node and returns its reply.
2834
+ #
2835
+ # @see https://redis.io/commands#cluster Reference of cluster command
2836
+ #
2837
+ # @param subcommand [String, Symbol] the subcommand of cluster command
2838
+ # e.g. `:slots`, `:nodes`, `:slaves`, `:info`
2839
+ #
2840
+ # @return [Object] depends on the subcommand
2841
+ def cluster(subcommand, *args)
2842
+ subcommand = subcommand.to_s.downcase
2843
+ block = case subcommand
2844
+ when 'slots' then HashifyClusterSlots
2845
+ when 'nodes' then HashifyClusterNodes
2846
+ when 'slaves' then HashifyClusterSlaves
2847
+ when 'info' then HashifyInfo
2848
+ else Noop
2849
+ end
2850
+
2851
+ # @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
2852
+ block = Noop unless @cluster_mode
2853
+
2854
+ synchronize do |client|
2855
+ client.call([:cluster, subcommand] + args, &block)
2856
+ end
2857
+ end
2858
+
2859
+ # Sends `ASKING` command to random node and returns its reply.
2860
+ #
2861
+ # @see https://redis.io/topics/cluster-spec#ask-redirection ASK redirection
2862
+ #
2863
+ # @return [String] `'OK'`
2864
+ def asking
2865
+ synchronize { |client| client.call(%i[asking]) }
2866
+ end
2867
+
2740
2868
  def id
2741
2869
  @original_client.id
2742
2870
  end
@@ -2750,6 +2878,8 @@ class Redis
2750
2878
  end
2751
2879
 
2752
2880
  def connection
2881
+ return @original_client.connection_info if @cluster_mode
2882
+
2753
2883
  {
2754
2884
  host: @original_client.host,
2755
2885
  port: @original_client.port,
@@ -2805,14 +2935,70 @@ private
2805
2935
  }
2806
2936
 
2807
2937
  FloatifyPairs =
2808
- lambda { |array|
2809
- if array
2810
- array.each_slice(2).map do |member, score|
2811
- [member, Floatify.call(score)]
2812
- end
2938
+ lambda { |result|
2939
+ result.each_slice(2).map do |member, score|
2940
+ [member, Floatify.call(score)]
2941
+ end
2942
+ }
2943
+
2944
+ HashifyInfo =
2945
+ lambda { |reply|
2946
+ Hash[reply.split("\r\n").map do |line|
2947
+ line.split(':', 2) unless line =~ /^(#|$)/
2948
+ end.compact]
2949
+ }
2950
+
2951
+ HashifyClusterNodeInfo =
2952
+ lambda { |str|
2953
+ arr = str.split(' ')
2954
+ {
2955
+ 'node_id' => arr[0],
2956
+ 'ip_port' => arr[1],
2957
+ 'flags' => arr[2].split(','),
2958
+ 'master_node_id' => arr[3],
2959
+ 'ping_sent' => arr[4],
2960
+ 'pong_recv' => arr[5],
2961
+ 'config_epoch' => arr[6],
2962
+ 'link_state' => arr[7],
2963
+ 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
2964
+ }
2965
+ }
2966
+
2967
+ HashifyClusterSlots =
2968
+ lambda { |reply|
2969
+ reply.map do |arr|
2970
+ first_slot, last_slot = arr[0..1]
2971
+ master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
2972
+ replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
2973
+ {
2974
+ 'start_slot' => first_slot,
2975
+ 'end_slot' => last_slot,
2976
+ 'master' => master,
2977
+ 'replicas' => replicas
2978
+ }
2813
2979
  end
2814
2980
  }
2815
2981
 
2982
+ HashifyClusterNodes =
2983
+ lambda { |reply|
2984
+ reply.split(/[\r\n]+/).map { |str| HashifyClusterNodeInfo.call(str) }
2985
+ }
2986
+
2987
+ HashifyClusterSlaves =
2988
+ lambda { |reply|
2989
+ reply.map { |str| HashifyClusterNodeInfo.call(str) }
2990
+ }
2991
+
2992
+ Noop = ->(reply) { reply }
2993
+
2994
+ def _geoarguments(*args, options: nil, sort: nil, count: nil)
2995
+ args.push sort if sort
2996
+ args.push 'count', count if count
2997
+ args.push options if options
2998
+
2999
+ args.uniq
3000
+ end
3001
+
2816
3002
  def _subscription(method, timeout, channels, block)
2817
3003
  return @client.call([method] + channels) if subscribed?
2818
3004
 
@@ -2827,11 +3013,11 @@ private
2827
3013
  @client = original
2828
3014
  end
2829
3015
  end
2830
-
2831
3016
  end
2832
3017
 
2833
3018
  require_relative "redis/version"
2834
3019
  require_relative "redis/connection"
2835
3020
  require_relative "redis/client"
3021
+ require_relative "redis/cluster"
2836
3022
  require_relative "redis/pipeline"
2837
3023
  require_relative "redis/subscribe"