redis 3.3.3 → 5.0.5
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +280 -12
- data/README.md +141 -147
- data/lib/redis/client.rb +77 -539
- data/lib/redis/commands/bitmaps.rb +66 -0
- data/lib/redis/commands/cluster.rb +28 -0
- data/lib/redis/commands/connection.rb +53 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +254 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +437 -0
- data/lib/redis/commands/lists.rb +285 -0
- data/lib/redis/commands/pubsub.rb +54 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +214 -0
- data/lib/redis/commands/sorted_sets.rb +818 -0
- data/lib/redis/commands/streams.rb +384 -0
- data/lib/redis/commands/strings.rb +314 -0
- data/lib/redis/commands/transactions.rb +115 -0
- data/lib/redis/commands.rb +235 -0
- data/lib/redis/distributed.rb +300 -108
- data/lib/redis/errors.rb +22 -1
- data/lib/redis/hash_ring.rb +36 -79
- data/lib/redis/pipeline.rb +69 -83
- data/lib/redis/subscribe.rb +26 -19
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +113 -2685
- metadata +40 -218
- data/.gitignore +0 -16
- data/.travis/Gemfile +0 -11
- data/.travis.yml +0 -89
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -87
- data/benchmarking/logging.rb +0 -71
- data/benchmarking/pipeline.rb +0 -51
- data/benchmarking/speed.rb +0 -21
- data/benchmarking/suite.rb +0 -24
- data/benchmarking/worker.rb +0 -71
- data/examples/basic.rb +0 -15
- data/examples/consistency.rb +0 -114
- data/examples/dist_redis.rb +0 -43
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sentinel.rb +0 -41
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/lib/redis/connection/command_helper.rb +0 -44
- data/lib/redis/connection/hiredis.rb +0 -66
- data/lib/redis/connection/registry.rb +0 -12
- data/lib/redis/connection/ruby.rb +0 -429
- data/lib/redis/connection/synchrony.rb +0 -133
- data/lib/redis/connection.rb +0 -9
- data/redis.gemspec +0 -44
- data/test/bitpos_test.rb +0 -69
- data/test/blocking_commands_test.rb +0 -42
- data/test/client_test.rb +0 -59
- data/test/command_map_test.rb +0 -30
- data/test/commands_on_hashes_test.rb +0 -21
- data/test/commands_on_hyper_log_log_test.rb +0 -21
- data/test/commands_on_lists_test.rb +0 -20
- data/test/commands_on_sets_test.rb +0 -77
- data/test/commands_on_sorted_sets_test.rb +0 -137
- data/test/commands_on_strings_test.rb +0 -101
- data/test/commands_on_value_types_test.rb +0 -133
- data/test/connection_handling_test.rb +0 -277
- data/test/db/.gitkeep +0 -0
- data/test/distributed_blocking_commands_test.rb +0 -46
- data/test/distributed_commands_on_hashes_test.rb +0 -10
- data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
- data/test/distributed_commands_on_lists_test.rb +0 -22
- data/test/distributed_commands_on_sets_test.rb +0 -83
- data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
- data/test/distributed_commands_on_strings_test.rb +0 -59
- data/test/distributed_commands_on_value_types_test.rb +0 -95
- data/test/distributed_commands_requiring_clustering_test.rb +0 -164
- data/test/distributed_connection_handling_test.rb +0 -23
- data/test/distributed_internals_test.rb +0 -79
- data/test/distributed_key_tags_test.rb +0 -52
- data/test/distributed_persistence_control_commands_test.rb +0 -26
- data/test/distributed_publish_subscribe_test.rb +0 -92
- data/test/distributed_remote_server_control_commands_test.rb +0 -66
- data/test/distributed_scripting_test.rb +0 -102
- data/test/distributed_sorting_test.rb +0 -20
- data/test/distributed_test.rb +0 -58
- data/test/distributed_transactions_test.rb +0 -32
- data/test/encoding_test.rb +0 -18
- data/test/error_replies_test.rb +0 -59
- data/test/fork_safety_test.rb +0 -65
- data/test/helper.rb +0 -232
- data/test/helper_test.rb +0 -24
- data/test/internals_test.rb +0 -457
- data/test/lint/blocking_commands.rb +0 -150
- data/test/lint/hashes.rb +0 -162
- data/test/lint/hyper_log_log.rb +0 -60
- data/test/lint/lists.rb +0 -143
- data/test/lint/sets.rb +0 -140
- data/test/lint/sorted_sets.rb +0 -316
- data/test/lint/strings.rb +0 -260
- data/test/lint/value_types.rb +0 -122
- data/test/persistence_control_commands_test.rb +0 -26
- data/test/pipelining_commands_test.rb +0 -242
- data/test/publish_subscribe_test.rb +0 -282
- data/test/remote_server_control_commands_test.rb +0 -118
- data/test/scanning_test.rb +0 -413
- data/test/scripting_test.rb +0 -78
- data/test/sentinel_command_test.rb +0 -80
- data/test/sentinel_test.rb +0 -255
- data/test/sorting_test.rb +0 -59
- data/test/ssl_test.rb +0 -73
- data/test/support/connection/hiredis.rb +0 -1
- data/test/support/connection/ruby.rb +0 -1
- data/test/support/connection/synchrony.rb +0 -17
- data/test/support/redis_mock.rb +0 -130
- data/test/support/ssl/gen_certs.sh +0 -31
- data/test/support/ssl/trusted-ca.crt +0 -25
- data/test/support/ssl/trusted-ca.key +0 -27
- data/test/support/ssl/trusted-cert.crt +0 -81
- data/test/support/ssl/trusted-cert.key +0 -28
- data/test/support/ssl/untrusted-ca.crt +0 -26
- data/test/support/ssl/untrusted-ca.key +0 -27
- data/test/support/ssl/untrusted-cert.crt +0 -82
- data/test/support/ssl/untrusted-cert.key +0 -28
- data/test/support/wire/synchrony.rb +0 -24
- data/test/support/wire/thread.rb +0 -5
- data/test/synchrony_driver.rb +0 -88
- data/test/test.conf.erb +0 -9
- data/test/thread_safety_test.rb +0 -62
- data/test/transactions_test.rb +0 -264
- data/test/unknown_commands_test.rb +0 -14
- data/test/url_param_test.rb +0 -138
data/lib/redis/errors.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
# Base error for all redis-rb errors.
|
3
|
-
class BaseError <
|
5
|
+
class BaseError < StandardError
|
4
6
|
end
|
5
7
|
|
6
8
|
# Raised by the connection when a protocol error occurs.
|
@@ -18,6 +20,18 @@ class Redis
|
|
18
20
|
class CommandError < BaseError
|
19
21
|
end
|
20
22
|
|
23
|
+
class PermissionError < CommandError
|
24
|
+
end
|
25
|
+
|
26
|
+
class WrongTypeError < CommandError
|
27
|
+
end
|
28
|
+
|
29
|
+
class ReadOnlyError < CommandError
|
30
|
+
end
|
31
|
+
|
32
|
+
class OutOfMemoryError < CommandError
|
33
|
+
end
|
34
|
+
|
21
35
|
# Base error for connection related errors.
|
22
36
|
class BaseConnectionError < BaseError
|
23
37
|
end
|
@@ -37,4 +51,11 @@ class Redis
|
|
37
51
|
# Raised when the connection was inherited by a child process.
|
38
52
|
class InheritedError < BaseConnectionError
|
39
53
|
end
|
54
|
+
|
55
|
+
# Raised when client options are invalid.
|
56
|
+
class InvalidClientOptionError < BaseError
|
57
|
+
end
|
58
|
+
|
59
|
+
class SubscriptionError < BaseError
|
60
|
+
end
|
40
61
|
end
|
data/lib/redis/hash_ring.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'zlib'
|
4
|
+
require 'digest/md5'
|
2
5
|
|
3
6
|
class Redis
|
4
7
|
class HashRing
|
5
|
-
|
6
8
|
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
7
9
|
|
8
10
|
attr_reader :ring, :sorted_keys, :replicas, :nodes
|
@@ -10,7 +12,7 @@ class Redis
|
|
10
12
|
# nodes is a list of objects that have a proper to_s representation.
|
11
13
|
# replicas indicates how many virtual points should be used pr. node,
|
12
14
|
# replicas are required to improve the distribution.
|
13
|
-
def initialize(nodes=[], replicas=POINTS_PER_SERVER)
|
15
|
+
def initialize(nodes = [], replicas = POINTS_PER_SERVER)
|
14
16
|
@replicas = replicas
|
15
17
|
@ring = {}
|
16
18
|
@nodes = []
|
@@ -24,8 +26,7 @@ class Redis
|
|
24
26
|
def add_node(node)
|
25
27
|
@nodes << node
|
26
28
|
@replicas.times do |i|
|
27
|
-
key =
|
28
|
-
raise "Node ID collision" if @ring.has_key?(key)
|
29
|
+
key = server_hash_for("#{node.id}:#{i}")
|
29
30
|
@ring[key] = node
|
30
31
|
@sorted_keys << key
|
31
32
|
end
|
@@ -33,100 +34,56 @@ class Redis
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def remove_node(node)
|
36
|
-
@nodes.reject!{|n| n.id == node.id}
|
37
|
+
@nodes.reject! { |n| n.id == node.id }
|
37
38
|
@replicas.times do |i|
|
38
|
-
key =
|
39
|
+
key = server_hash_for("#{node.id}:#{i}")
|
39
40
|
@ring.delete(key)
|
40
|
-
@sorted_keys.reject! {|k| k == key}
|
41
|
+
@sorted_keys.reject! { |k| k == key }
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
45
|
# get the node in the hash ring for this key
|
45
46
|
def get_node(key)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
def get_node_pos(key)
|
50
|
-
return [nil,nil] if @ring.size == 0
|
51
|
-
crc = Zlib.crc32(key)
|
52
|
-
idx = HashRing.binary_search(@sorted_keys, crc)
|
53
|
-
return [@ring[@sorted_keys[idx]], idx]
|
47
|
+
hash = hash_for(key)
|
48
|
+
idx = binary_search(@sorted_keys, hash)
|
49
|
+
@ring[@sorted_keys[idx]]
|
54
50
|
end
|
55
51
|
|
56
52
|
def iter_nodes(key)
|
57
|
-
return [nil,nil] if @ring.
|
58
|
-
|
53
|
+
return [nil, nil] if @ring.empty?
|
54
|
+
|
55
|
+
crc = hash_for(key)
|
56
|
+
pos = binary_search(@sorted_keys, crc)
|
59
57
|
@ring.size.times do |n|
|
60
|
-
yield @ring[@sorted_keys[(pos+n) % @ring.size]]
|
58
|
+
yield @ring[@sorted_keys[(pos + n) % @ring.size]]
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
# gem install RubyInline to use this code
|
67
|
-
# Native extension to perform the binary search within the hashring.
|
68
|
-
# There's a pure ruby version below so this is purely optional
|
69
|
-
# for performance. In testing 20k gets and sets, the native
|
70
|
-
# binary search shaved about 12% off the runtime (9sec -> 8sec).
|
71
|
-
begin
|
72
|
-
require 'inline'
|
73
|
-
inline do |builder|
|
74
|
-
builder.c <<-EOM
|
75
|
-
int binary_search(VALUE ary, unsigned int r) {
|
76
|
-
int upper = RARRAY_LEN(ary) - 1;
|
77
|
-
int lower = 0;
|
78
|
-
int idx = 0;
|
79
|
-
|
80
|
-
while (lower <= upper) {
|
81
|
-
idx = (lower + upper) / 2;
|
62
|
+
private
|
82
63
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
return idx;
|
87
|
-
}
|
88
|
-
else if (l > r) {
|
89
|
-
upper = idx - 1;
|
90
|
-
}
|
91
|
-
else {
|
92
|
-
lower = idx + 1;
|
93
|
-
}
|
94
|
-
}
|
95
|
-
if (upper < 0) {
|
96
|
-
upper = RARRAY_LEN(ary) - 1;
|
97
|
-
}
|
98
|
-
return upper;
|
99
|
-
}
|
100
|
-
EOM
|
101
|
-
end
|
102
|
-
rescue Exception
|
103
|
-
# Find the closest index in HashRing with value <= the given value
|
104
|
-
def binary_search(ary, value, &block)
|
105
|
-
upper = ary.size - 1
|
106
|
-
lower = 0
|
107
|
-
idx = 0
|
108
|
-
|
109
|
-
while(lower <= upper) do
|
110
|
-
idx = (lower + upper) / 2
|
111
|
-
comp = ary[idx] <=> value
|
64
|
+
def hash_for(key)
|
65
|
+
Zlib.crc32(key)
|
66
|
+
end
|
112
67
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
upper = idx - 1
|
117
|
-
else
|
118
|
-
lower = idx + 1
|
119
|
-
end
|
120
|
-
end
|
68
|
+
def server_hash_for(key)
|
69
|
+
Digest::MD5.digest(key).unpack1("L>")
|
70
|
+
end
|
121
71
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
72
|
+
# Find the closest index in HashRing with value <= the given value
|
73
|
+
def binary_search(ary, value)
|
74
|
+
upper = ary.size
|
75
|
+
lower = 0
|
76
|
+
|
77
|
+
while lower < upper
|
78
|
+
mid = (lower + upper) / 2
|
79
|
+
if ary[mid] > value
|
80
|
+
upper = mid
|
81
|
+
else
|
82
|
+
lower = mid + 1
|
126
83
|
end
|
127
|
-
|
128
84
|
end
|
129
|
-
end
|
130
85
|
|
86
|
+
upper - 1
|
87
|
+
end
|
131
88
|
end
|
132
89
|
end
|
data/lib/redis/pipeline.rb
CHANGED
@@ -1,99 +1,72 @@
|
|
1
|
-
|
2
|
-
unless defined?(::BasicObject)
|
3
|
-
class BasicObject
|
4
|
-
instance_methods.each { |meth| undef_method(meth) unless meth =~ /\A(__|instance_eval)/ }
|
5
|
-
end
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
attr_accessor :db
|
3
|
+
require "delegate"
|
10
4
|
|
11
|
-
|
5
|
+
class Redis
|
6
|
+
class PipelinedConnection
|
7
|
+
attr_accessor :db
|
12
8
|
|
13
|
-
def initialize
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@futures = []
|
9
|
+
def initialize(pipeline, futures = [])
|
10
|
+
@pipeline = pipeline
|
11
|
+
@futures = futures
|
17
12
|
end
|
18
13
|
|
19
|
-
|
20
|
-
|
14
|
+
include Commands
|
15
|
+
|
16
|
+
def pipelined
|
17
|
+
yield self
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
24
|
-
|
20
|
+
def multi
|
21
|
+
transaction = MultiConnection.new(@pipeline, @futures)
|
22
|
+
send_command([:multi])
|
23
|
+
size = @futures.size
|
24
|
+
yield transaction
|
25
|
+
multi_future = MultiFuture.new(@futures[size..-1])
|
26
|
+
@pipeline.call_v([:exec]) do |result|
|
27
|
+
multi_future._set(result)
|
28
|
+
end
|
29
|
+
@futures << multi_future
|
30
|
+
multi_future
|
25
31
|
end
|
26
32
|
|
27
|
-
|
28
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def synchronize
|
36
|
+
yield self
|
29
37
|
end
|
30
38
|
|
31
|
-
def
|
32
|
-
# A pipeline that contains a shutdown should not raise ECONNRESET when
|
33
|
-
# the connection is gone.
|
34
|
-
@shutdown = true if command.first == :shutdown
|
39
|
+
def send_command(command, &block)
|
35
40
|
future = Future.new(command, block)
|
41
|
+
@pipeline.call_v(command) do |result|
|
42
|
+
future._set(result)
|
43
|
+
end
|
36
44
|
@futures << future
|
37
45
|
future
|
38
46
|
end
|
39
47
|
|
40
|
-
def
|
41
|
-
|
42
|
-
@
|
43
|
-
|
44
|
-
nil
|
45
|
-
end
|
46
|
-
|
47
|
-
def commands
|
48
|
-
@futures.map { |f| f._command }
|
49
|
-
end
|
50
|
-
|
51
|
-
def with_reconnect(val=true)
|
52
|
-
@with_reconnect = false unless val
|
53
|
-
yield
|
54
|
-
end
|
55
|
-
|
56
|
-
def without_reconnect(&blk)
|
57
|
-
with_reconnect(false, &blk)
|
58
|
-
end
|
59
|
-
|
60
|
-
def finish(replies, &blk)
|
61
|
-
if blk
|
62
|
-
futures.each_with_index.map do |future, i|
|
63
|
-
future._set(blk.call(replies[i]))
|
64
|
-
end
|
65
|
-
else
|
66
|
-
futures.each_with_index.map do |future, i|
|
67
|
-
future._set(replies[i])
|
68
|
-
end
|
48
|
+
def send_blocking_command(command, timeout, &block)
|
49
|
+
future = Future.new(command, block)
|
50
|
+
@pipeline.blocking_call_v(timeout, command) do |result|
|
51
|
+
future._set(result)
|
69
52
|
end
|
53
|
+
@futures << future
|
54
|
+
future
|
70
55
|
end
|
56
|
+
end
|
71
57
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
return if exec.nil? # The transaction failed because of WATCH.
|
77
|
-
|
78
|
-
# EXEC command failed.
|
79
|
-
raise exec if exec.is_a?(CommandError)
|
80
|
-
|
81
|
-
if exec.size < futures.size
|
82
|
-
# Some command wasn't recognized by Redis.
|
83
|
-
raise replies.detect { |r| r.is_a?(CommandError) }
|
84
|
-
end
|
58
|
+
class MultiConnection < PipelinedConnection
|
59
|
+
def multi
|
60
|
+
raise Redis::Error, "Can't nest multi transaction"
|
61
|
+
end
|
85
62
|
|
86
|
-
|
87
|
-
# Because an EXEC returns nested replies, hiredis won't be able to
|
88
|
-
# convert an error reply to a CommandError instance itself. This is
|
89
|
-
# specific to MULTI/EXEC, so we solve this here.
|
90
|
-
reply.is_a?(::RuntimeError) ? CommandError.new(reply.message) : reply
|
91
|
-
end
|
92
|
-
end
|
63
|
+
private
|
93
64
|
|
94
|
-
|
95
|
-
|
96
|
-
|
65
|
+
# Blocking commands inside transaction behave like non-blocking.
|
66
|
+
# It shouldn't be done though.
|
67
|
+
# https://redis.io/commands/blpop/#blpop-inside-a-multi--exec-transaction
|
68
|
+
def send_blocking_command(command, _timeout, &block)
|
69
|
+
send_command(command, &block)
|
97
70
|
end
|
98
71
|
end
|
99
72
|
|
@@ -106,10 +79,10 @@ class Redis
|
|
106
79
|
class Future < BasicObject
|
107
80
|
FutureNotReady = ::Redis::FutureNotReady.new
|
108
81
|
|
109
|
-
def initialize(command,
|
82
|
+
def initialize(command, coerce)
|
110
83
|
@command = command
|
111
|
-
@transformation = transformation
|
112
84
|
@object = FutureNotReady
|
85
|
+
@coerce = coerce
|
113
86
|
end
|
114
87
|
|
115
88
|
def inspect
|
@@ -117,16 +90,12 @@ class Redis
|
|
117
90
|
end
|
118
91
|
|
119
92
|
def _set(object)
|
120
|
-
@object = @
|
93
|
+
@object = @coerce ? @coerce.call(object) : object
|
121
94
|
value
|
122
95
|
end
|
123
96
|
|
124
|
-
def _command
|
125
|
-
@command
|
126
|
-
end
|
127
|
-
|
128
97
|
def value
|
129
|
-
::Kernel.raise(@object) if @object.
|
98
|
+
::Kernel.raise(@object) if @object.is_a?(::StandardError)
|
130
99
|
@object
|
131
100
|
end
|
132
101
|
|
@@ -138,4 +107,21 @@ class Redis
|
|
138
107
|
Future
|
139
108
|
end
|
140
109
|
end
|
110
|
+
|
111
|
+
class MultiFuture < Future
|
112
|
+
def initialize(futures)
|
113
|
+
@futures = futures
|
114
|
+
@command = [:exec]
|
115
|
+
@object = FutureNotReady
|
116
|
+
end
|
117
|
+
|
118
|
+
def _set(replies)
|
119
|
+
if replies
|
120
|
+
@futures.each_with_index do |future, index|
|
121
|
+
future._set(replies[index])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
@object = replies
|
125
|
+
end
|
126
|
+
end
|
141
127
|
end
|
data/lib/redis/subscribe.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
class SubscribedClient
|
3
5
|
def initialize(client)
|
4
6
|
@client = client
|
7
|
+
@write_monitor = Monitor.new
|
5
8
|
end
|
6
9
|
|
7
|
-
def
|
8
|
-
@
|
10
|
+
def call_v(command)
|
11
|
+
@write_monitor.synchronize do
|
12
|
+
@client.call_v(command)
|
13
|
+
end
|
9
14
|
end
|
10
15
|
|
11
16
|
def subscribe(*channels, &block)
|
@@ -25,31 +30,36 @@ class Redis
|
|
25
30
|
end
|
26
31
|
|
27
32
|
def unsubscribe(*channels)
|
28
|
-
|
33
|
+
call_v([:unsubscribe, *channels])
|
29
34
|
end
|
30
35
|
|
31
36
|
def punsubscribe(*channels)
|
32
|
-
|
37
|
+
call_v([:punsubscribe, *channels])
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
@client.close
|
33
42
|
end
|
34
43
|
|
35
|
-
|
44
|
+
protected
|
36
45
|
|
37
46
|
def subscription(start, stop, channels, block, timeout = 0)
|
38
47
|
sub = Subscription.new(&block)
|
39
48
|
|
40
|
-
|
49
|
+
call_v([start, *channels])
|
50
|
+
while event = @client.next_event(timeout)
|
51
|
+
if event.is_a?(::RedisClient::CommandError)
|
52
|
+
raise Client::ERROR_MAPPING.fetch(event.class), event.message
|
53
|
+
end
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
sub.callbacks[type].call(*rest)
|
46
|
-
unsubscribed = type == stop && rest.last == 0
|
47
|
-
break if unsubscribed
|
55
|
+
type, *rest = event
|
56
|
+
if callback = sub.callbacks[type]
|
57
|
+
callback.call(*rest)
|
48
58
|
end
|
49
|
-
|
50
|
-
# No need to unsubscribe here. The real client closes the connection
|
51
|
-
# whenever an exception is raised (see #ensure_connected).
|
59
|
+
break if type == stop && rest.last == 0
|
52
60
|
end
|
61
|
+
# No need to unsubscribe here. The real client closes the connection
|
62
|
+
# whenever an exception is raised (see #ensure_connected).
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
@@ -57,10 +67,7 @@ class Redis
|
|
57
67
|
attr :callbacks
|
58
68
|
|
59
69
|
def initialize
|
60
|
-
@callbacks =
|
61
|
-
hash[key] = lambda { |*_| }
|
62
|
-
end
|
63
|
-
|
70
|
+
@callbacks = {}
|
64
71
|
yield(self)
|
65
72
|
end
|
66
73
|
|
data/lib/redis/version.rb
CHANGED