redis 4.1.4 → 4.7.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +141 -0
  3. data/README.md +52 -27
  4. data/lib/redis/client.rb +122 -87
  5. data/lib/redis/cluster/command.rb +4 -6
  6. data/lib/redis/cluster/command_loader.rb +8 -9
  7. data/lib/redis/cluster/node.rb +17 -1
  8. data/lib/redis/cluster/node_loader.rb +8 -11
  9. data/lib/redis/cluster/option.rb +18 -5
  10. data/lib/redis/cluster/slot.rb +28 -14
  11. data/lib/redis/cluster/slot_loader.rb +11 -15
  12. data/lib/redis/cluster.rb +37 -13
  13. data/lib/redis/commands/bitmaps.rb +63 -0
  14. data/lib/redis/commands/cluster.rb +45 -0
  15. data/lib/redis/commands/connection.rb +58 -0
  16. data/lib/redis/commands/geo.rb +84 -0
  17. data/lib/redis/commands/hashes.rb +251 -0
  18. data/lib/redis/commands/hyper_log_log.rb +37 -0
  19. data/lib/redis/commands/keys.rb +411 -0
  20. data/lib/redis/commands/lists.rb +289 -0
  21. data/lib/redis/commands/pubsub.rb +72 -0
  22. data/lib/redis/commands/scripting.rb +114 -0
  23. data/lib/redis/commands/server.rb +188 -0
  24. data/lib/redis/commands/sets.rb +207 -0
  25. data/lib/redis/commands/sorted_sets.rb +812 -0
  26. data/lib/redis/commands/streams.rb +382 -0
  27. data/lib/redis/commands/strings.rb +313 -0
  28. data/lib/redis/commands/transactions.rb +139 -0
  29. data/lib/redis/commands.rb +242 -0
  30. data/lib/redis/connection/command_helper.rb +4 -2
  31. data/lib/redis/connection/hiredis.rb +6 -7
  32. data/lib/redis/connection/registry.rb +1 -1
  33. data/lib/redis/connection/ruby.rb +106 -114
  34. data/lib/redis/connection/synchrony.rb +16 -10
  35. data/lib/redis/connection.rb +2 -1
  36. data/lib/redis/distributed.rb +200 -65
  37. data/lib/redis/errors.rb +10 -0
  38. data/lib/redis/hash_ring.rb +14 -14
  39. data/lib/redis/pipeline.rb +133 -10
  40. data/lib/redis/subscribe.rb +10 -12
  41. data/lib/redis/version.rb +2 -1
  42. data/lib/redis.rb +158 -3358
  43. metadata +32 -10
@@ -1,10 +1,80 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
2
5
  class Redis
6
+ class PipelinedConnection
7
+ def initialize(pipeline)
8
+ @pipeline = pipeline
9
+ end
10
+
11
+ include Commands
12
+
13
+ def db
14
+ @pipeline.db
15
+ end
16
+
17
+ def db=(db)
18
+ @pipeline.db = db
19
+ end
20
+
21
+ def pipelined
22
+ yield self
23
+ end
24
+
25
+ def call_pipeline(pipeline)
26
+ @pipeline.call_pipeline(pipeline)
27
+ nil
28
+ end
29
+
30
+ private
31
+
32
+ def synchronize
33
+ yield self
34
+ end
35
+
36
+ def send_command(command, &block)
37
+ @pipeline.call(command, &block)
38
+ end
39
+
40
+ def send_blocking_command(command, timeout, &block)
41
+ @pipeline.call_with_timeout(command, timeout, &block)
42
+ end
43
+ end
44
+
3
45
  class Pipeline
