redis 4.8.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +75 -161
  4. data/lib/redis/client.rb +78 -615
  5. data/lib/redis/commands/bitmaps.rb +4 -1
  6. data/lib/redis/commands/cluster.rb +1 -18
  7. data/lib/redis/commands/connection.rb +5 -10
  8. data/lib/redis/commands/geo.rb +3 -3
  9. data/lib/redis/commands/hashes.rb +8 -5
  10. data/lib/redis/commands/hyper_log_log.rb +1 -1
  11. data/lib/redis/commands/keys.rb +1 -19
  12. data/lib/redis/commands/lists.rb +20 -25
  13. data/lib/redis/commands/pubsub.rb +7 -25
  14. data/lib/redis/commands/server.rb +14 -14
  15. data/lib/redis/commands/sets.rb +31 -40
  16. data/lib/redis/commands/sorted_sets.rb +18 -12
  17. data/lib/redis/commands/streams.rb +12 -10
  18. data/lib/redis/commands/strings.rb +14 -13
  19. data/lib/redis/commands/transactions.rb +7 -31
  20. data/lib/redis/commands.rb +1 -6
  21. data/lib/redis/distributed.rb +86 -64
  22. data/lib/redis/errors.rb +11 -50
  23. data/lib/redis/hash_ring.rb +26 -26
  24. data/lib/redis/pipeline.rb +43 -222
  25. data/lib/redis/subscribe.rb +23 -15
  26. data/lib/redis/version.rb +1 -1
  27. data/lib/redis.rb +80 -185
  28. metadata +11 -55
  29. data/lib/redis/cluster/command.rb +0 -79
  30. data/lib/redis/cluster/command_loader.rb +0 -33
  31. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  32. data/lib/redis/cluster/node.rb +0 -120
  33. data/lib/redis/cluster/node_key.rb +0 -31
  34. data/lib/redis/cluster/node_loader.rb +0 -34
  35. data/lib/redis/cluster/option.rb +0 -100
  36. data/lib/redis/cluster/slot.rb +0 -86
  37. data/lib/redis/cluster/slot_loader.rb +0 -46
  38. data/lib/redis/cluster.rb +0 -315
  39. data/lib/redis/connection/command_helper.rb +0 -41
  40. data/lib/redis/connection/hiredis.rb +0 -68
  41. data/lib/redis/connection/registry.rb +0 -13
  42. data/lib/redis/connection/ruby.rb +0 -437
  43. data/lib/redis/connection/synchrony.rb +0 -148
  44. data/lib/redis/connection.rb +0 -11
data/lib/redis.rb CHANGED
@@ -6,26 +6,10 @@ require "redis/commands"
6
6
 
7
7
  class Redis
8
8
  BASE_PATH = __dir__
9
- @exists_returns_integer = true
10
- @sadd_returns_boolean = true
11
-
12
9
  Deprecated = Class.new(StandardError)
13
10
 
14
11
  class << self
15
- attr_reader :exists_returns_integer
16
- attr_accessor :silence_deprecations, :raise_deprecations, :sadd_returns_boolean
17
-
18
- def exists_returns_integer=(value)
19
- unless value
20
- deprecate!(
21
- "`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
22
- "disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
23
- "`exists?` instead."
24
- )
25
- end
26
-
27
- @exists_returns_integer = value
28
- end
12
+ attr_accessor :silence_deprecations, :raise_deprecations
29
13
 
30
14
  def deprecate!(message)
31
15
  unless silence_deprecations
@@ -36,20 +20,12 @@ class Redis
36
20
  end
37
21
  end
38
22
  end
