redis 2.2.0 → 2.2.1
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.
- data/CHANGELOG.md +16 -1
- data/README.md +18 -0
- data/Rakefile +3 -5
- data/TODO.md +4 -0
- data/lib/redis.rb +135 -119
- data/lib/redis/client.rb +29 -6
- data/lib/redis/connection/command_helper.rb +2 -2
- data/lib/redis/connection/ruby.rb +6 -2
- data/lib/redis/connection/synchrony.rb +9 -5
- data/lib/redis/distributed.rb +9 -2
- data/lib/redis/pipeline.rb +16 -1
- data/lib/redis/subscribe.rb +19 -4
- data/lib/redis/version.rb +1 -1
- data/test/connection_handling_test.rb +2 -1
- data/test/distributed_internals_test.rb +10 -1
- data/test/distributed_remote_server_control_commands_test.rb +12 -0
- data/test/distributed_test.rb +0 -1
- data/test/error_replies_test.rb +1 -1
- data/test/internals_test.rb +4 -1
- data/test/lint/internals.rb +0 -4
- data/test/remote_server_control_commands_test.rb +19 -0
- metadata +4 -3
data/lib/redis/client.rb
CHANGED
|
@@ -21,8 +21,8 @@ class Redis
|
|
|
21
21
|
|
|
22
22
|
def connect
|
|
23
23
|
establish_connection
|
|
24
|
-
call
|
|
25
|
-
call
|
|
24
|
+
call [:auth, @password] if @password
|
|
25
|
+
call [:select, @db] if @db != 0
|
|
26
26
|
self
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -34,17 +34,40 @@ class Redis
|
|
|
34
34
|
@path || "#{@host}:#{@port}"
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# Starting with 2.2.1, assume that this method is called with a single
|
|
38
|
+
# array argument. Check its size for backwards compat.
|
|
37
39
|
def call(*args)
|
|
38
|
-
|
|
40
|
+
if args.first.is_a?(Array) && args.size == 1
|
|
41
|
+
command = args.first
|
|
42
|
+
else
|
|
43
|
+
command = args
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
reply = process([command]) { read }
|
|
39
47
|
raise reply if reply.is_a?(RuntimeError)
|
|
40
48
|
reply
|
|
41
49
|
end
|
|
42
50
|
|
|
51
|
+
# Assume that this method is called with a single array argument. No
|
|
52
|
+
# backwards compat here, since it was introduced in 2.2.2.
|
|
53
|
+
def call_without_reply(command)
|
|
54
|
+
process([command])
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Starting with 2.2.1, assume that this method is called with a single
|
|
59
|
+
# array argument. Check its size for backwards compat.
|
|
43
60
|
def call_loop(*args)
|
|
61
|
+
if args.first.is_a?(Array) && args.size == 1
|
|
62
|
+
command = args.first
|
|
63
|
+
else
|
|
64
|
+
command = args
|
|
65
|
+
end
|
|
66
|
+
|
|
44
67
|
error = nil
|
|
45
68
|
|
|
46
69
|
result = without_socket_timeout do
|
|
47
|
-
process(
|
|
70
|
+
process([command]) do
|
|
48
71
|
loop do
|
|
49
72
|
reply = read
|
|
50
73
|
if reply.is_a?(RuntimeError)
|
|
@@ -74,7 +97,7 @@ class Redis
|
|
|
74
97
|
# read, retrying would re-execute the entire pipeline, thus re-issueing
|
|
75
98
|
# already succesfully executed commands. To circumvent this, don't retry
|
|
76
99
|
# after the first reply has been read succesfully.
|
|
77
|
-
first = process(
|
|
100
|
+
first = process(commands) { read }
|
|
78
101
|
error = first if first.is_a?(RuntimeError)
|
|
79
102
|
|
|
80
103
|
begin
|
|
@@ -109,7 +132,7 @@ class Redis
|
|
|
109
132
|
retry
|
|
110
133
|
end
|
|
111
134
|
|
|
112
|
-
def process(
|
|
135
|
+
def process(commands)
|
|
113
136
|
logging(commands) do
|
|
114
137
|
ensure_connected do
|
|
115
138
|
commands.each do |command|
|
|
@@ -4,7 +4,7 @@ class Redis
|
|
|
4
4
|
|
|
5
5
|
COMMAND_DELIMITER = "\r\n"
|
|
6
6
|
|
|
7
|
-
def build_command(
|
|
7
|
+
def build_command(args)
|
|
8
8
|
command = []
|
|
9
9
|
command << "*#{args.size}"
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@ class Redis
|
|
|
16
16
|
|
|
17
17
|
# Trailing delimiter
|
|
18
18
|
command << ""
|
|
19
|
-
command
|
|
19
|
+
command.join(COMMAND_DELIMITER)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
protected
|
|
@@ -55,7 +55,7 @@ class Redis
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def write(command)
|
|
58
|
-
@sock.
|
|
58
|
+
@sock.write(build_command(command))
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def read
|
|
@@ -116,7 +116,11 @@ class Redis
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
rescue LoadError
|
|
119
|
-
|
|
119
|
+
if ! defined?(RUBY_ENGINE)
|
|
120
|
+
# MRI 1.8, all other interpreters define RUBY_ENGINE, JRuby and
|
|
121
|
+
# Rubinius should have no issues with timeout.
|
|
122
|
+
warn "WARNING: using the built-in Timeout class which is known to have issues when used for opening connections. Install the SystemTimer gem if you want to make sure the Redis client will not hang."
|
|
123
|
+
end
|
|
120
124
|
|
|
121
125
|
require "timeout"
|
|
122
126
|
|
|
@@ -10,13 +10,19 @@ class Redis
|
|
|
10
10
|
|
|
11
11
|
def post_init
|
|
12
12
|
@req = nil
|
|
13
|
+
@connected = false
|
|
13
14
|
@reader = ::Hiredis::Reader.new
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def connection_completed
|
|
18
|
+
@connected = true
|
|
17
19
|
succeed
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
def connected?
|
|
23
|
+
@connected
|
|
24
|
+
end
|
|
25
|
+
|
|
20
26
|
def receive_data(data)
|
|
21
27
|
@reader.feed(data)
|
|
22
28
|
|
|
@@ -39,6 +45,7 @@ class Redis
|
|
|
39
45
|
end
|
|
40
46
|
|
|
41
47
|
def unbind
|
|
48
|
+
@connected = false
|
|
42
49
|
if @req
|
|
43
50
|
@req.fail [:error, Errno::ECONNRESET]
|
|
44
51
|
@req = nil
|
|
@@ -53,12 +60,11 @@ class Redis
|
|
|
53
60
|
|
|
54
61
|
def initialize
|
|
55
62
|
@timeout = 5_000_000
|
|
56
|
-
@state = :disconnected
|
|
57
63
|
@connection = nil
|
|
58
64
|
end
|
|
59
65
|
|
|
60
66
|
def connected?
|
|
61
|
-
@
|
|
67
|
+
@connection && @connection.connected?
|
|
62
68
|
end
|
|
63
69
|
|
|
64
70
|
def timeout=(usecs)
|
|
@@ -79,13 +85,12 @@ class Redis
|
|
|
79
85
|
end
|
|
80
86
|
|
|
81
87
|
def disconnect
|
|
82
|
-
@state = :disconnected
|
|
83
88
|
@connection.close_connection
|
|
84
89
|
@connection = nil
|
|
85
90
|
end
|
|
86
91
|
|
|
87
92
|
def write(command)
|
|
88
|
-
@connection.send(build_command(
|
|
93
|
+
@connection.send(build_command(command))
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
def read
|
|
@@ -105,7 +110,6 @@ class Redis
|
|
|
105
110
|
def setup_connect_callbacks(conn, f)
|
|
106
111
|
conn.callback do
|
|
107
112
|
@connection = conn
|
|
108
|
-
@state = :connected
|
|
109
113
|
f.resume conn
|
|
110
114
|
end
|
|
111
115
|
|
data/lib/redis/distributed.rb
CHANGED
|
@@ -637,8 +637,8 @@ class Redis
|
|
|
637
637
|
end
|
|
638
638
|
|
|
639
639
|
# Get information and statistics about the server.
|
|
640
|
-
def info
|
|
641
|
-
on_each_node :info
|
|
640
|
+
def info(cmd = nil)
|
|
641
|
+
on_each_node :info, cmd
|
|
642
642
|
end
|
|
643
643
|
|
|
644
644
|
# Listen for all requests received by the server in real time.
|
|
@@ -655,6 +655,13 @@ class Redis
|
|
|
655
655
|
raise CannotDistribute, :pipelined
|
|
656
656
|
end
|
|
657
657
|
|
|
658
|
+
def inspect
|
|
659
|
+
node_info = nodes.map do |node|
|
|
660
|
+
"#{node.id} (Redis v#{node.info['redis_version']})"
|
|
661
|
+
end
|
|
662
|
+
"#<Redis client v#{Redis::VERSION} connected to #{node_info.join(', ')}>"
|
|
663
|
+
end
|
|
664
|
+
|
|
658
665
|
protected
|
|
659
666
|
|
|
660
667
|
def on_each_node(command, *args)
|
data/lib/redis/pipeline.rb
CHANGED
|
@@ -6,8 +6,23 @@ class Redis
|
|
|
6
6
|
@commands = []
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
# Starting with 2.2.1, assume that this method is called with a single
|
|
10
|
+
# array argument. Check its size for backwards compat.
|
|
9
11
|
def call(*args)
|
|
10
|
-
|
|
12
|
+
if args.first.is_a?(Array) && args.size == 1
|
|
13
|
+
command = args.first
|
|
14
|
+
else
|
|
15
|
+
command = args
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@commands << command
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Assume that this method is called with a single array argument. No
|
|
23
|
+
# backwards compat here, since it was introduced in 2.2.2.
|
|
24
|
+
def call_without_reply(command)
|
|
25
|
+
@commands.push command
|
|
11
26
|
nil
|
|
12
27
|
end
|
|
13
28
|
|
data/lib/redis/subscribe.rb
CHANGED
|
@@ -4,8 +4,23 @@ class Redis
|
|
|
4
4
|
@client = client
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
# Starting with 2.2.1, assume that this method is called with a single
|
|
8
|
+
# array argument. Check its size for backwards compat.
|
|
7
9
|
def call(*args)
|
|
8
|
-
|
|
10
|
+
if args.first.is_a?(Array) && args.size == 1
|
|
11
|
+
command = args.first
|
|
12
|
+
else
|
|
13
|
+
command = args
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@client.process([command])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Assume that this method is called with a single array argument. No
|
|
20
|
+
# backwards compat here, since it was introduced in 2.2.2.
|
|
21
|
+
def call_without_reply(command)
|
|
22
|
+
@commands.push command
|
|
23
|
+
nil
|
|
9
24
|
end
|
|
10
25
|
|
|
11
26
|
def subscribe(*channels, &block)
|
|
@@ -17,11 +32,11 @@ class Redis
|
|
|
17
32
|
end
|
|
18
33
|
|
|
19
34
|
def unsubscribe(*channels)
|
|
20
|
-
call
|
|
35
|
+
call [:unsubscribe, *channels]
|
|
21
36
|
end
|
|
22
37
|
|
|
23
38
|
def punsubscribe(*channels)
|
|
24
|
-
call
|
|
39
|
+
call [:punsubscribe, *channels]
|
|
25
40
|
end
|
|
26
41
|
|
|
27
42
|
protected
|
|
@@ -30,7 +45,7 @@ class Redis
|
|
|
30
45
|
sub = Subscription.new(&block)
|
|
31
46
|
|
|
32
47
|
begin
|
|
33
|
-
@client.call_loop(start, *channels) do |line|
|
|
48
|
+
@client.call_loop([start, *channels]) do |line|
|
|
34
49
|
type, *rest = line
|
|
35
50
|
sub.callbacks[type].call(*rest)
|
|
36
51
|
break if type == stop && rest.last == 0
|
data/lib/redis/version.rb
CHANGED
|
@@ -47,7 +47,8 @@ test "SHUTDOWN" do
|
|
|
47
47
|
redis_mock(:shutdown => lambda { "+SHUTDOWN" }) do
|
|
48
48
|
redis = Redis.new(OPTIONS.merge(:port => 6380))
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
# SHUTDOWN does not reply: test that it does not raise here.
|
|
51
|
+
assert nil == redis.shutdown
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
|
|
@@ -13,6 +13,15 @@ setup do
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
$TEST_PIPELINING = false
|
|
16
|
-
$TEST_INSPECT = false
|
|
17
16
|
|
|
18
17
|
load File.expand_path("./lint/internals.rb", File.dirname(__FILE__))
|
|
18
|
+
|
|
19
|
+
test "provides a meaningful inspect" do |r, _|
|
|
20
|
+
nodes = ["redis://localhost:6379/15", *NODES]
|
|
21
|
+
@r = Redis::Distributed.new nodes
|
|
22
|
+
|
|
23
|
+
node_info = nodes.map do |node|
|
|
24
|
+
"#{node} (Redis v#{@r.info.first["redis_version"]})"
|
|
25
|
+
end
|
|
26
|
+
assert "#<Redis client v#{Redis::VERSION} connected to #{node_info.join(', ')}>" == @r.inspect
|
|
27
|
+
end
|
|
@@ -16,6 +16,18 @@ test "INFO" do |r|
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
test "INFO COMMANDSTATS" do |r|
|
|
20
|
+
# Only available on Redis >= 2.3.0
|
|
21
|
+
next if r.info.first["redis_version"] < "2.3.0"
|
|
22
|
+
|
|
23
|
+
r.nodes.each { |n| n.config(:resetstat) }
|
|
24
|
+
r.ping # Executed on every node
|
|
25
|
+
|
|
26
|
+
r.info(:commandstats).each do |info|
|
|
27
|
+
assert "1" == info["ping"]["calls"]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
19
31
|
test "MONITOR" do |r|
|
|
20
32
|
begin
|
|
21
33
|
r.monitor
|
data/test/distributed_test.rb
CHANGED
data/test/error_replies_test.rb
CHANGED
data/test/internals_test.rb
CHANGED
|
@@ -12,10 +12,13 @@ setup do
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
$TEST_PIPELINING = true
|
|
15
|
-
$TEST_INSPECT = true
|
|
16
15
|
|
|
17
16
|
load File.expand_path("./lint/internals.rb", File.dirname(__FILE__))
|
|
18
17
|
|
|
18
|
+
test "provides a meaningful inspect" do |r, _|
|
|
19
|
+
assert "#<Redis client v#{Redis::VERSION} connected to redis://127.0.0.1:6379/15 (Redis v#{r.info["redis_version"]})>" == r.inspect
|
|
20
|
+
end
|
|
21
|
+
|
|
19
22
|
test "Redis.current" do
|
|
20
23
|
Redis.current.set("foo", "bar")
|
|
21
24
|
|
data/test/lint/internals.rb
CHANGED
|
@@ -27,10 +27,6 @@ test "Recovers from failed commands" do |r, _|
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
test "provides a meaningful inspect" do |r, _|
|
|
31
|
-
assert "#<Redis client v#{Redis::VERSION} connected to redis://127.0.0.1:6379/15 (Redis v#{r.info["redis_version"]})>" == r.inspect
|
|
32
|
-
end if $TEST_INSPECT
|
|
33
|
-
|
|
34
30
|
test "raises on protocol errors" do
|
|
35
31
|
redis_mock(:ping => lambda { |*_| "foo" }) do
|
|
36
32
|
assert_raise(Redis::ProtocolError) do
|
|
@@ -15,6 +15,17 @@ test "INFO" do |r|
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
test "INFO COMMANDSTATS" do |r|
|
|
19
|
+
# Only available on Redis >= 2.3.0
|
|
20
|
+
next if r.info["redis_version"] < "2.3.0"
|
|
21
|
+
|
|
22
|
+
r.config(:resetstat)
|
|
23
|
+
r.ping
|
|
24
|
+
|
|
25
|
+
result = r.info(:commandstats)
|
|
26
|
+
assert "1" == result["ping"]["calls"]
|
|
27
|
+
end
|
|
28
|
+
|
|
18
29
|
test "MONITOR" do |r|
|
|
19
30
|
log = []
|
|
20
31
|
|
|
@@ -52,6 +63,14 @@ test "DEBUG" do |r|
|
|
|
52
63
|
assert r.debug(:object, "foo").kind_of?(String)
|
|
53
64
|
end
|
|
54
65
|
|
|
66
|
+
test "OBJECT" do |r|
|
|
67
|
+
r.lpush "list", "value"
|
|
68
|
+
|
|
69
|
+
assert r.object(:refcount, "list") == 1
|
|
70
|
+
assert r.object(:encoding, "list") == "ziplist"
|
|
71
|
+
assert r.object(:idletime, "list").kind_of?(Fixnum)
|
|
72
|
+
end
|
|
73
|
+
|
|
55
74
|
test "SYNC" do |r|
|
|
56
75
|
replies = {:sync => lambda { "+OK" }}
|
|
57
76
|
|
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: redis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 2.2.
|
|
5
|
+
version: 2.2.1
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Ezra Zygmuntowicz
|
|
@@ -18,7 +18,7 @@ autorequire: redis
|
|
|
18
18
|
bindir: bin
|
|
19
19
|
cert_chain: []
|
|
20
20
|
|
|
21
|
-
date: 2011-
|
|
21
|
+
date: 2011-06-08 00:00:00 -03:00
|
|
22
22
|
default_executable:
|
|
23
23
|
dependencies: []
|
|
24
24
|
|
|
@@ -36,6 +36,7 @@ files:
|
|
|
36
36
|
- LICENSE
|
|
37
37
|
- README.md
|
|
38
38
|
- Rakefile
|
|
39
|
+
- TODO.md
|
|
39
40
|
- benchmarking/logging.rb
|
|
40
41
|
- benchmarking/pipeline.rb
|
|
41
42
|
- benchmarking/speed.rb
|
|
@@ -136,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
136
137
|
requirements: []
|
|
137
138
|
|
|
138
139
|
rubyforge_project: redis-rb
|
|
139
|
-
rubygems_version: 1.
|
|
140
|
+
rubygems_version: 1.6.2
|
|
140
141
|
signing_key:
|
|
141
142
|
specification_version: 3
|
|
142
143
|
summary: Ruby client library for Redis, the key value storage server
|