redis 4.1.0.beta1 → 4.1.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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -2
  3. data/README.md +45 -0
  4. data/lib/redis.rb +497 -20
  5. data/lib/redis/client.rb +14 -6
  6. data/lib/redis/cluster.rb +1 -0
  7. data/lib/redis/cluster/command_loader.rb +2 -0
  8. data/lib/redis/cluster/node_loader.rb +2 -0
  9. data/lib/redis/cluster/option.rb +1 -0
  10. data/lib/redis/cluster/slot_loader.rb +2 -0
  11. data/lib/redis/distributed.rb +3 -4
  12. data/lib/redis/version.rb +1 -1
  13. metadata +20 -243
  14. data/.gitignore +0 -19
  15. data/.travis.yml +0 -61
  16. data/.travis/Gemfile +0 -18
  17. data/.yardopts +0 -3
  18. data/Gemfile +0 -8
  19. data/benchmarking/logging.rb +0 -71
  20. data/benchmarking/pipeline.rb +0 -51
  21. data/benchmarking/speed.rb +0 -21
  22. data/benchmarking/suite.rb +0 -24
  23. data/benchmarking/worker.rb +0 -71
  24. data/bin/build +0 -71
  25. data/bors.toml +0 -14
  26. data/examples/basic.rb +0 -15
  27. data/examples/consistency.rb +0 -114
  28. data/examples/dist_redis.rb +0 -43
  29. data/examples/incr-decr.rb +0 -17
  30. data/examples/list.rb +0 -26
  31. data/examples/pubsub.rb +0 -37
  32. data/examples/sentinel.rb +0 -41
  33. data/examples/sentinel/start +0 -49
  34. data/examples/sets.rb +0 -36
  35. data/examples/unicorn/config.ru +0 -3
  36. data/examples/unicorn/unicorn.rb +0 -20
  37. data/makefile +0 -74
  38. data/redis.gemspec +0 -42
  39. data/test/bitpos_test.rb +0 -63
  40. data/test/blocking_commands_test.rb +0 -40
  41. data/test/client_test.rb +0 -76
  42. data/test/cluster_abnormal_state_test.rb +0 -38
  43. data/test/cluster_blocking_commands_test.rb +0 -15
  44. data/test/cluster_client_internals_test.rb +0 -77
  45. data/test/cluster_client_key_hash_tags_test.rb +0 -88
  46. data/test/cluster_client_options_test.rb +0 -147
  47. data/test/cluster_client_pipelining_test.rb +0 -59
  48. data/test/cluster_client_replicas_test.rb +0 -36
  49. data/test/cluster_client_slots_test.rb +0 -94
  50. data/test/cluster_client_transactions_test.rb +0 -71
  51. data/test/cluster_commands_on_cluster_test.rb +0 -165
  52. data/test/cluster_commands_on_connection_test.rb +0 -40
  53. data/test/cluster_commands_on_geo_test.rb +0 -74
  54. data/test/cluster_commands_on_hashes_test.rb +0 -11
  55. data/test/cluster_commands_on_hyper_log_log_test.rb +0 -17
  56. data/test/cluster_commands_on_keys_test.rb +0 -134
  57. data/test/cluster_commands_on_lists_test.rb +0 -15
  58. data/test/cluster_commands_on_pub_sub_test.rb +0 -101
  59. data/test/cluster_commands_on_scripting_test.rb +0 -56
  60. data/test/cluster_commands_on_server_test.rb +0 -221
  61. data/test/cluster_commands_on_sets_test.rb +0 -39
  62. data/test/cluster_commands_on_sorted_sets_test.rb +0 -35
  63. data/test/cluster_commands_on_streams_test.rb +0 -196
  64. data/test/cluster_commands_on_strings_test.rb +0 -15
  65. data/test/cluster_commands_on_transactions_test.rb +0 -41
  66. data/test/cluster_commands_on_value_types_test.rb +0 -14
  67. data/test/command_map_test.rb +0 -28
  68. data/test/commands_on_geo_test.rb +0 -116
  69. data/test/commands_on_hashes_test.rb +0 -7
  70. data/test/commands_on_hyper_log_log_test.rb +0 -7
  71. data/test/commands_on_lists_test.rb +0 -7
  72. data/test/commands_on_sets_test.rb +0 -7
  73. data/test/commands_on_sorted_sets_test.rb +0 -7
  74. data/test/commands_on_strings_test.rb +0 -7
  75. data/test/commands_on_value_types_test.rb +0 -207
  76. data/test/connection_handling_test.rb +0 -275
  77. data/test/connection_test.rb +0 -57
  78. data/test/distributed_blocking_commands_test.rb +0 -52
  79. data/test/distributed_commands_on_hashes_test.rb +0 -21
  80. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -26
  81. data/test/distributed_commands_on_lists_test.rb +0 -19
  82. data/test/distributed_commands_on_sets_test.rb +0 -105
  83. data/test/distributed_commands_on_sorted_sets_test.rb +0 -59
  84. data/test/distributed_commands_on_strings_test.rb +0 -79
  85. data/test/distributed_commands_on_value_types_test.rb +0 -129
  86. data/test/distributed_commands_requiring_clustering_test.rb +0 -162
  87. data/test/distributed_connection_handling_test.rb +0 -21
  88. data/test/distributed_internals_test.rb +0 -68
  89. data/test/distributed_key_tags_test.rb +0 -50
  90. data/test/distributed_persistence_control_commands_test.rb +0 -24
  91. data/test/distributed_publish_subscribe_test.rb +0 -90
  92. data/test/distributed_remote_server_control_commands_test.rb +0 -64
  93. data/test/distributed_scripting_test.rb +0 -100
  94. data/test/distributed_sorting_test.rb +0 -18
  95. data/test/distributed_test.rb +0 -56
  96. data/test/distributed_transactions_test.rb +0 -30
  97. data/test/encoding_test.rb +0 -14
  98. data/test/error_replies_test.rb +0 -57
  99. data/test/fork_safety_test.rb +0 -60
  100. data/test/helper.rb +0 -344
  101. data/test/helper_test.rb +0 -22
  102. data/test/internals_test.rb +0 -395
  103. data/test/lint/blocking_commands.rb +0 -174
  104. data/test/lint/hashes.rb +0 -203
  105. data/test/lint/hyper_log_log.rb +0 -74
  106. data/test/lint/lists.rb +0 -159
  107. data/test/lint/sets.rb +0 -282
  108. data/test/lint/sorted_sets.rb +0 -497
  109. data/test/lint/strings.rb +0 -348
  110. data/test/lint/value_types.rb +0 -130
  111. data/test/persistence_control_commands_test.rb +0 -24
  112. data/test/pipelining_commands_test.rb +0 -246
  113. data/test/publish_subscribe_test.rb +0 -280
  114. data/test/remote_server_control_commands_test.rb +0 -175
  115. data/test/scanning_test.rb +0 -407
  116. data/test/scripting_test.rb +0 -76
  117. data/test/sentinel_command_test.rb +0 -78
  118. data/test/sentinel_test.rb +0 -253
  119. data/test/sorting_test.rb +0 -57
  120. data/test/ssl_test.rb +0 -69
  121. data/test/support/cluster/orchestrator.rb +0 -199
  122. data/test/support/connection/hiredis.rb +0 -1
  123. data/test/support/connection/ruby.rb +0 -1
  124. data/test/support/connection/synchrony.rb +0 -17
  125. data/test/support/redis_mock.rb +0 -130
  126. data/test/support/ssl/gen_certs.sh +0 -31
  127. data/test/support/ssl/trusted-ca.crt +0 -25
  128. data/test/support/ssl/trusted-ca.key +0 -27
  129. data/test/support/ssl/trusted-cert.crt +0 -81
  130. data/test/support/ssl/trusted-cert.key +0 -28
  131. data/test/support/ssl/untrusted-ca.crt +0 -26
  132. data/test/support/ssl/untrusted-ca.key +0 -27
  133. data/test/support/ssl/untrusted-cert.crt +0 -82
  134. data/test/support/ssl/untrusted-cert.key +0 -28
  135. data/test/support/wire/synchrony.rb +0 -24
  136. data/test/support/wire/thread.rb +0 -5
  137. data/test/synchrony_driver.rb +0 -85
  138. data/test/test.conf.erb +0 -9
  139. data/test/thread_safety_test.rb +0 -60
  140. data/test/transactions_test.rb +0 -272
  141. data/test/unknown_commands_test.rb +0 -12
  142. data/test/url_param_test.rb +0 -136
