redis 3.0.0 → 4.2.2

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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +269 -0
  3. data/README.md +295 -58
  4. data/lib/redis.rb +1760 -451
  5. data/lib/redis/client.rb +355 -88
  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 +90 -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 +12 -8
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +232 -63
  21. data/lib/redis/connection/synchrony.rb +41 -14
  22. data/lib/redis/distributed.rb +205 -70
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +31 -73
  25. data/lib/redis/pipeline.rb +74 -18
  26. data/lib/redis/subscribe.rb +24 -13
  27. data/lib/redis/version.rb +3 -1
  28. metadata +63 -160
  29. data/.gitignore +0 -10
  30. data/.order +0 -169
  31. data/.travis.yml +0 -50
  32. data/.travis/Gemfile +0 -11
  33. data/.yardopts +0 -3
  34. data/Rakefile +0 -392
  35. data/benchmarking/logging.rb +0 -62
  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/dist_redis.rb +0 -43
  42. data/examples/incr-decr.rb +0 -17
  43. data/examples/list.rb +0 -26
  44. data/examples/pubsub.rb +0 -31
  45. data/examples/sets.rb +0 -36
  46. data/examples/unicorn/config.ru +0 -3
  47. data/examples/unicorn/unicorn.rb +0 -20
  48. data/redis.gemspec +0 -41
  49. data/test/blocking_commands_test.rb +0 -42
  50. data/test/command_map_test.rb +0 -30
  51. data/test/commands_on_hashes_test.rb +0 -21
  52. data/test/commands_on_lists_test.rb +0 -20
  53. data/test/commands_on_sets_test.rb +0 -77
  54. data/test/commands_on_sorted_sets_test.rb +0 -109
  55. data/test/commands_on_strings_test.rb +0 -83
  56. data/test/commands_on_value_types_test.rb +0 -99
  57. data/test/connection_handling_test.rb +0 -189
  58. data/test/db/.gitignore +0 -1
  59. data/test/distributed_blocking_commands_test.rb +0 -46
  60. data/test/distributed_commands_on_hashes_test.rb +0 -10
  61. data/test/distributed_commands_on_lists_test.rb +0 -22
  62. data/test/distributed_commands_on_sets_test.rb +0 -83
  63. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  64. data/test/distributed_commands_on_strings_test.rb +0 -48
  65. data/test/distributed_commands_on_value_types_test.rb +0 -87
  66. data/test/distributed_commands_requiring_clustering_test.rb +0 -148
  67. data/test/distributed_connection_handling_test.rb +0 -23
  68. data/test/distributed_internals_test.rb +0 -15
  69. data/test/distributed_key_tags_test.rb +0 -52
  70. data/test/distributed_persistence_control_commands_test.rb +0 -26
  71. data/test/distributed_publish_subscribe_test.rb +0 -92
  72. data/test/distributed_remote_server_control_commands_test.rb +0 -53
  73. data/test/distributed_scripting_test.rb +0 -102
  74. data/test/distributed_sorting_test.rb +0 -20
  75. data/test/distributed_test.rb +0 -58
  76. data/test/distributed_transactions_test.rb +0 -32
  77. data/test/encoding_test.rb +0 -18
  78. data/test/error_replies_test.rb +0 -59
  79. data/test/helper.rb +0 -188
  80. data/test/helper_test.rb +0 -22
  81. data/test/internals_test.rb +0 -214
  82. data/test/lint/blocking_commands.rb +0 -124
  83. data/test/lint/hashes.rb +0 -162
  84. data/test/lint/lists.rb +0 -143
  85. data/test/lint/sets.rb +0 -96
  86. data/test/lint/sorted_sets.rb +0 -201
  87. data/test/lint/strings.rb +0 -157
  88. data/test/lint/value_types.rb +0 -106
  89. data/test/persistence_control_commands_test.rb +0 -26
  90. data/test/pipelining_commands_test.rb +0 -195
  91. data/test/publish_subscribe_test.rb +0 -153
  92. data/test/remote_server_control_commands_test.rb +0 -104
  93. data/test/scripting_test.rb +0 -78
  94. data/test/sorting_test.rb +0 -45
  95. data/test/support/connection/hiredis.rb +0 -1
  96. data/test/support/connection/ruby.rb +0 -1
  97. data/test/support/connection/synchrony.rb +0 -17
  98. data/test/support/redis_mock.rb +0 -92
  99. data/test/support/wire/synchrony.rb +0 -24
  100. data/test/support/wire/thread.rb +0 -5
  101. data/test/synchrony_driver.rb +0 -57
  102. data/test/test.conf +0 -9
  103. data/test/thread_safety_test.rb +0 -32
  104. data/test/transactions_test.rb +0 -244
  105. data/test/unknown_commands_test.rb +0 -14
  106. data/test/url_param_test.rb +0 -64