46
+ REDIS_INTERNAL_PATH = File.expand_path("..", __dir__).freeze
47
+ # Redis use MonitorMixin#synchronize and this class use DelegateClass which we want to filter out.
48
+ # Both are in the stdlib so we can simply filter the entire stdlib out.
49
+ STDLIB_PATH = File.expand_path("..", MonitorMixin.instance_method(:synchronize).source_location.first).freeze
50
+
51
+ class << self
52
+ def deprecation_warning(method, caller_locations) # :nodoc:
53
+ callsite = caller_locations.find { |l| !l.path.start_with?(REDIS_INTERNAL_PATH, STDLIB_PATH) }
54
+ callsite ||= caller_locations.last # The caller_locations should be large enough, but just in case.
55
+ ::Redis.deprecate! <<~MESSAGE
56
+ Pipelining commands on a Redis instance is deprecated and will be removed in Redis 5.0.0.
57
+
58
+ redis.#{method} do
59
+ redis.get("key")
60
+ end
61
+
62
+ should be replaced by
63
+
64
+ redis.#{method} do |pipeline|
65
+ pipeline.get("key")
66
+ end
67
+
68
+ (called from #{callsite}}
69
+ MESSAGE
70
+ end
71
+ end
72
+
4
73
  attr_accessor :db
5
74
  attr_reader :client
6
75
 
7
76
  attr :futures
77
+ alias materialized_futures futures
8
78
 
9
79
  def initialize(client)
10
80
  @client = client.is_a?(Pipeline) ? client.client : client
@@ -48,7 +118,7 @@ class Redis
48
118
 
49
119
  def call_pipeline(pipeline)
50
120
  @shutdown = true if pipeline.shutdown?
51
- @futures.concat(pipeline.futures)
121
+ @futures.concat(pipeline.materialized_futures)
52
122
  @db = pipeline.db
53
123
  nil
54
124
  end
@@ -61,7 +131,7 @@ class Redis
61
131
  @futures.map(&:timeout)
62
132
  end
63
133
 
64
- def with_reconnect(val=true)
134
+ def with_reconnect(val = true)
65
135
  @with_reconnect = false unless val
66
136
  yield
67
137
  end
@@ -93,7 +163,8 @@ class Redis
93
163
 
94
164
  if exec.size < futures.size
95
165
  # Some command wasn't recognized by Redis.
96
- raise replies.detect { |r| r.is_a?(CommandError) }
166
+ command_error = replies.detect { |r| r.is_a?(CommandError) }
167
+ raise command_error
97
168
  end
98
169
 
99
170
  super(exec) do |reply|
@@ -104,6 +175,18 @@ class Redis
104
175
  end
105
176
  end
106
177
 
178
+ def materialized_futures
179
+ if empty?
180
+ []
181
+ else
182
+ [
183
+ Future.new([:multi], nil, 0),
184
+ *futures,
185
+ MultiFuture.new(futures)
186
+ ]
187
+ end
188
+ end
189
+
107
190
  def timeouts
108
191
  if empty?
109
192
  []
@@ -122,6 +205,36 @@ class Redis
122
205
  end
123
206
  end
124
207
 
208
+ class DeprecatedPipeline < DelegateClass(Pipeline)
209
+ def initialize(pipeline)
210
+ super(pipeline)
211
+ @deprecation_displayed = false
212
+ end
213
+
214
+ def __getobj__
215
+ unless @deprecation_displayed
216
+ Pipeline.deprecation_warning("pipelined", Kernel.caller_locations(1, 10))
217
+ @deprecation_displayed = true
218
+ end
219
+ @delegate_dc_obj
220
+ end
221
+ end
222
+
223
+ class DeprecatedMulti < DelegateClass(Pipeline::Multi)
224
+ def initialize(pipeline)
225
+ super(pipeline)
226
+ @deprecation_displayed = false
227
+ end
228
+
229
+ def __getobj__
230
+ unless @deprecation_displayed
231
+ Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 10))
232
+ @deprecation_displayed = true
233
+ end
234
+ @delegate_dc_obj
235
+ end
236
+ end
237
+
125
238
  class FutureNotReady < RuntimeError
126
239
  def initialize
127
240
  super("Value will be available once the pipeline executes.")
@@ -141,15 +254,11 @@ class Redis
141
254
  end
142
255
 
143
256
  def ==(_other)
144
- message = +"The methods == and != are deprecated for Redis::Future and will be removed in 4.2.0"
257
+ message = +"The methods == and != are deprecated for Redis::Future and will be removed in 5.0.0"
145
258
  message << " - You probably meant to call .value == or .value !="
146
259
  message << " (#{::Kernel.caller(1, 1).first})\n"
147
260
 
148
- if defined?(::Warning)
149
- ::Warning.warn(message)
150
- else
151
- $stderr.puts(message)
152
- end
261
+ ::Redis.deprecate!(message)
153
262
 
154
263
  super
155
264
  end
@@ -168,7 +277,7 @@ class Redis
168
277
  end
169
278
 
170
279
  def value
171
- ::Kernel.raise(@object) if @object.kind_of?(::RuntimeError)
280
+ ::Kernel.raise(@object) if @object.is_a?(::RuntimeError)
172
281
  @object
173
282
  end
174
283
 
@@ -180,4 +289,18 @@ class Redis
180
289
  Future
181
290
  end
182
291
  end
292
+
293
+ class MultiFuture < Future
294
+ def initialize(futures)
295
+ @futures = futures
296
+ @command = [:exec]
297
+ end
298
+
299
+ def _set(replies)
300
+ @futures.each_with_index do |future, index|
301
+ future._set(replies[index])
302
+ end
303
+ replies
304
+ end
305
+ end
183
306
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  class SubscribedClient
4
5
  def initialize(client)
@@ -33,24 +34,21 @@ class Redis
33
34
  call([:punsubscribe, *channels])
34
35
  end
35
36
 
36
- protected
37
+ protected
37
38
 
38
39
  def subscription(start, stop, channels, block, timeout = 0)
39
40
  sub = Subscription.new(&block)
40
41
 
41
42
  unsubscribed = false
42
43
 
43
- begin
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
- end
50
- ensure
51
- # No need to unsubscribe here. The real client closes the connection
52
- # whenever an exception is raised (see #ensure_connected).
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
53
49
  end
50
+ # No need to unsubscribe here. The real client closes the connection
51
+ # whenever an exception is raised (see #ensure_connected).
54
52
  end
55
53
  end
56
54
 
@@ -59,7 +57,7 @@ class Redis
59
57
 
60
58
  def initialize
61
59
  @callbacks = Hash.new do |hash, key|
62
- hash[key] = lambda { |*_| }
60
+ hash[key] = ->(*_) {}
63
61
  end
64
62
 
65
63
  yield(self)
data/lib/redis/version.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
- VERSION = '4.1.4'
4
+ VERSION = '4.7.1'
4
5
  end