39
-
40
- def current
41
- deprecate!("`Redis.current` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
42
- @current ||= Redis.new
43
- end
44
-
45
- def current=(redis)
46
- deprecate!("`Redis.current=` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
47
- @current = redis
48
- end
49
23
  end
50
24
 
51
25
  include Commands
52
26
 
27
+ SERVER_URL_OPTIONS = %i(url host port path).freeze
28
+
53
29
  # Create a new client instance
54
30
  #
55
31
  # @param [Hash] options
@@ -63,52 +39,45 @@ class Redis
63
39
  # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
64
40
  # @option options [String] :username Username to authenticate against server
65
41
  # @option options [String] :password Password to authenticate against server
66
- # @option options [Integer] :db (0) Database to select after initial connect
67
- # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
42
+ # @option options [Integer] :db (0) Database to select after connect and on reconnects
43
+ # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`
68
44
  # @option options [String] :id ID for the client connection, assigns name to current connection by sending
69
45
  # `CLIENT SETNAME`
70
- # @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
71
- # based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
72
- # @option options [Integer] :reconnect_attempts Number of attempts trying to connect
46
+ # @option options [Integer, Array<Integer, Float>] :reconnect_attempts Number of attempts trying to connect,
47
+ # or a list of sleep duration between attempts.
73
48
  # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
49
+ # @option options [String] :name The name of the server group to connect to.
74
50
  # @option options [Array] :sentinels List of sentinels to contact
75
- # @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
76
- # @option options [Array<String, Hash{Symbol => String, Integer}>] :cluster List of cluster nodes to contact
77
- # @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
78
- # @option options [String] :fixed_hostname Specify a FQDN if cluster mode enabled and
79
- # client has to connect nodes via single endpoint with SSL/TLS
80
- # @option options [Class] :connector Class of custom connector
81
51
  #
82
52
  # @return [Redis] a new client instance
83
53
  def initialize(options = {})
84
- @options = options.dup
85
- @cluster_mode = options.key?(:cluster)
86
- client = @cluster_mode ? Cluster : Client
87
- @original_client = @client = client.new(options)
88
- @queue = Hash.new { |h, k| h[k] = [] }
89
54
  @monitor = Monitor.new
90
- end
91
-
92
- # Run code with the client reconnecting
93
- def with_reconnect(val = true, &blk)
94
- synchronize do |client|
95
- client.with_reconnect(val, &blk)
55
+ @options = options.dup
56
+ @options[:reconnect_attempts] = 1 unless @options.key?(:reconnect_attempts)
57
+ if ENV["REDIS_URL"] && SERVER_URL_OPTIONS.none? { |o| @options.key?(o) }
58
+ @options[:url] = ENV["REDIS_URL"]
96
59
  end
60
+ inherit_socket = @options.delete(:inherit_socket)
61
+ @subscription_client = nil
62
+
63
+ @client = initialize_client(@options)
64
+ @client.inherit_socket! if inherit_socket
97
65
  end
98
66
 
99
67
  # Run code without the client reconnecting
100
- def without_reconnect(&blk)
101
- with_reconnect(false, &blk)
68
+ def without_reconnect(&block)
69
+ @client.disable_reconnection(&block)
102
70
  end
103
71
 
104
72
  # Test whether or not the client is connected
105
73
  def connected?
106
- @original_client.connected?
74
+ @client.connected? || @subscription_client&.connected?
107
75
  end
108
76
 
109
77
  # Disconnect the client as quickly and silently as possible.
110
78
  def close
111
- @original_client.disconnect
79
+ @client.close
80
+ @subscription_client&.close
112
81
  end
113
82
  alias disconnect! close
114
83
 
@@ -116,127 +85,20 @@ class Redis
116
85
  yield self
117
86
  end
118
87
 
119
- # @deprecated Queues a command for pipelining.
120
- #
121
- # Commands in the queue are executed with the Redis#commit method.
122
- #
123
- # See http://redis.io/topics/pipelining for more details.
124
- #
125
- def queue(*command)
126
- ::Redis.deprecate!(
127
- "Redis#queue is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead." \
128
- "(called from: #{caller(1, 1).first})"
129
- )
130
-
131
- synchronize do
132
- @queue[Thread.current.object_id] << command
133
- end
134
- end
135
-
136
- # @deprecated Sends all commands in the queue.
137
- #
138
- # See http://redis.io/topics/pipelining for more details.
139
- #
140
- def commit
141
- ::Redis.deprecate!(
142
- "Redis#commit is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead. " \
143
- "(called from: #{Kernel.caller(1, 1).first})"
144
- )
145
-
146
- synchronize do |client|
147
- begin
148
- pipeline = Pipeline.new(client)
149
- @queue[Thread.current.object_id].each do |command|
150
- pipeline.call(command)
151
- end
152
-
153
- client.call_pipelined(pipeline)
154
- ensure
155
- @queue.delete(Thread.current.object_id)
156
- end
157
- end
158
- end
159
-
160
88
  def _client
161
89
  @client
162
90
  end
163
91
 
164
- def pipelined(&block)
165
- deprecation_displayed = false
166
- if block&.arity == 0
167
- Pipeline.deprecation_warning("pipelined", Kernel.caller_locations(1, 5))
168
- deprecation_displayed = true
169
- end
170
-
171
- synchronize do |prior_client|
172
- begin
173
- pipeline = Pipeline.new(prior_client)
174
- @client = deprecation_displayed ? pipeline : DeprecatedPipeline.new(pipeline)
175
- pipelined_connection = PipelinedConnection.new(pipeline)
176
- yield pipelined_connection
177
- prior_client.call_pipeline(pipeline)
178
- ensure
179
- @client = prior_client
180
- end
181
- end
182
- end
183
-
184
- # Mark the start of a transaction block.
185
- #
186
- # Passing a block is optional.
187
- #
188
- # @example With a block
189
- # redis.multi do |multi|
190
- # multi.set("key", "value")
191
- # multi.incr("counter")
192
- # end # => ["OK", 6]
193
- #
194
- # @example Without a block
195
- # redis.multi
196
- # # => "OK"
197
- # redis.set("key", "value")
198
- # # => "QUEUED"
199
- # redis.incr("counter")
200
- # # => "QUEUED"
201
- # redis.exec
202
- # # => ["OK", 6]
203
- #
204
- # @yield [multi] the commands that are called inside this block are cached
205
- # and written to the server upon returning from it
206
- # @yieldparam [Redis] multi `self`
207
- #
208
- # @return [String, Array<...>]
209
- # - when a block is not given, `OK`
210
- # - when a block is given, an array with replies
211
- #
212
- # @see #watch
213
- # @see #unwatch
214
- def multi(&block)
215
- if block_given?
216
- deprecation_displayed = false
217
- if block&.arity == 0
218
- Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 5))
219
- deprecation_displayed = true
220
- end
221
-
222
- synchronize do |prior_client|
223
- begin
224
- pipeline = Pipeline::Multi.new(prior_client)
225
- @client = deprecation_displayed ? pipeline : DeprecatedMulti.new(pipeline)
226
- pipelined_connection = PipelinedConnection.new(pipeline)
227
- yield pipelined_connection
228
- prior_client.call_pipeline(pipeline)
229
- ensure
230
- @client = prior_client
231
- end
92
+ def pipelined
93
+ synchronize do |client|
94
+ client.pipelined do |raw_pipeline|
95
+ yield PipelinedConnection.new(raw_pipeline)
232
96
  end