@@ -1,20 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestDistributedSorting < Test::Unit::TestCase
6
-
7
- include Helper::Distributed
8
-
9
- def test_sort
10
- assert_raise(Redis::Distributed::CannotDistribute) do
11
- r.set("foo:1", "s1")
12
- r.set("foo:2", "s2")
13
-
14
- r.rpush("bar", "1")
15
- r.rpush("bar", "2")
16
-
17
- r.sort("bar", :get => "foo:*", :limit => [0, 1])
18
- end
19
- end
20
- end
@@ -1,58 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestDistributed < Test::Unit::TestCase
6
-
7
- include Helper::Distributed
8
-
9
- def test_handle_multiple_servers
10
- @r = Redis::Distributed.new ["redis://localhost:#{PORT}/15", *NODES]
11
-
12
- 100.times do |idx|
13
- @r.set(idx.to_s, "foo#{idx}")
14
- end
15
-
16
- 100.times do |idx|
17
- assert_equal "foo#{idx}", @r.get(idx.to_s)
18
- end
19
-
20
- assert_equal "0", @r.keys("*").sort.first
21
- assert_equal "string", @r.type("1")
22
- end
23
-
24
- def test_add_nodes
25
- logger = Logger.new("/dev/null")
26
-
27
- @r = Redis::Distributed.new NODES, :logger => logger, :timeout => 10
28
-
29
- assert_equal "127.0.0.1", @r.nodes[0].client.host
30
- assert_equal PORT, @r.nodes[0].client.port
31
- assert_equal 15, @r.nodes[0].client.db
32
- assert_equal 10, @r.nodes[0].client.timeout
33
- assert_equal logger, @r.nodes[0].client.logger
34
-
35
- @r.add_node("redis://localhost:6380/14")
36
-
37
- assert_equal "localhost", @r.nodes[1].client.host
38
- assert_equal 6380, @r.nodes[1].client.port
39
- assert_equal 14, @r.nodes[1].client.db
40
- assert_equal 10, @r.nodes[1].client.timeout
41
- assert_equal logger, @r.nodes[1].client.logger
42
- end
43
-
44
- def test_pipelining_commands_cannot_be_distributed
45
- assert_raise Redis::Distributed::CannotDistribute do
46
- r.pipelined do
47
- r.lpush "foo", "s1"
48
- r.lpush "foo", "s2"
49
- end
50
- end
51
- end
52
-
53
- def test_unknown_commands_does_not_work_by_default
54
- assert_raise NoMethodError do
55
- r.not_yet_implemented_command
56
- end
57
- end
58
- end
@@ -1,32 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestDistributedTransactions < Test::Unit::TestCase
6
-
7
- include Helper::Distributed
8
-
9
- def test_multi_discard
10
- @foo = nil
11
-
12
- assert_raise Redis::Distributed::CannotDistribute do
13
- r.multi { @foo = 1 }
14
- end
15
-
16
- assert_equal nil, @foo
17
-
18
- assert_raise Redis::Distributed::CannotDistribute do
19
- r.discard
20
- end
21
- end
22
-
23
- def test_watch_unwatch
24
- assert_raise Redis::Distributed::CannotDistribute do
25
- r.watch("foo")
26
- end
27
-
28
- assert_raise Redis::Distributed::CannotDistribute do
29
- r.unwatch
30
- end
31
- end
32
- end
@@ -1,18 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestEncoding < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_returns_properly_encoded_strings
10
- if defined?(Encoding)
11
- with_external_encoding("UTF-8") do
12
- r.set "foo", "שלום"
13
-
14
- assert_equal "Shalom שלום", "Shalom " + r.get("foo")
15
- end
16
- end
17
- end
18
- end
@@ -1,59 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestErrorReplies < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- # Every test shouldn't disconnect from the server. Also, when error replies are
10
- # in play, the protocol should never get into an invalid state where there are
11
- # pending replies in the connection. Calling INFO after every test ensures that
12
- # the protocol is still in a valid state.
13
- def with_reconnection_check
14
- before = r.info["total_connections_received"]
15
- yield(r)
16
- after = r.info["total_connections_received"]
17
- ensure
18
- assert_equal before, after
19
- end
20
-
21
- def test_error_reply_for_single_command
22
- with_reconnection_check do
23
- begin
24
- r.unknown_command
25
- rescue => ex
26
- ensure
27
- assert ex.message =~ /unknown command/i
28
- end
29
- end
30
- end
31
-
32
- def test_raise_first_error_reply_in_pipeline
33
- with_reconnection_check do
34
- begin
35
- r.pipelined do
36
- r.set("foo", "s1")
37
- r.incr("foo") # not an integer
38
- r.lpush("foo", "value") # wrong kind of value
39
- end
40
- rescue => ex
41
- ensure
42
- assert ex.message =~ /not an integer/i
43
- end
44
- end
45
- end
46
-
47
- def test_recover_from_raise_in__call_loop
48
- with_reconnection_check do
49
- begin
50
- r.client.call_loop([:invalid_monitor]) do
51
- assert false # Should never be executed
52
- end
53
- rescue => ex
54
- ensure
55
- assert ex.message =~ /unknown command/i
56
- end
57
- end
58
- end
59
- end
@@ -1,188 +0,0 @@
1
- $:.unshift File.expand_path('../lib', File.dirname(__FILE__))
2
-
3
- require "test/unit"
4
- require "logger"
5
- require "stringio"
6
-
7
- begin
8
- require "ruby-debug"
9
- rescue LoadError
10
- end
11
-
12
- $VERBOSE = true
13
-
14
- ENV["conn"] ||= "ruby"
15
-
16
- require "redis"
17
- require "redis/distributed"
18
- require "redis/connection/#{ENV["conn"]}"
19
-
20
- require "support/redis_mock"
21
- require "support/connection/#{ENV["conn"]}"
22
-
23
- PORT = 6381
24
- OPTIONS = {:port => PORT, :db => 15, :timeout => 0.1}
25
- NODES = ["redis://127.0.0.1:#{PORT}/15"]
26
-
27
- def init(redis)
28
- begin
29
- redis.select 14
30
- redis.flushdb
31
- redis.select 15
32
- redis.flushdb
33
- redis
34
- rescue Redis::CannotConnectError
35
- puts <<-EOS
36
-
37
- Cannot connect to Redis.
38
-
39
- Make sure Redis is running on localhost, port #{PORT}.
40
- This testing suite connects to the database 15.
41
-
42
- To install redis:
43
- visit <http://redis.io/download/>.
44
-
45
- To start the server:
46
- rake start
47
-
48
- To stop the server:
49
- rake stop
50
-
51
- EOS
52
- exit 1
53
- end
54
- end
55
-
56
- def driver(*drivers, &blk)
57
- if drivers.map(&:to_s).include?(ENV["conn"])
58
- class_eval(&blk)
59
- end
60
- end
61
-
62
- module Helper
63
-
64
- def run(runner)
65
- if respond_to?(:around)
66
- around { super(runner) }
67
- else
68
- super
69
- end
70
- end
71
-
72
- def silent
73
- verbose, $VERBOSE = $VERBOSE, false
74
-
75
- begin
76
- yield
77
- ensure
78
- $VERBOSE = verbose
79
- end
80
- end
81
-
82
- def with_external_encoding(encoding)
83
- original_encoding = Encoding.default_external
84
-
85
- begin
86
- silent { Encoding.default_external = Encoding.find(encoding) }
87
- yield
88
- ensure
89
- silent { Encoding.default_external = original_encoding }
90
- end
91
- end
92
-
93
- class Version
94
-
95
- include Comparable
96
-
97
- attr :parts
98
-
99
- def initialize(v)
100
- case v
101
- when Version
102
- @parts = v.parts
103
- else
104
- @parts = v.to_s.split(".")
105
- end
106
- end
107
-
108
- def <=>(other)
109
- other = Version.new(other)
110
- length = [self.parts.length, other.parts.length].max
111
- length.times do |i|
112
- a, b = self.parts[i], other.parts[i]
113
-
114
- return -1 if a.nil?
115
- return +1 if b.nil?
116
- return a <=> b if a != b
117
- end
118
-
119
- 0
120
- end
121
- end
122
-
123
- module Generic
124
-
125
- include Helper
126
-
127
- attr_reader :log
128
- attr_reader :redis
129
-
130
- alias :r :redis
131
-
132
- def setup
133
- @log = StringIO.new
134
- @redis = init _new_client
135
- end
136
-
137
- def teardown
138
- @redis.quit if @redis
139
- end
140
-
141
- def redis_mock(commands, options = {}, &blk)
142
- RedisMock.start(commands) do |port|
143
- yield _new_client(options.merge(:port => port))
144
- end
145
- end
146
- end
147
-
148
- module Client
149
-
150
- include Generic
151
-
152
- def version
153
- Version.new(redis.info["redis_version"])
154
- end
155
-
156
- private
157
-
158
- def _format_options(options)
159
- OPTIONS.merge(:logger => ::Logger.new(@log)).merge(options)
160
- end
161
-
162
- def _new_client(options = {})
163
- Redis.new(_format_options(options))
164
- end
165
- end
166
-
167
- module Distributed
168
-
169
- include Generic
170
-
171
- def version
172
- Version.new(redis.info.first["redis_version"])
173
- end
174
-
175
- private
176
-
177
- def _format_options(options)
178
- {
179
- :timeout => OPTIONS[:timeout],
180
- :logger => ::Logger.new(@log),
181
- }.merge(options)
182
- end
183
-
184
- def _new_client(options = {})
185
- Redis::Distributed.new(NODES, _format_options(options))
186
- end
187
- end
188
- end
@@ -1,22 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestHelper < Test::Unit::TestCase
6
-
7
- include Helper
8
-
9
- def test_version_comparison
10
- v = Version.new("2.0.0")
11
-
12
- assert v < "3"
13
- assert v > "1"
14
- assert v > "2"
15
-
16
- assert v < "2.1"
17
- assert v < "2.0.1"
18
- assert v < "2.0.0.1"
19
-
20
- assert v == "2.0.0"
21
- end
22
- end
@@ -1,214 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestInternals < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_logger
10
- r.ping
11
-
12
- assert log.string =~ /Redis >> PING/
13
- assert log.string =~ /Redis >> \d+\.\d+ms/
14
- end
15
-
16
- def test_logger_with_pipelining
17
- r.pipelined do
18
- r.set "foo", "bar"
19
- r.get "foo"
20
- end
21
-
22
- assert log.string["SET foo bar"]
23
- assert log.string["GET foo"]
24
- end
25
-
26
- def test_recovers_from_failed_commands
27
- # See https://github.com/redis/redis-rb/issues#issue/28
28
-
29
- assert_raise(Redis::CommandError) do
30
- r.command_that_doesnt_exist
31
- end
32
-
33
- assert_nothing_raised do
34
- r.info
35
- end
36
- end
37
-
38
- def test_raises_on_protocol_errors
39
- redis_mock(:ping => lambda { |*_| "foo" }) do |redis|
40
- assert_raise(Redis::ProtocolError) do
41
- redis.ping
42
- end
43
- end
44
- end
45
-
46
- def test_provides_a_meaningful_inspect
47
- assert_equal "#<Redis client v#{Redis::VERSION} for redis://127.0.0.1:#{PORT}/15>", r.inspect
48
- end
49
-
50
- def test_redis_current
51
- assert_equal "127.0.0.1", Redis.current.client.host
52
- assert_equal 6379, Redis.current.client.port
53
- assert_equal 0, Redis.current.client.db
54
-
55
- Redis.current = Redis.new(OPTIONS.merge(:port => 6380, :db => 1))
56
-
57
- t = Thread.new do
58
- assert_equal "127.0.0.1", Redis.current.client.host
59
- assert_equal 6380, Redis.current.client.port
60
- assert_equal 1, Redis.current.client.db
61
- end
62
-
63
- t.join
64
-
65
- assert_equal "127.0.0.1", Redis.current.client.host
66
- assert_equal 6380, Redis.current.client.port
67
- assert_equal 1, Redis.current.client.db
68
- end
69
-
70
- def test_default_id_with_host_and_port
71
- redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
72
- assert_equal "redis://host:1234/0", redis.client.id
73
- end
74
-
75
- def test_default_id_with_host_and_port_and_explicit_scheme
76
- redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0, :scheme => "foo"))
77
- assert_equal "redis://host:1234/0", redis.client.id
78
- end
79
-
80
- def test_default_id_with_path
81
- redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0))
82
- assert_equal "redis:///tmp/redis.sock/0", redis.client.id
83
- end
84
-
85
- def test_default_id_with_path_and_explicit_scheme
86
- redis = Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock", :db => 0, :scheme => "foo"))
87
- assert_equal "redis:///tmp/redis.sock/0", redis.client.id
88
- end
89
-
90
- def test_override_id
91
- redis = Redis.new(OPTIONS.merge(:id => "test"))
92
- assert_equal redis.client.id, "test"
93
- end
94
-
95
- def test_timeout
96
- assert_nothing_raised do
97
- Redis.new(OPTIONS.merge(:timeout => 0))
98
- end
99
- end
100
-
101
- def test_time
102
- return if version < "2.5.4"
103
-
104
- # Test that the difference between the time that Ruby reports and the time
105
- # that Redis reports is minimal (prevents the test from being racy).
106
- rv = r.time
107
-
108
- redis_usec = rv[0] * 1_000_000 + rv[1]
109
- ruby_usec = Integer(Time.now.to_f * 1_000_000)
110
-
111
- assert 500_000 > (ruby_usec - redis_usec).abs
112
- end
113
-
114
- def test_connection_timeout
115
- assert_raise Redis::CannotConnectError do
116
- Redis.new(OPTIONS.merge(:host => "10.255.255.254", :timeout => 0.1)).ping
117
- end
118
- end
119
-
120
- def close_on_ping(seq)
121
- $request = 0
122
-
123
- command = lambda do
124
- idx = $request
125
- $request += 1
126
-
127
- rv = "+%d" % idx
128
- rv = nil if seq.include?(idx)
129
- rv
130
- end
131
-
132
- redis_mock(:ping => command, :timeout => 0.1) do |redis|
133
- yield(redis)
134
- end
135
- end
136
-
137
- def test_retry_by_default
138
- close_on_ping([0]) do |redis|
139
- assert_equal "1", redis.ping
140
- end
141
- end
142
-
143
- def test_retry_when_wrapped_in_with_reconnect_true
144
- close_on_ping([0]) do |redis|
145
- redis.with_reconnect(true) do
146
- assert_equal "1", redis.ping
147
- end
148
- end
149
- end
150
-
151
- def test_dont_retry_when_wrapped_in_with_reconnect_false
152
- close_on_ping([0]) do |redis|
153
- assert_raise Redis::ConnectionError do
154
- redis.with_reconnect(false) do
155
- redis.ping
156
- end
157
- end
158
- end
159
- end
160
-
161
- def test_dont_retry_when_wrapped_in_without_reconnect
162
- close_on_ping([0]) do |redis|
163
- assert_raise Redis::ConnectionError do
164
- redis.without_reconnect do
165
- redis.ping
166
- end
167
- end
168
- end
169
- end
170
-
171
- def test_retry_only_once_when_read_raises_econnreset
172
- close_on_ping([0, 1]) do |redis|
173
- assert_raise Redis::ConnectionError do
174
- redis.ping
175
- end
176
-
177
- assert !redis.client.connected?
178
- end
179
- end
180
-
181
- def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
182
- close_on_ping([1]) do |redis|
183
- assert_raise Redis::ConnectionError do
184
- redis.pipelined do
185
- redis.ping
186
- redis.ping # Second #read times out
187
- end
188
- end
189
-
190
- assert !redis.client.connected?
191
- end
192
- end
193
-
194
- def test_connecting_to_unix_domain_socket
195
- assert_nothing_raised do
196
- Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock")).ping
197
- end
198
- end
199
-
200
- driver(:ruby, :hiredis) do
201
- def test_bubble_timeout_without_retrying
202
- serv = TCPServer.new(6380)
203
-
204
- redis = Redis.new(:port => 6380, :timeout => 0.1)
205
-
206
- assert_raise(Redis::TimeoutError) do
207
- redis.ping
208
- end
209
-
210
- ensure
211
- serv.close if serv
212
- end
213
- end
214
- end