@@ -1,100 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestDistributedScripting < Test::Unit::TestCase
4
-
5
- include Helper::Distributed
6
-
7
- def to_sha(script)
8
- r.script(:load, script).first
9
- end
10
-
11
- def test_script_exists
12
- target_version "2.5.9" do # 2.6-rc1
13
- a = to_sha("return 1")
14
- b = a.succ
15
-
16
- assert_equal [true], r.script(:exists, a)
17
- assert_equal [false], r.script(:exists, b)
18
- assert_equal [[true]], r.script(:exists, [a])
19
- assert_equal [[false]], r.script(:exists, [b])
20
- assert_equal [[true, false]], r.script(:exists, [a, b])
21
- end
22
- end
23
-
24
- def test_script_flush
25
- target_version "2.5.9" do # 2.6-rc1
26
- sha = to_sha("return 1")
27
- assert r.script(:exists, sha).first
28
- assert_equal ["OK"], r.script(:flush)
29
- assert !r.script(:exists, sha).first
30
- end
31
- end
32
-
33
- def test_script_kill
34
- target_version "2.5.9" do # 2.6-rc1
35
- redis_mock(:script => lambda { |arg| "+#{arg.upcase}" }) do |redis|
36
- assert_equal ["KILL"], redis.script(:kill)
37
- end
38
- end
39
- end
40
-
41
- def test_eval
42
- target_version "2.5.9" do # 2.6-rc1
43
- assert_raises(Redis::Distributed::CannotDistribute) do
44
- r.eval("return #KEYS")
45
- end
46
-
47
- assert_raises(Redis::Distributed::CannotDistribute) do
48
- r.eval("return KEYS", ["k1", "k2"])
49
- end
50
-
51
- assert_equal ["k1"], r.eval("return KEYS", ["k1"])
52
- assert_equal ["a1", "a2"], r.eval("return ARGV", ["k1"], ["a1", "a2"])
53
- end
54
- end
55
-
56
- def test_eval_with_options_hash
57
- target_version "2.5.9" do # 2.6-rc1
58
- assert_raises(Redis::Distributed::CannotDistribute) do
59
- r.eval("return #KEYS", {})
60
- end
61
-
62
- assert_raises(Redis::Distributed::CannotDistribute) do
63
- r.eval("return KEYS", { :keys => ["k1", "k2"] })
64
- end
65
-
66
- assert_equal ["k1"], r.eval("return KEYS", { :keys => ["k1"] })
67
- assert_equal ["a1", "a2"], r.eval("return ARGV", { :keys => ["k1"], :argv => ["a1", "a2"] })
68
- end
69
- end
70
-
71
- def test_evalsha
72
- target_version "2.5.9" do # 2.6-rc1
73
- assert_raises(Redis::Distributed::CannotDistribute) do
74
- r.evalsha(to_sha("return #KEYS"))
75
- end
76
-
77
- assert_raises(Redis::Distributed::CannotDistribute) do
78
- r.evalsha(to_sha("return KEYS"), ["k1", "k2"])
79
- end
80
-
81
- assert_equal ["k1"], r.evalsha(to_sha("return KEYS"), ["k1"])
82
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), ["k1"], ["a1", "a2"])
83
- end
84
- end
85
-
86
- def test_evalsha_with_options_hash
87
- target_version "2.5.9" do # 2.6-rc1
88
- assert_raises(Redis::Distributed::CannotDistribute) do
89
- r.evalsha(to_sha("return #KEYS"), {})
90
- end
91
-
92
- assert_raises(Redis::Distributed::CannotDistribute) do
93
- r.evalsha(to_sha("return KEYS"), { :keys => ["k1", "k2"] })
94
- end
95
-
96
- assert_equal ["k1"], r.evalsha(to_sha("return KEYS"), { :keys => ["k1"] })
97
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), { :keys => ["k1"], :argv => ["a1", "a2"] })
98
- end
99
- end
100
- end
@@ -1,18 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestDistributedSorting < Test::Unit::TestCase
4
-
5
- include Helper::Distributed
6
-
7
- def test_sort
8
- assert_raise(Redis::Distributed::CannotDistribute) do
9
- r.set("foo:1", "s1")
10
- r.set("foo:2", "s2")
11
-
12
- r.rpush("bar", "1")
13
- r.rpush("bar", "2")
14
-
15
- r.sort("bar", :get => "foo:*", :limit => [0, 1])
16
- end
17
- end
18
- end
@@ -1,56 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestDistributed < Test::Unit::TestCase
4
-
5
- include Helper::Distributed
6
-
7
- def test_handle_multiple_servers
8
- @r = Redis::Distributed.new ["redis://127.0.0.1:#{PORT}/15", *NODES]
9
-
10
- 100.times do |idx|
11
- @r.set(idx.to_s, "foo#{idx}")
12
- end
13
-
14
- 100.times do |idx|
15
- assert_equal "foo#{idx}", @r.get(idx.to_s)
16
- end
17
-
18
- assert_equal "0", @r.keys("*").sort.first
19
- assert_equal "string", @r.type("1")
20
- end
21
-
22
- def test_add_nodes
23
- logger = Logger.new("/dev/null")
24
-
25
- @r = Redis::Distributed.new NODES, :logger => logger, :timeout => 10
26
-
27
- assert_equal "127.0.0.1", @r.nodes[0]._client.host
28
- assert_equal PORT, @r.nodes[0]._client.port
29
- assert_equal 15, @r.nodes[0]._client.db
30
- assert_equal 10, @r.nodes[0]._client.timeout
31
- assert_equal logger, @r.nodes[0]._client.logger
32
-
33
- @r.add_node("redis://127.0.0.1:6380/14")
34
-
35
- assert_equal "127.0.0.1", @r.nodes[1]._client.host
36
- assert_equal 6380, @r.nodes[1]._client.port
37
- assert_equal 14, @r.nodes[1]._client.db
38
- assert_equal 10, @r.nodes[1]._client.timeout
39
- assert_equal logger, @r.nodes[1]._client.logger
40
- end
41
-
42
- def test_pipelining_commands_cannot_be_distributed
43
- assert_raise Redis::Distributed::CannotDistribute do
44
- r.pipelined do
45
- r.lpush "foo", "s1"
46
- r.lpush "foo", "s2"
47
- end
48
- end
49
- end
50
-
51
- def test_unknown_commands_does_not_work_by_default
52
- assert_raise NoMethodError do
53
- r.not_yet_implemented_command
54
- end
55
- end
56
- end
@@ -1,30 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestDistributedTransactions < Test::Unit::TestCase
4
-
5
- include Helper::Distributed
6
-
7
- def test_multi_discard
8
- @foo = nil
9
-
10
- assert_raise Redis::Distributed::CannotDistribute do
11
- r.multi { @foo = 1 }
12
- end
13
-
14
- assert_equal nil, @foo
15
-
16
- assert_raise Redis::Distributed::CannotDistribute do
17
- r.discard
18
- end
19
- end
20
-
21
- def test_watch_unwatch
22
- assert_raise Redis::Distributed::CannotDistribute do
23
- r.watch("foo")
24
- end
25
-
26
- assert_raise Redis::Distributed::CannotDistribute do
27
- r.unwatch
28
- end
29
- end
30
- end
@@ -1,14 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestEncoding < Test::Unit::TestCase
4
-
5
- include Helper::Client
6
-
7
- def test_returns_properly_encoded_strings
8
- with_external_encoding("UTF-8") do
9
- r.set "foo", "שלום"
10
-
11
- assert_equal "Shalom שלום", "Shalom " + r.get("foo")
12
- end
13
- end
14
- end
@@ -1,57 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestErrorReplies < Test::Unit::TestCase
4
-
5
- include Helper::Client
6
-
7
- # Every test shouldn't disconnect from the server. Also, when error replies are
8
- # in play, the protocol should never get into an invalid state where there are
9
- # pending replies in the connection. Calling INFO after every test ensures that
10
- # the protocol is still in a valid state.
11
- def with_reconnection_check
12
- before = r.info["total_connections_received"]
13
- yield(r)
14
- after = r.info["total_connections_received"]
15
- ensure
16
- assert_equal before, after
17
- end
18
-
19
- def test_error_reply_for_single_command
20
- with_reconnection_check do
21
- begin
22
- r.unknown_command
23
- rescue => ex
24
- ensure
25
- assert ex.message =~ /unknown command/i
26
- end
27
- end
28
- end
29
-
30
- def test_raise_first_error_reply_in_pipeline
31
- with_reconnection_check do
32
- begin
33
- r.pipelined do
34
- r.set("foo", "s1")
35
- r.incr("foo") # not an integer
36
- r.lpush("foo", "value") # wrong kind of value
37
- end
38
- rescue => ex
39
- ensure
40
- assert ex.message =~ /not an integer/i
41
- end
42
- end
43
- end
44
-
45
- def test_recover_from_raise_in__call_loop
46
- with_reconnection_check do
47
- begin
48
- r._client.call_loop([:invalid_monitor]) do
49
- assert false # Should never be executed
50
- end
51
- rescue => ex
52
- ensure
53
- assert ex.message =~ /unknown command/i
54
- end
55
- end
56
- end
57
- end
@@ -1,60 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestForkSafety < Test::Unit::TestCase
4
-
5
- include Helper::Client
6
-
7
- driver(:ruby, :hiredis) do
8
- def test_fork_safety
9
- redis = Redis.new(OPTIONS)
10
- redis.set "foo", 1
11
-
12
- child_pid = fork do
13
- begin
14
- # InheritedError triggers a reconnect,
15
- # so we need to disable reconnects to force
16
- # the exception bubble up
17
- redis.without_reconnect do
18
- redis.set "foo", 2
19
- end
20
- rescue Redis::InheritedError
21
- exit 127
22
- end
23
- end
24
-
25
- _, status = Process.wait2(child_pid)
26
-
27
- assert_equal 127, status.exitstatus
28
- assert_equal "1", redis.get("foo")
29
-
30
- rescue NotImplementedError => error
31
- raise unless error.message =~ /fork is not available/
32
- end
33
-
34
- def test_fork_safety_with_enabled_inherited_socket
35
- redis = Redis.new(OPTIONS.merge(:inherit_socket => true))
36
- redis.set "foo", 1
37
-
38
- child_pid = fork do
39
- begin
40
- # InheritedError triggers a reconnect,
41
- # so we need to disable reconnects to force
42
- # the exception bubble up
43
- redis.without_reconnect do
44
- redis.set "foo", 2
45
- end
46
- rescue Redis::InheritedError
47
- exit 127
48
- end
49
- end
50
-
51
- _, status = Process.wait2(child_pid)
52
-
53
- assert_equal 0, status.exitstatus
54
- assert_equal "2", redis.get("foo")
55
-
56
- rescue NotImplementedError => error
57
- raise unless error.message =~ /fork is not available/
58
- end
59
- end
60
- end
@@ -1,344 +0,0 @@
1
- require "test/unit"
2
- require "logger"
3
- require "stringio"
4
-
5
- $VERBOSE = true
6
-
7
- ENV["DRIVER"] ||= "ruby"
8
-
9
- require_relative "../lib/redis"
10
- require_relative "../lib/redis/distributed"
11
- require_relative "../lib/redis/connection/#{ENV["DRIVER"]}"
12
-
13
- require_relative "support/redis_mock"
14
- require_relative "support/connection/#{ENV["DRIVER"]}"
15
- require_relative 'support/cluster/orchestrator'
16
-
17
- PORT = 6381
18
- OPTIONS = {:port => PORT, :db => 15, :timeout => Float(ENV["TIMEOUT"] || 0.1)}
19
- NODES = ["redis://127.0.0.1:#{PORT}/15"]
20
-
21
- def driver(*drivers, &blk)
22
- if drivers.map(&:to_s).include?(ENV["DRIVER"])
23
- class_eval(&blk)
24
- end
25
- end
26
-
27
- module Helper
28
-
29
- def run(runner)
30
- if respond_to?(:around)
31
- around { super(runner) }
32
- else
33
- super
34
- end
35
- end
36
-
37
- def silent
38
- verbose, $VERBOSE = $VERBOSE, false
39
-
40
- begin
41
- yield
42
- ensure
43
- $VERBOSE = verbose
44
- end
45
- end
46
-
47
- def with_external_encoding(encoding)
48
- original_encoding = Encoding.default_external
49
-
50
- begin
51
- silent { Encoding.default_external = Encoding.find(encoding) }
52
- yield
53
- ensure
54
- silent { Encoding.default_external = original_encoding }
55
- end
56
- end
57
-
58
- class Version
59
-
60
- include Comparable
61
-
62
- attr :parts
63
-
64
- def initialize(v)
65
- case v
66
- when Version
67
- @parts = v.parts
68
- else
69
- @parts = v.to_s.split(".")
70
- end
71
- end
72
-
73
- def <=>(other)
74
- other = Version.new(other)
75
- length = [self.parts.length, other.parts.length].max
76
- length.times do |i|
77
- a, b = self.parts[i], other.parts[i]
78
-
79
- return -1 if a.nil?
80
- return +1 if b.nil?
81
- return a.to_i <=> b.to_i if a != b
82
- end
83
-
84
- 0
85
- end
86
- end
87
-
88
- module Generic
89
-
90
- include Helper
91
-
92
- attr_reader :log
93
- attr_reader :redis
94
-
95
- alias :r :redis
96
-
97
- def setup
98
- @log = StringIO.new
99
- @redis = init _new_client
100
-
101
- # Run GC to make sure orphaned connections are closed.
102
- GC.start
103
- end
104
-
105
- def teardown
106
- @redis.quit if @redis
107
- end
108
-
109
- def init(redis)
110
- redis.select 14
111
- redis.flushdb
112
- redis.select 15
113
- redis.flushdb
114
- redis
115
- rescue Redis::CannotConnectError
116
- puts <<-MSG
117
-
118
- Cannot connect to Redis.
119
-
120
- Make sure Redis is running on localhost, port #{PORT}.
121
- This testing suite connects to the database 15.
122
-
123
- Try this once:
124
-
125
- $ make clean
126
-
127
- Then run the build again:
128
-
129
- $ make
130
-
131
- MSG
132
- exit 1
133
- end
134
-
135
- def redis_mock(commands, options = {}, &blk)
136
- RedisMock.start(commands, options) do |port|
137
- yield _new_client(options.merge(:port => port))
138
- end
139
- end
140
-
141
- def redis_mock_with_handler(handler, options = {}, &blk)
142
- RedisMock.start_with_handler(handler, options) do |port|
143
- yield _new_client(options.merge(:port => port))
144
- end
145
- end
146
-
147
- def assert_in_range(range, value)
148
- assert range.include?(value), "expected #{value} to be in #{range.inspect}"
149
- end
150
-
151
- def target_version(target)
152
- if version < target
153
- skip("Requires Redis > #{target}") if respond_to?(:skip)
154
- else
155
- yield
156
- end
157
- end
158
-
159
- def version
160
- Version.new(redis.info['redis_version'])
161
- end
162
- end
163
-
164
- module Client
165
-
166
- include Generic
167
-
168
- private
169
-
170
- def _format_options(options)
171
- OPTIONS.merge(:logger => ::Logger.new(@log)).merge(options)
172
- end
173
-
174
- def _new_client(options = {})
175
- Redis.new(_format_options(options).merge(:driver => ENV["DRIVER"]))
176
- end
177
- end
178
-
179
- module Distributed
180
-
181
- include Generic
182
-
183
- def version
184
- Version.new(redis.info.first["redis_version"])
185
- end
186
-
187
- private
188
-
189
- def _format_options(options)
190
- {
191
- :timeout => OPTIONS[:timeout],
192
- :logger => ::Logger.new(@log),
193
- }.merge(options)
194
- end
195
-
196
- def _new_client(options = {})
197
- Redis::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
198
- end
199
- end
200
-
201
- module Cluster
202
- include Generic
203
-
204
- DEFAULT_HOST = '127.0.0.1'
205
- DEFAULT_PORTS = (7000..7005).freeze
206
-
207
- ClusterSlotsRawReply = lambda { |host, port|
208
- # @see https://redis.io/topics/protocol
209
- <<-REPLY.delete(' ')
210
- *1\r
211
- *4\r
212
- :0\r
213
- :16383\r
214
- *3\r
215
- $#{host.size}\r
216
- #{host}\r
217
- :#{port}\r
218
- $40\r
219
- 649fa246273043021a05f547a79478597d3f1dc5\r
220
- *3\r
221
- $#{host.size}\r
222
- #{host}\r
223
- :#{port}\r
224
- $40\r
225
- 649fa246273043021a05f547a79478597d3f1dc5\r
226
- REPLY
227
- }
228
-
229
- ClusterNodesRawReply = lambda { |host, port|
230
- line = "649fa246273043021a05f547a79478597d3f1dc5 #{host}:#{port}@17000 "\
231
- 'myself,master - 0 1530797742000 1 connected 0-16383'
232
- "$#{line.size}\r\n#{line}\r\n"
233
- }
234
-
235
- def init(redis)
236
- redis.flushall
237
- redis
238
- rescue Redis::CannotConnectError
239
- puts <<-MSG
240
-
241
- Cannot connect to Redis Cluster.
242
-
243
- Make sure Redis is running on localhost, port #{DEFAULT_PORTS}.
244
-
245
- Try this once:
246
-
247
- $ make stop_cluster
248
-
249
- Then run the build again:
250
-
251
- $ make
252
-
253
- MSG
254
- exit 1
255
- end
256
-
257
- def build_another_client(options = {})
258
- _new_client(options)
259
- end
260
-
261
- def redis_cluster_mock(commands, options = {})
262
- host = DEFAULT_HOST
263
- port = nil
264
-
265
- cluster_subcommands = if commands.key?(:cluster)
266
- commands.delete(:cluster)
267
- .map { |k, v| [k.to_s.downcase, v] }
268
- .to_h
269
- else
270
- {}
271
- end
272
-
273
- commands[:cluster] = lambda { |subcommand, *args|
274
- if cluster_subcommands.key?(subcommand)
275
- cluster_subcommands[subcommand].call(*args)
276
- else
277
- case subcommand
278
- when 'slots' then ClusterSlotsRawReply.call(host, port)
279
- when 'nodes' then ClusterNodesRawReply.call(host, port)
280
- else '+OK'
281
- end
282
- end
283
- }
284
-
285
- commands[:command] = ->(*_) { "*0\r\n" }
286
-
287
- RedisMock.start(commands, options) do |po|
288
- port = po
289
- scheme = options[:ssl] ? 'rediss' : 'redis'
290
- nodes = %W[#{scheme}://#{host}:#{port}]
291
- yield _new_client(options.merge(cluster: nodes))
292
- end
293
- end
294
-
295
- def redis_cluster_down
296
- trib = ClusterOrchestrator.new(_default_nodes)
297
- trib.down
298
- yield
299
- ensure
300
- trib.rebuild
301
- trib.close
302
- end
303
-
304
- def redis_cluster_failover
305
- trib = ClusterOrchestrator.new(_default_nodes)
306
- trib.failover
307
- yield
308
- ensure
309
- trib.rebuild
310
- trib.close
311
- end
312
-
313
- # @param slot [Integer]
314
- # @param src [String] <ip>:<port>
315
- # @param dest [String] <ip>:<port>
316
- def redis_cluster_resharding(slot, src:, dest:)
317
- trib = ClusterOrchestrator.new(_default_nodes)
318
- trib.start_resharding(slot, src, dest)
319
- yield
320
- trib.finish_resharding(slot, dest)
321
- ensure
322
- trib.rebuild
323
- trib.close
324
- end
325
-
326
- private
327
-
328
- def _default_nodes(host: DEFAULT_HOST, ports: DEFAULT_PORTS)
329
- ports.map { |port| "redis://#{host}:#{port}" }
330
- end
331
-
332
- def _format_options(options)
333
- {
334
- timeout: OPTIONS[:timeout],
335
- logger: ::Logger.new(@log),
336
- cluster: _default_nodes
337
- }.merge(options)
338
- end
339
-
340
- def _new_client(options = {})
341
- Redis.new(_format_options(options).merge(driver: ENV['DRIVER']))
342
- end
343
- end
344
- end