redis 3.3.5 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +132 -2
  3. data/README.md +144 -79
  4. data/lib/redis.rb +1174 -405
  5. data/lib/redis/client.rb +150 -90
  6. data/lib/redis/cluster.rb +295 -0
  7. data/lib/redis/cluster/command.rb +81 -0
  8. data/lib/redis/cluster/command_loader.rb +34 -0
  9. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  10. data/lib/redis/cluster/node.rb +107 -0
  11. data/lib/redis/cluster/node_key.rb +31 -0
  12. data/lib/redis/cluster/node_loader.rb +37 -0
  13. data/lib/redis/cluster/option.rb +93 -0
  14. data/lib/redis/cluster/slot.rb +86 -0
  15. data/lib/redis/cluster/slot_loader.rb +49 -0
  16. data/lib/redis/connection.rb +4 -2
  17. data/lib/redis/connection/command_helper.rb +5 -10
  18. data/lib/redis/connection/hiredis.rb +6 -5
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +126 -128
  21. data/lib/redis/connection/synchrony.rb +21 -8
  22. data/lib/redis/distributed.rb +147 -72
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +30 -73
  25. data/lib/redis/pipeline.rb +55 -15
  26. data/lib/redis/subscribe.rb +11 -12
  27. data/lib/redis/version.rb +3 -1
  28. metadata +49 -202
  29. data/.gitignore +0 -16
  30. data/.travis.yml +0 -89
  31. data/.travis/Gemfile +0 -11
  32. data/.yardopts +0 -3
  33. data/Gemfile +0 -4
  34. data/Rakefile +0 -87
  35. data/benchmarking/logging.rb +0 -71
  36. data/benchmarking/pipeline.rb +0 -51
  37. data/benchmarking/speed.rb +0 -21
  38. data/benchmarking/suite.rb +0 -24
  39. data/benchmarking/worker.rb +0 -71
  40. data/examples/basic.rb +0 -15
  41. data/examples/consistency.rb +0 -114
  42. data/examples/dist_redis.rb +0 -43
  43. data/examples/incr-decr.rb +0 -17
  44. data/examples/list.rb +0 -26
  45. data/examples/pubsub.rb +0 -37
  46. data/examples/sentinel.rb +0 -41
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sets.rb +0 -36
  50. data/examples/unicorn/config.ru +0 -3
  51. data/examples/unicorn/unicorn.rb +0 -20
  52. data/redis.gemspec +0 -44
  53. data/test/bitpos_test.rb +0 -69
  54. data/test/blocking_commands_test.rb +0 -42
  55. data/test/client_test.rb +0 -59
  56. data/test/command_map_test.rb +0 -30
  57. data/test/commands_on_hashes_test.rb +0 -21
  58. data/test/commands_on_hyper_log_log_test.rb +0 -21
  59. data/test/commands_on_lists_test.rb +0 -20
  60. data/test/commands_on_sets_test.rb +0 -77
  61. data/test/commands_on_sorted_sets_test.rb +0 -137
  62. data/test/commands_on_strings_test.rb +0 -101
  63. data/test/commands_on_value_types_test.rb +0 -133
  64. data/test/connection_handling_test.rb +0 -277
  65. data/test/connection_test.rb +0 -57
  66. data/test/db/.gitkeep +0 -0
  67. data/test/distributed_blocking_commands_test.rb +0 -46
  68. data/test/distributed_commands_on_hashes_test.rb +0 -10
  69. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  70. data/test/distributed_commands_on_lists_test.rb +0 -22
  71. data/test/distributed_commands_on_sets_test.rb +0 -83
  72. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  73. data/test/distributed_commands_on_strings_test.rb +0 -59
  74. data/test/distributed_commands_on_value_types_test.rb +0 -95
  75. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  76. data/test/distributed_connection_handling_test.rb +0 -23
  77. data/test/distributed_internals_test.rb +0 -79
  78. data/test/distributed_key_tags_test.rb +0 -52
  79. data/test/distributed_persistence_control_commands_test.rb +0 -26
  80. data/test/distributed_publish_subscribe_test.rb +0 -92
  81. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  82. data/test/distributed_scripting_test.rb +0 -102
  83. data/test/distributed_sorting_test.rb +0 -20
  84. data/test/distributed_test.rb +0 -58
  85. data/test/distributed_transactions_test.rb +0 -32
  86. data/test/encoding_test.rb +0 -18
  87. data/test/error_replies_test.rb +0 -59
  88. data/test/fork_safety_test.rb +0 -65
  89. data/test/helper.rb +0 -232
  90. data/test/helper_test.rb +0 -24
  91. data/test/internals_test.rb +0 -417
  92. data/test/lint/blocking_commands.rb +0 -150
  93. data/test/lint/hashes.rb +0 -162
  94. data/test/lint/hyper_log_log.rb +0 -60
  95. data/test/lint/lists.rb +0 -143
  96. data/test/lint/sets.rb +0 -140
  97. data/test/lint/sorted_sets.rb +0 -316
  98. data/test/lint/strings.rb +0 -260
  99. data/test/lint/value_types.rb +0 -122
  100. data/test/persistence_control_commands_test.rb +0 -26
  101. data/test/pipelining_commands_test.rb +0 -242
  102. data/test/publish_subscribe_test.rb +0 -282
  103. data/test/remote_server_control_commands_test.rb +0 -118
  104. data/test/scanning_test.rb +0 -413
  105. data/test/scripting_test.rb +0 -78
  106. data/test/sentinel_command_test.rb +0 -80
  107. data/test/sentinel_test.rb +0 -255
  108. data/test/sorting_test.rb +0 -59
  109. data/test/ssl_test.rb +0 -73
  110. data/test/support/connection/hiredis.rb +0 -1
  111. data/test/support/connection/ruby.rb +0 -1
  112. data/test/support/connection/synchrony.rb +0 -17
  113. data/test/support/redis_mock.rb +0 -130
  114. data/test/support/ssl/gen_certs.sh +0 -31
  115. data/test/support/ssl/trusted-ca.crt +0 -25
  116. data/test/support/ssl/trusted-ca.key +0 -27
  117. data/test/support/ssl/trusted-cert.crt +0 -81
  118. data/test/support/ssl/trusted-cert.key +0 -28
  119. data/test/support/ssl/untrusted-ca.crt +0 -26
  120. data/test/support/ssl/untrusted-ca.key +0 -27
  121. data/test/support/ssl/untrusted-cert.crt +0 -82
  122. data/test/support/ssl/untrusted-cert.key +0 -28
  123. data/test/support/wire/synchrony.rb +0 -24
  124. data/test/support/wire/thread.rb +0 -5
  125. data/test/synchrony_driver.rb +0 -88
  126. data/test/test.conf.erb +0 -9
  127. data/test/thread_safety_test.rb +0 -62
  128. data/test/transactions_test.rb +0 -264
  129. data/test/unknown_commands_test.rb +0 -14
  130. data/test/url_param_test.rb +0 -138