233
- else
234
- send_command([:multi])
235
97
  end
236
98
  end
237
99
 
238
100
  def id
239
- @original_client.id
101
+ @client.id || @client.server_url
240
102
  end
241
103
 
242
104
  def inspect
@@ -248,54 +110,87 @@ class Redis
248
110
  end
249
111
 
250
112
  def connection
251
- return @original_client.connection_info if @cluster_mode
252
-
253
113
  {
254
- host: @original_client.host,
255
- port: @original_client.port,
256
- db: @original_client.db,
257
- id: @original_client.id,
258
- location: @original_client.location
114
+ host: @client.host,
115
+ port: @client.port,
116
+ db: @client.db,
117
+ id: id,
118
+ location: "#{@client.host}:#{@client.port}"
259
119
  }
260
120
  end
261
121
 
262
122
  private
263
123
 
124
+ def initialize_client(options)
125
+ if options.key?(:cluster)
126
+ raise "Redis Cluster support was moved to the `redis_cluster` gem."
127
+ end
128
+
129
+ if options.key?(:sentinels)
130
+ if url = options.delete(:url)
131
+ uri = URI.parse(url)
132
+ if !options.key?(:name) && uri.host
133
+ options[:name] = uri.host
134
+ end
135
+
136
+ if !options.key?(:password) && uri.password && !uri.password.empty?
137
+ options[:password] = uri.password
138
+ end
139
+
140
+ if !options.key?(:username) && uri.user && !uri.user.empty?
141
+ options[:username] = uri.user
142
+ end
143
+ end
144
+
145
+ Client.sentinel(**options).new_client
146
+ else
147
+ Client.config(**options).new_client
148
+ end
149
+ end
150
+
264
151
  def synchronize
265
152
  @monitor.synchronize { yield(@client) }
266
153
  end
267
154
 
268
155
  def send_command(command, &block)
269
156
  @monitor.synchronize do
270
- @client.call(command, &block)
157
+ @client.call_v(command, &block)
271
158
  end
272
159
  end
273
160
 
274
161
  def send_blocking_command(command, timeout, &block)
275
162
  @monitor.synchronize do
276
- @client.call_with_timeout(command, timeout, &block)
163
+ @client.blocking_call_v(timeout, command, &block)
277
164
  end
278
165
  end
279
166
 
280
167
  def _subscription(method, timeout, channels, block)
281
- return @client.call([method] + channels) if subscribed?
168
+ if block
169
+ if @subscription_client
170
+ raise SubscriptionError, "This client is already subscribed"
171
+ end
282
172
 
