redis 4.5.1 → 5.0.6

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +120 -0
  3. data/README.md +82 -153
  4. data/lib/redis/client.rb +77 -615
  5. data/lib/redis/commands/bitmaps.rb +66 -0
  6. data/lib/redis/commands/cluster.rb +28 -0
  7. data/lib/redis/commands/connection.rb +53 -0
  8. data/lib/redis/commands/geo.rb +84 -0
  9. data/lib/redis/commands/hashes.rb +254 -0
  10. data/lib/redis/commands/hyper_log_log.rb +37 -0
  11. data/lib/redis/commands/keys.rb +437 -0
  12. data/lib/redis/commands/lists.rb +285 -0
  13. data/lib/redis/commands/pubsub.rb +54 -0
  14. data/lib/redis/commands/scripting.rb +114 -0
  15. data/lib/redis/commands/server.rb +188 -0
  16. data/lib/redis/commands/sets.rb +214 -0
  17. data/lib/redis/commands/sorted_sets.rb +818 -0
  18. data/lib/redis/commands/streams.rb +402 -0
  19. data/lib/redis/commands/strings.rb +314 -0
  20. data/lib/redis/commands/transactions.rb +115 -0
  21. data/lib/redis/commands.rb +237 -0
  22. data/lib/redis/distributed.rb +140 -70
  23. data/lib/redis/errors.rb +15 -41
  24. data/lib/redis/hash_ring.rb +26 -26
  25. data/lib/redis/pipeline.rb +66 -120
  26. data/lib/redis/subscribe.rb +23 -15
  27. data/lib/redis/version.rb +1 -1
  28. data/lib/redis.rb +106 -3736
  29. metadata +26 -53
  30. data/lib/redis/cluster/command.rb +0 -81
  31. data/lib/redis/cluster/command_loader.rb +0 -33
  32. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  33. data/lib/redis/cluster/node.rb +0 -108
  34. data/lib/redis/cluster/node_key.rb +0 -31
  35. data/lib/redis/cluster/node_loader.rb +0 -37
  36. data/lib/redis/cluster/option.rb +0 -93
  37. data/lib/redis/cluster/slot.rb +0 -86
  38. data/lib/redis/cluster/slot_loader.rb +0 -49
  39. data/lib/redis/cluster.rb +0 -291
  40. data/lib/redis/connection/command_helper.rb +0 -41
  41. data/lib/redis/connection/hiredis.rb +0 -67
  42. data/lib/redis/connection/registry.rb +0 -13
  43. data/lib/redis/connection/ruby.rb +0 -428
  44. data/lib/redis/connection/synchrony.rb +0 -146
  45. data/lib/redis/connection.rb +0 -11
@@ -1,126 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "delegate"
4
+
3
5
  class Redis
4
- class Pipeline
6
+ class PipelinedConnection
5
7
  attr_accessor :db
6
- attr_reader :client
7
-
8
- attr :futures
9
8
 
10
- def initialize(client)
11
- @client = client.is_a?(Pipeline) ? client.client : client
12
- @with_reconnect = true
13
- @shutdown = false
14
- @futures = []
9
+ def initialize(pipeline, futures = [])
10
+ @pipeline = pipeline
11
+ @futures = futures
15
12
  end
16
13
 
17
- def timeout
18
- client.timeout
19
- end
14
+ include Commands
20
15
 
21
- def with_reconnect?
22
- @with_reconnect
16
+ def pipelined
17
+ yield self
23
18
  end
24
19
 
25
- def without_reconnect?
26
- !@with_reconnect
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
27
31
  end
28
32
 
29
- def shutdown?
30
- @shutdown
31
- end
33
+ private
32
34
 
33
- def empty?
34
- @futures.empty?
35
+ def synchronize
36
+ yield self
35
37
  end
36
38
 
37
- def call(command, timeout: nil, &block)
38
- # A pipeline that contains a shutdown should not raise ECONNRESET when
39
- # the connection is gone.
40
- @shutdown = true if command.first == :shutdown
41
- future = Future.new(command, block, timeout)
39
+ def send_command(command, &block)
40
+ future = Future.new(command, block)
41
+ @pipeline.call_v(command) do |result|
42
+ future._set(result)
43
+ end
42
44
  @futures << future
43
45
  future
44
46
  end
45
47
 
46
- def call_with_timeout(command, timeout, &block)
47
- call(command, timeout: timeout, &block)
48
- end
49
-
50
- def call_pipeline(pipeline)
51
- @shutdown = true if pipeline.shutdown?
52
- @futures.concat(pipeline.futures)
53
- @db = pipeline.db
54
- nil
55
- end
56
-
57
- def commands
58
- @futures.map(&:_command)
59
- end
60
-
61
- def timeouts
62
- @futures.map(&:timeout)
63
- end
64
-
65
- def with_reconnect(val = true)
66
- @with_reconnect = false unless val
67
- yield
68
- end
69
-
70
- def without_reconnect(&blk)
71
- with_reconnect(false, &blk)
72
- end
73
-
74
- def finish(replies, &blk)
75
- if blk
76
- futures.each_with_index.map do |future, i|
77
- future._set(blk.call(replies[i]))
78
- end
79
- else
80
- futures.each_with_index.map do |future, i|
81
- future._set(replies[i])
82
- 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)
83
52
  end