@@ -1,78 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class TestScripting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def to_sha(script)
10
- r.script(:load, script)
11
- end
12
-
13
- def test_script_exists
14
- target_version "2.5.9" do # 2.6-rc1
15
- a = to_sha("return 1")
16
- b = a.succ
17
-
18
- assert_equal true, r.script(:exists, a)
19
- assert_equal false, r.script(:exists, b)
20
- assert_equal [true], r.script(:exists, [a])
21
- assert_equal [false], r.script(:exists, [b])
22
- assert_equal [true, false], r.script(:exists, [a, b])
23
- end
24
- end
25
-
26
- def test_script_flush
27
- target_version "2.5.9" do # 2.6-rc1
28
- sha = to_sha("return 1")
29
- assert r.script(:exists, sha)
30
- assert_equal "OK", r.script(:flush)
31
- assert !r.script(:exists, sha)
32
- end
33
- end
34
-
35
- def test_script_kill
36
- target_version "2.5.9" do # 2.6-rc1
37
- redis_mock(:script => lambda { |arg| "+#{arg.upcase}" }) do |redis|
38
- assert_equal "KILL", redis.script(:kill)
39
- end
40
- end
41
- end
42
-
43
- def test_eval
44
- target_version "2.5.9" do # 2.6-rc1
45
- assert_equal 0, r.eval("return #KEYS")
46
- assert_equal 0, r.eval("return #ARGV")
47
- assert_equal ["k1", "k2"], r.eval("return KEYS", ["k1", "k2"])
48
- assert_equal ["a1", "a2"], r.eval("return ARGV", [], ["a1", "a2"])
49
- end
50
- end
51
-
52
- def test_eval_with_options_hash
53
- target_version "2.5.9" do # 2.6-rc1
54
- assert_equal 0, r.eval("return #KEYS", {})
55
- assert_equal 0, r.eval("return #ARGV", {})
56
- assert_equal ["k1", "k2"], r.eval("return KEYS", { :keys => ["k1", "k2"] })
57
- assert_equal ["a1", "a2"], r.eval("return ARGV", { :argv => ["a1", "a2"] })
58
- end
59
- end
60
-
61
- def test_evalsha
62
- target_version "2.5.9" do # 2.6-rc1
63
- assert_equal 0, r.evalsha(to_sha("return #KEYS"))
64
- assert_equal 0, r.evalsha(to_sha("return #ARGV"))
65
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), ["k1", "k2"])
66
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), [], ["a1", "a2"])
67
- end
68
- end
69
-
70
- def test_evalsha_with_options_hash
71
- target_version "2.5.9" do # 2.6-rc1
72
- assert_equal 0, r.evalsha(to_sha("return #KEYS"), {})
73
- assert_equal 0, r.evalsha(to_sha("return #ARGV"), {})
74
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), { :keys => ["k1", "k2"] })
75
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), { :argv => ["a1", "a2"] })
76
- end
77
- end
78
- end
@@ -1,80 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class SentinelCommandsTest < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_sentinel_command_master
10
-
11
- handler = lambda do |id|
12
- {
13
- :sentinel => lambda do |command, *args|
14
- ["name", "master1", "ip", "127.0.0.1"]
15
- end
16
- }
17
- end
18
-
19
- RedisMock.start(handler.call(:s1)) do |port|
20
- redis = Redis.new(:host => "127.0.0.1", :port => port)
21
-
22
- result = redis.sentinel('master', 'master1')
23
- assert_equal result, { "name" => "master1", "ip" => "127.0.0.1" }
24
- end
25
- end
26
-
27
- def test_sentinel_command_masters
28
-
29
- handler = lambda do |id|
30
- {
31
- :sentinel => lambda do |command, *args|
32
- [%w[name master1 ip 127.0.0.1 port 6381], %w[name master1 ip 127.0.0.1 port 6382]]
33
- end
34
- }
35
- end
36
-
37
- RedisMock.start(handler.call(:s1)) do |port|
38
- redis = Redis.new(:host => "127.0.0.1", :port => port)
39
-
40
- result = redis.sentinel('masters')
41
- assert_equal result[0], { "name" => "master1", "ip" => "127.0.0.1", "port" => "6381" }
42
- assert_equal result[1], { "name" => "master1", "ip" => "127.0.0.1", "port" => "6382" }
43
- end
44
- end
45
-
46
- def test_sentinel_command_get_master_by_name
47
-
48
- handler = lambda do |id|
49
- {
50
- :sentinel => lambda do |command, *args|
51
- ["127.0.0.1", "6381"]
52
- end
53
- }
54
- end
55
-
56
- RedisMock.start(handler.call(:s1)) do |port|
57
- redis = Redis.new(:host => "127.0.0.1", :port => port)
58
-
59
- result = redis.sentinel('get-master-addr-by-name', 'master1')
60
- assert_equal result, ["127.0.0.1", "6381"]
61
- end
62
- end
63
-
64
- def test_sentinel_command_ckquorum
65
- handler = lambda do |id|
66
- {
67
- :sentinel => lambda do |command, *args|
68
- "+OK 2 usable Sentinels. Quorum and failover authorization can be reached"
69
- end
70
- }
71
- end
72
-
73
- RedisMock.start(handler.call(:s1)) do |port|
74
- redis = Redis.new(:host => "127.0.0.1", :port => port)
75
-
76
- result = redis.sentinel('ckquorum', 'master1')
77
- assert_equal result, "OK 2 usable Sentinels. Quorum and failover authorization can be reached"
78
- end
79
- end
80
- end
@@ -1,255 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class SentinelTest < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_sentinel_connection
10
- sentinels = [{:host => "127.0.0.1", :port => 26381},
11
- {:host => "127.0.0.1", :port => 26382}]
12
-
13
- commands = {
14
- :s1 => [],
15
- :s2 => [],
16
- }
17
-
18
- handler = lambda do |id|
19
- {
20
- :sentinel => lambda do |command, *args|
21
- commands[id] << [command, *args]
22
- ["127.0.0.1", "6381"]
23
- end
24
- }
25
- end
26
-
27
- RedisMock.start(handler.call(:s1)) do |s1_port|
28
- RedisMock.start(handler.call(:s2)) do |s2_port|
29
- sentinels[0][:port] = s1_port
30
- sentinels[1][:port] = s2_port
31
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master)
32
-
33
- assert redis.ping
34
- end
35
- end
36
-
37
- assert_equal commands[:s1], [%w[get-master-addr-by-name master1]]
38
- assert_equal commands[:s2], []
39
- end
40
-
41
- def test_sentinel_failover
42
- sentinels = [{:host => "127.0.0.1", :port => 26381},
43
- {:host => "127.0.0.1", :port => 26382}]
44
-
45
- commands = {
46
- :s1 => [],
47
- :s2 => [],
48
- }
49
-
50
- s1 = {
51
- :sentinel => lambda do |command, *args|
52
- commands[:s1] << [command, *args]
53
- "$-1" # Nil
54
- end
55
- }
56
-
57
- s2 = {
58
- :sentinel => lambda do |command, *args|
59
- commands[:s2] << [command, *args]
60
- ["127.0.0.1", "6381"]
61
- end
62
- }
63
-
64
- RedisMock.start(s1) do |s1_port|
65
- RedisMock.start(s2) do |s2_port|
66
- sentinels[0][:port] = s1_port
67
- sentinels[1][:port] = s2_port
68
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master)
69
-
70
- assert redis.ping
71
- end
72
- end
73
-
74
- assert_equal commands[:s1], [%w[get-master-addr-by-name master1]]
75
- assert_equal commands[:s2], [%w[get-master-addr-by-name master1]]
76
- end
77
-
78
- def test_sentinel_failover_prioritize_healthy_sentinel
79
- sentinels = [{:host => "127.0.0.1", :port => 26381},
80
- {:host => "127.0.0.1", :port => 26382}]
81
-
82
- commands = {
83
- :s1 => [],
84
- :s2 => [],
85
- }
86
-
87
- s1 = {
88
- :sentinel => lambda do |command, *args|
89
- commands[:s1] << [command, *args]
90
- "$-1" # Nil
91
- end
92
- }
93
-
94
- s2 = {
95
- :sentinel => lambda do |command, *args|
96
- commands[:s2] << [command, *args]
97
- ["127.0.0.1", "6381"]
98
- end
99
- }
100
-
101
- RedisMock.start(s1) do |s1_port|
102
- RedisMock.start(s2) do |s2_port|
103
- sentinels[0][:port] = s1_port
104
- sentinels[1][:port] = s2_port
105
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master)
106
-
107
- assert redis.ping
108
-
109
- redis.quit
110
-
111
- assert redis.ping
112
- end
113
- end
114
-
115
- assert_equal commands[:s1], [%w[get-master-addr-by-name master1]]
116
- assert_equal commands[:s2], [%w[get-master-addr-by-name master1], %w[get-master-addr-by-name master1]]
117
- end
118
-
119
- def test_sentinel_with_non_sentinel_options
120
- sentinels = [{:host => "127.0.0.1", :port => 26381}]
121
-
122
- commands = {
123
- :s1 => [],
124
- :m1 => []
125
- }
126
-
127
- sentinel = lambda do |port|
128
- {
129
- :auth => lambda do |pass|
130
- commands[:s1] << ["auth", pass]
131
- "-ERR unknown command 'auth'"
132
- end,
133
- :select => lambda do |db|
134
- commands[:s1] << ["select", db]
135
- "-ERR unknown command 'select'"
136
- end,
137
- :sentinel => lambda do |command, *args|
138
- commands[:s1] << [command, *args]
139
- ["127.0.0.1", port.to_s]
140
- end
141
- }
142
- end
143
-
144
- master = {
145
- :auth => lambda do |pass|
146
- commands[:m1] << ["auth", pass]
147
- "+OK"
148
- end,
149
- :role => lambda do
150
- commands[:m1] << ["role"]
151
- ["master"]
152
- end
153
- }
154
-
155
- RedisMock.start(master) do |master_port|
156
- RedisMock.start(sentinel.call(master_port)) do |sen_port|
157
- sentinels[0][:port] = sen_port
158
- redis = Redis.new(:url => "redis://:foo@master1/15", :sentinels => sentinels, :role => :master)
159
-
160
- assert redis.ping
161
- end
162
- end
163
-
164
- assert_equal [%w[get-master-addr-by-name master1]], commands[:s1]
165
- assert_equal [%w[auth foo], %w[role]], commands[:m1]
166
- end
167
-
168
- def test_sentinel_role_mismatch
169
- sentinels = [{:host => "127.0.0.1", :port => 26381}]
170
-
171
- sentinel = lambda do |port|
172
- {
173
- :sentinel => lambda do |command, *args|
174
- ["127.0.0.1", port.to_s]
175
- end
176
- }
177
- end
178
-
179
- master = {
180
- :role => lambda do
181
- ["slave"]
182
- end
183
- }
184
-
185
- ex = assert_raise(Redis::ConnectionError) do
186
- RedisMock.start(master) do |master_port|
187
- RedisMock.start(sentinel.call(master_port)) do |sen_port|
188
- sentinels[0][:port] = sen_port
189
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master)
190
-
191
- assert redis.ping
192
- end
193
- end
194
- end
195
-
196
- assert_match(/Instance role mismatch/, ex.message)
197
- end
198
-
199
- def test_sentinel_retries
200
- sentinels = [{:host => "127.0.0.1", :port => 26381},
201
- {:host => "127.0.0.1", :port => 26382}]
202
-
203
- connections = []
204
-
205
- handler = lambda do |id, port|
206
- {
207
- :sentinel => lambda do |command, *args|
208
- connections << id
209
-
210
- if connections.count(id) < 2
211
- :close
212
- else
213
- ["127.0.0.1", port.to_s]
214
- end
215
- end
216
- }
217
- end
218
-
219
- master = {
220
- :role => lambda do
221
- ["master"]
222
- end
223
- }
224
-
225
- RedisMock.start(master) do |master_port|
226
- RedisMock.start(handler.call(:s1, master_port)) do |s1_port|
227
- RedisMock.start(handler.call(:s2, master_port)) do |s2_port|
228
- sentinels[0][:port] = s1_port
229
- sentinels[1][:port] = s2_port
230
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master, :reconnect_attempts => 1)
231
-
232
- assert redis.ping
233
- end
234
- end
235
- end
236
-
237
- assert_equal [:s1, :s2, :s1], connections
238
-
239
- connections.clear
240
-
241
- ex = assert_raise(Redis::CannotConnectError) do
242
- RedisMock.start(master) do |master_port|
243
- RedisMock.start(handler.call(:s1, master_port)) do |s1_port|
244
- RedisMock.start(handler.call(:s2, master_port)) do |s2_port|
245
- redis = Redis.new(:url => "redis://master1", :sentinels => sentinels, :role => :master, :reconnect_attempts => 0)
246
-
247
- assert redis.ping
248
- end
249
- end
250
- end
251
- end
252
-
253
- assert_match(/No sentinels available/, ex.message)
254
- end
255
- end
data/test/sorting_test.rb DELETED
@@ -1,59 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
4
-
5
- class TestSorting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_sort
10
- r.set("foo:1", "s1")
11
- r.set("foo:2", "s2")
12
-
13
- r.rpush("bar", "1")
14
- r.rpush("bar", "2")
15
-
16
- assert_equal ["s1"], r.sort("bar", :get => "foo:*", :limit => [0, 1])
17
- assert_equal ["s2"], r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
18
- end
19
-
20
- def test_sort_with_an_array_of_gets
21
- r.set("foo:1:a", "s1a")
22
- r.set("foo:1:b", "s1b")
23
-
24
- r.set("foo:2:a", "s2a")
25
- r.set("foo:2:b", "s2b")
26
-
27
- r.rpush("bar", "1")
28
- r.rpush("bar", "2")
29
-
30
- assert_equal [["s1a", "s1b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
31
- assert_equal [["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
32
- assert_equal [["s1a", "s1b"], ["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"])
33
- end
34
-
35
- def test_sort_with_store
36
- r.set("foo:1", "s1")
37
- r.set("foo:2", "s2")
38
-
39
- r.rpush("bar", "1")
40
- r.rpush("bar", "2")
41
-
42
- r.sort("bar", :get => "foo:*", :store => "baz")
43
- assert_equal ["s1", "s2"], r.lrange("baz", 0, -1)
44
- end
45
-
46
- def test_sort_with_an_array_of_gets_and_with_store
47
- r.set("foo:1:a", "s1a")
48
- r.set("foo:1:b", "s1b")
49
-
50
- r.set("foo:2:a", "s2a")
51
- r.set("foo:2:b", "s2b")
52
-
53
- r.rpush("bar", "1")
54
- r.rpush("bar", "2")
55
-
56
- r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :store => 'baz')
57
- assert_equal ["s1a", "s1b", "s2a", "s2b"], r.lrange("baz", 0, -1)
58
- end
59
- end