283
- begin
284
- original, @client = @client, SubscribedClient.new(@client)
285
- if timeout > 0
286
- @client.send(method, timeout, *channels, &block)
287
- else
288
- @client.send(method, *channels, &block)
173
+ begin
174
+ @subscription_client = SubscribedClient.new(@client.pubsub)
175
+ if timeout > 0
176
+ @subscription_client.send(method, timeout, *channels, &block)
177
+ else
178
+ @subscription_client.send(method, *channels, &block)
179
+ end
180
+ ensure
181
+ @subscription_client = nil
182
+ end
183
+ else
184
+ unless @subscription_client
185
+ raise SubscriptionError, "This client is not subscribed"
289
186
  end
290
- ensure
291
- @client = original
187
+
188
+ @subscription_client.call_v([method].concat(channels))
292
189
  end
293
190
  end
294
191
  end
295
192
 
296
193
  require "redis/version"
297
- require "redis/connection"
298
194
  require "redis/client"
299
- require "redis/cluster"
300
195
  require "redis/pipeline"
301
196
  require "redis/subscribe"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -16,50 +16,22 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2022-08-22 00:00:00.000000000 Z
19
+ date: 2022-08-29 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: em-synchrony
22
+ name: redis-client
23
23
  requirement: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '0'
28
- type: :development
27
+ version: '0.7'
28
+ type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '0'
35
- - !ruby/object:Gem::Dependency
36
- name: hiredis
37
- requirement: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '0'
42
- type: :development
43
- prerelease: false
44
- version_requirements: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- - !ruby/object:Gem::Dependency
50
- name: mocha
51
- requirement: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
57
- prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
34
+ version: '0.7'
63
35
  description: |2
64
36
  A Ruby client that tries to match Redis' API one-to-one, while still
65
37
  providing an idiomatic interface.
@@ -74,16 +46,6 @@ files:
74
46
  - README.md
75
47
  - lib/redis.rb
76
48
  - lib/redis/client.rb
77
- - lib/redis/cluster.rb
78
- - lib/redis/cluster/command.rb
79
- - lib/redis/cluster/command_loader.rb
80
- - lib/redis/cluster/key_slot_converter.rb
81
- - lib/redis/cluster/node.rb
82
- - lib/redis/cluster/node_key.rb
83
- - lib/redis/cluster/node_loader.rb
84
- - lib/redis/cluster/option.rb
85
- - lib/redis/cluster/slot.rb
86
- - lib/redis/cluster/slot_loader.rb
87
49
  - lib/redis/commands.rb
88
50
  - lib/redis/commands/bitmaps.rb
89
51
  - lib/redis/commands/cluster.rb
@@ -101,12 +63,6 @@ files:
101
63
  - lib/redis/commands/streams.rb
102
64
  - lib/redis/commands/strings.rb
103
65
  - lib/redis/commands/transactions.rb
104
- - lib/redis/connection.rb
105
- - lib/redis/connection/command_helper.rb
106
- - lib/redis/connection/hiredis.rb
107
- - lib/redis/connection/registry.rb
108
- - lib/redis/connection/ruby.rb
109
- - lib/redis/connection/synchrony.rb
110
66
  - lib/redis/distributed.rb
111
67
  - lib/redis/errors.rb
112
68
  - lib/redis/hash_ring.rb
@@ -119,9 +75,9 @@ licenses:
119
75
  metadata:
120
76
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
121
77
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
122
- documentation_uri: https://www.rubydoc.info/gems/redis/4.8.0
78
+ documentation_uri: https://www.rubydoc.info/gems/redis/5.0.0
123
79
  homepage_uri: https://github.com/redis/redis-rb
124
- source_code_uri: https://github.com/redis/redis-rb/tree/v4.8.0
80
+ source_code_uri: https://github.com/redis/redis-rb/tree/v5.0.0
125
81
  post_install_message:
126
82
  rdoc_options: []
127
83
  require_paths:
@@ -130,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
86
  requirements:
131
87
  - - ">="
132
88
  - !ruby/object:Gem::Version
133
- version: 2.4.0
89
+ version: 2.5.0
134
90
  required_rubygems_version: !ruby/object:Gem::Requirement
135
91
  requirements:
136
92
  - - ">="
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../errors'
4
-
5
- class Redis
6
- class Cluster
7
- # Keep details about Redis commands for Redis Cluster Client.
8
- # @see https://redis.io/commands/command
9
- class Command
10
- def initialize(details)
11
- @details = pick_details(details)
12
- end
13
-
14
- def extract_first_key(command)
15
- i = determine_first_key_position(command)
16
- return '' if i == 0
17
-
18
- key = command[i].to_s
19
- hash_tag = extract_hash_tag(key)
20
- hash_tag.empty? ? key : hash_tag
21
- end
22
-
23
- def should_send_to_master?(command)
24
- dig_details(command, :write)
25
- end
26
-
27
- def should_send_to_slave?(command)
28
- dig_details(command, :readonly)
29
- end
30
-
31
- private
32
-
33
- def pick_details(details)
34
- details.transform_values do |detail|
35
- {
36
- first_key_position: detail[:first],
37
- write: detail[:flags].include?('write'),
38
- readonly: detail[:flags].include?('readonly')
39
- }
40
- end
41
- end
42
-
43
- def dig_details(command, key)
44
- name = command.first.to_s
45
- return unless @details.key?(name)
46
-
47
- @details.fetch(name).fetch(key)
48
- end
49
-
50
- def determine_first_key_position(command)
51
- case command.first.to_s.downcase
52
- when 'eval', 'evalsha', 'migrate', 'zinterstore', 'zunionstore' then 3
53
- when 'object' then 2
54
- when 'memory'
55
- command[1].to_s.casecmp('usage').zero? ? 2 : 0
56
- when 'xread', 'xreadgroup'
57
- determine_optional_key_position(command, 'streams')
58
- else
59
- dig_details(command, :first_key_position).to_i
60
- end
61
- end
62
-
63
- def determine_optional_key_position(command, option_name)
64
- idx = command.map(&:to_s).map(&:downcase).index(option_name)
65
- idx.nil? ? 0 : idx + 1
66
- end
67
-
68
- # @see https://redis.io/topics/cluster-spec#keys-hash-tags Keys hash tags
69
- def extract_hash_tag(key)
70
- s = key.index('{')
71
- e = key.index('}', s.to_i + 1)
72
-
73
- return '' if s.nil? || e.nil?
74
-
75
- key[s + 1..e - 1]
76
- end
77
- end
78
- end
79
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'redis/errors'
4
-
5
- class Redis
6
- class Cluster
7
- # Load details about Redis commands for Redis Cluster Client
8
- # @see https://redis.io/commands/command
9
- module CommandLoader
10
- module_function
11
-
12
- def load(nodes)
13
- errors = nodes.map do |node|
14
- begin
15
- return fetch_command_details(node)
16
- rescue CannotConnectError, ConnectionError, CommandError => error
17
- error
18
- end
19
- end
20
-
21
- raise InitialSetupError, errors
22
- end
23
-
24
- def fetch_command_details(node)
25
- node.call(%i[command]).map do |reply|
26
- [reply[0], { arity: reply[1], flags: reply[2], first: reply[3], last: reply[4], step: reply[5] }]
27
- end.to_h
28
- end
29
-
30
- private_class_method :fetch_command_details
31
- end
32
- end
33
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Redis
4
- class Cluster
5
- # Key to slot converter for Redis Cluster Client
6
- #
7
- # We can test it by `CLUSTER KEYSLOT` command.
8
- #
9
- # @see https://github.com/antirez/redis-rb-cluster
10
- # Reference implementation in Ruby
11
- # @see https://redis.io/topics/cluster-spec#appendix
12
- # Reference implementation in ANSI C
13
- # @see https://redis.io/commands/cluster-keyslot
14
- # CLUSTER KEYSLOT command reference
15
- #
16
- # Copyright (C) 2013 Salvatore Sanfilippo <antirez@gmail.com>
17
- module KeySlotConverter
18
- XMODEM_CRC16_LOOKUP = [
19
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
20
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
21
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
22
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
23
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
24
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
25
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
26
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
27
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
28
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
29
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
30
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
31
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
32
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
33
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
34
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
35
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
36
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
37
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
38
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
39
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
40
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
41
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
42
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
43
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
44
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
45
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
46
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
47
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
48
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
49
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
50
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
51
- ].freeze
52
-
53
- HASH_SLOTS = 16_384
54
-
55
- module_function
56
-
57
- # Convert key into slot.
58
- #
59
- # @param key [String] the key of the redis command
60
- #
61
- # @return [Integer] slot number
62
- def convert(key)
63
- crc = 0
64
- key.each_byte do |b|
65
- crc = ((crc << 8) & 0xffff) ^ XMODEM_CRC16_LOOKUP[((crc >> 8) ^ b) & 0xff]
66
- end
67
-
68
- crc % HASH_SLOTS
69
- end
70
- end
71
- end
72
- end