53
+ @futures << future
54
+ future
84
55
  end
56
+ end
85
57
 
86
- class Multi < self
87
- def finish(replies)
88
- exec = replies.last
89
-
90
- return if exec.nil? # The transaction failed because of WATCH.
91
-
92
- # EXEC command failed.
93
- raise exec if exec.is_a?(CommandError)
94
-
95
- if exec.size < futures.size
96
- # Some command wasn't recognized by Redis.
97
- command_error = replies.detect { |r| r.is_a?(CommandError) }
98
- raise command_error
99
- end
58
+ class MultiConnection < PipelinedConnection
59
+ def multi
60
+ raise Redis::Error, "Can't nest multi transaction"
61
+ end
100
62
 
101
- super(exec) do |reply|
102
- # Because an EXEC returns nested replies, hiredis won't be able to
103
- # convert an error reply to a CommandError instance itself. This is
104
- # specific to MULTI/EXEC, so we solve this here.
105
- reply.is_a?(::RuntimeError) ? CommandError.new(reply.message) : reply
106
- end
107
- end
63
+ private
108
64
 
109
- def timeouts
110
- if empty?
111
- []
112
- else
113
- [nil, *super, nil]
114
- end
115
- end
116
-
117
- def commands
118
- if empty?
119
- []
120
- else
121
- [[:multi]] + super + [[:exec]]
122
- end
123
- end
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)
124
70
  end
125
71
  end
126
72
 
@@ -133,23 +79,10 @@ class Redis
133
79
  class Future < BasicObject
134
80
  FutureNotReady = ::Redis::FutureNotReady.new
135
81
 
136
- attr_reader :timeout
137
-
138
- def initialize(command, transformation, timeout)
82
+ def initialize(command, coerce)
139
83
  @command = command
140
- @transformation = transformation
141
- @timeout = timeout
142
84
  @object = FutureNotReady
143
- end
144
-
145
- def ==(_other)
146
- message = +"The methods == and != are deprecated for Redis::Future and will be removed in 4.2.0"
147
- message << " - You probably meant to call .value == or .value !="
148
- message << " (#{::Kernel.caller(1, 1).first})\n"
149
-
150
- ::Kernel.warn(message)
151
-
152
- super
85
+ @coerce = coerce
153
86
  end
154
87
 
155
88
  def inspect
@@ -157,16 +90,12 @@ class Redis
157
90
  end
158
91
 
159
92
  def _set(object)
160
- @object = @transformation ? @transformation.call(object) : object
93
+ @object = @coerce ? @coerce.call(object) : object
161
94
  value
162
95
  end
163
96
 
164
- def _command
165
- @command
166
- end
167
-
168
97
  def value
169
- ::Kernel.raise(@object) if @object.is_a?(::RuntimeError)
98
+ ::Kernel.raise(@object) if @object.is_a?(::StandardError)
170
99
  @object
171
100
  end
172
101
 
@@ -178,4 +107,21 @@ class Redis
178
107
  Future
179
108
  end
180
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
181
127
  end
@@ -4,10 +4,13 @@ class Redis
4
4
  class SubscribedClient
5
5
  def initialize(client)
6
6
  @client = client
7
+ @write_monitor = Monitor.new
7
8
  end
8
9
 
9
- def call(command)
10
- @client.process([command])
10
+ def call_v(command)
11
+ @write_monitor.synchronize do
12
+ @client.call_v(command)
13
+ end
11
14
  end
12
15
 
13
16
  def subscribe(*channels, &block)
@@ -27,11 +30,15 @@ class Redis
27
30
  end
28
31
 
29
32
  def unsubscribe(*channels)
30
- call([:unsubscribe, *channels])
33
+ call_v([:unsubscribe, *channels])
31
34
  end
32
35
 
33
36
  def punsubscribe(*channels)
34
- call([:punsubscribe, *channels])
37
+ call_v([:punsubscribe, *channels])
38
+ end
39
+
40
+ def close
41
+ @client.close
35
42
  end
36
43
 
37
44
  protected
@@ -39,13 +46,17 @@ class Redis
39
46
  def subscription(start, stop, channels, block, timeout = 0)
40
47
  sub = Subscription.new(&block)
41
48
 
42
- unsubscribed = false
43
-
44
- @client.call_loop([start, *channels], timeout) do |line|
45
- type, *rest = line
46
- sub.callbacks[type].call(*rest)
47
- unsubscribed = type == stop && rest.last == 0
48
- break if unsubscribed
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
54
+
55
+ type, *rest = event
56
+ if callback = sub.callbacks[type]
57
+ callback.call(*rest)
58
+ end
59
+ break if type == stop && rest.last == 0
49
60
  end
50
61
  # No need to unsubscribe here. The real client closes the connection
51
62
  # whenever an exception is raised (see #ensure_connected).
@@ -56,10 +67,7 @@ class Redis
56
67
  attr :callbacks
57
68
 
58
69
  def initialize
59
- @callbacks = Hash.new do |hash, key|
60
- hash[key] = ->(*_) {}
61
- end
62
-
70
+ @callbacks = {}
63
71
  yield(self)
64
72
  end
65
73
 
data/lib/redis/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '4.5.1'
4
+ VERSION = '5.0.6'
5
5
  end