redis-key_hash 0.0.2
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 +7 -0
- data/.gitignore +52 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +56 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/redis/impending_cross_slot_error.rb +18 -0
- data/lib/redis/key_hash.rb +214 -0
- data/lib/redis/key_hash/version.rb +17 -0
- data/redis-key_hash.gemspec +57 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c7dd84fcafb7fdfa166839a664d177a851ad7bf5
|
4
|
+
data.tar.gz: 496ced31fb42c55927fc739c6e5a930f6ea046f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9aa7190e2b7e7f50651d8628a1b7488e864f4a11cb803f25553f2233480f37f97af38024a335502dc93e3a7c7b3d2d451676b50399b81e40ff1d75e210a0487c
|
7
|
+
data.tar.gz: 7356c4f3ecb5efe65b4c8e8fff4bc67d70da7cc4560974d06736dad5f1a171a9bbb80307dfc7f373dee23af6cbc9e8daace89ad53c5d2fa7890ea260756f05c7
|
data/.gitignore
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
*.gem
|
2
|
+
*.gem
|
3
|
+
*.rbc
|
4
|
+
/.config
|
5
|
+
/coverage/
|
6
|
+
/InstalledFiles
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/spec/examples.txt
|
10
|
+
/test/tmp/
|
11
|
+
/test/version_tmp/
|
12
|
+
/tmp/
|
13
|
+
|
14
|
+
# Used by dotenv library to load environment variables.
|
15
|
+
# .env
|
16
|
+
|
17
|
+
## Specific to RubyMotion:
|
18
|
+
.dat*
|
19
|
+
.repl_history
|
20
|
+
build/
|
21
|
+
*.bridgesupport
|
22
|
+
build-iPhoneOS/
|
23
|
+
build-iPhoneSimulator/
|
24
|
+
|
25
|
+
## Specific to RubyMotion (use of CocoaPods):
|
26
|
+
#
|
27
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
28
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
29
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
30
|
+
#
|
31
|
+
# vendor/Pods/
|
32
|
+
|
33
|
+
## Documentation cache and generated files:
|
34
|
+
/.yardoc/
|
35
|
+
/_yardoc/
|
36
|
+
/doc/
|
37
|
+
/rdoc/
|
38
|
+
|
39
|
+
## Environment normalization:
|
40
|
+
/.bundle/
|
41
|
+
/vendor/bundle
|
42
|
+
/lib/bundler/man/
|
43
|
+
|
44
|
+
# For a library or gem, you might want to ignore these files since the code is
|
45
|
+
# intended to run in multiple environments; otherwise, check them in:
|
46
|
+
#
|
47
|
+
Gemfile.lock
|
48
|
+
.ruby-version
|
49
|
+
.ruby-gemset
|
50
|
+
|
51
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
52
|
+
.rvmrc
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 ProsperWorks
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Redis::KeyHash
|
2
|
+
|
3
|
+
Tests of key hash slot agreement for use with Redis Cluster and
|
4
|
+
RedisLabs Enterprise Cluster.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'redis-key_hash'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install redis-key_hash
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
require 'redis/key_hash'
|
25
|
+
|
26
|
+
# As syntactic sugar, expose Redis::KeyHash methods in the Redis class.
|
27
|
+
#
|
28
|
+
Redis.include Redis::KeyHash
|
29
|
+
|
30
|
+
# Test whether several keys will hash to the same slot.
|
31
|
+
#
|
32
|
+
if Redis.all_in_one_slot?('a','b')
|
33
|
+
'happy'
|
34
|
+
else
|
35
|
+
'sad'
|
36
|
+
end
|
37
|
+
Redis.all_in_one_slot!('a','b') # may raise Redis::ImpendingCrossSlotError
|
38
|
+
|
39
|
+
## Development
|
40
|
+
|
41
|
+
After checking out the repo, run `bin/setup` to install
|
42
|
+
dependencies. Then, run `rake test` to run the tests. You can also run
|
43
|
+
`bin/console` for an interactive prompt that will allow you to
|
44
|
+
experiment.
|
45
|
+
|
46
|
+
To install this gem onto your local machine, run `bundle exec rake
|
47
|
+
install`. To release a new version, update the version number in
|
48
|
+
`version.rb`, and then run `bundle exec rake release`, which will
|
49
|
+
create a git tag for the version, push git commits and tags, and push
|
50
|
+
the `.gem` file to [rubygems.org](https://rubygems.org).
|
51
|
+
|
52
|
+
## Contributing
|
53
|
+
|
54
|
+
Bug reports and pull requests are welcome on GitHub at
|
55
|
+
https://github.com/ProsperWorks/redis-key_hash.
|
56
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "redis/key_hash_util"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Raised from Redis::KeyHash.all_in_one_slot! on a mismatch.
|
2
|
+
#
|
3
|
+
# Generally, this indicates we were about to risk a Redis operation
|
4
|
+
# which is likely to produce a Redis error result like:
|
5
|
+
#
|
6
|
+
# (error) CROSSSLOT Keys in request don't hash to the same slot
|
7
|
+
#
|
8
|
+
# TODO: rubocop
|
9
|
+
#
|
10
|
+
# TODO: rdoc
|
11
|
+
#
|
12
|
+
class Redis
|
13
|
+
class ImpendingCrossSlotError < ArgumentError # TODO: Redis::CommandError?
|
14
|
+
#
|
15
|
+
# TODO: capture the problems with the keys?
|
16
|
+
#
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'redis/key_hash/version'
|
2
|
+
require 'redis/impending_cross_slot_error'
|
3
|
+
|
4
|
+
module Redis::KeyHash
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# TODO: rubocop
|
12
|
+
|
13
|
+
# TODO: rdoc
|
14
|
+
|
15
|
+
#
|
16
|
+
# TODO: KNOWN_STYLES hash, etc, move comments around
|
17
|
+
#
|
18
|
+
|
19
|
+
# The default for all_in_one_slot? and all_in_one_slot! is
|
20
|
+
# [:rc,:rlec] to encourage the of portable persistent hashing
|
21
|
+
# schemes.
|
22
|
+
#
|
23
|
+
# A scheme which works with both side-steps a potential vendor
|
24
|
+
# lock-in.
|
25
|
+
#
|
26
|
+
DEFAULT_STYLES ||= [ :rc, :rlec ].freeze
|
27
|
+
|
28
|
+
# The default style for hash_tag and hash_slot is :rc because we
|
29
|
+
# only know the hashing algorithm for Redis Cluster.
|
30
|
+
#
|
31
|
+
# We can guess that the hash for RedisLabs Enterprise Cluster is
|
32
|
+
# similar, but it is not documented.
|
33
|
+
#
|
34
|
+
DEFAULT_STYLE ||= :rc
|
35
|
+
|
36
|
+
# Tests whether all of keys will hash to the same slot in all
|
37
|
+
# specified sharding styles.
|
38
|
+
#
|
39
|
+
# @param keys String keys to be tested
|
40
|
+
#
|
41
|
+
# @param namespace String or nil if non-nil, applied as a prefix to
|
42
|
+
# all keys as per the redis-namespace gem before testing.
|
43
|
+
#
|
44
|
+
# @param styles Array of Symbols and/or Regexps as per hash_tag().
|
45
|
+
#
|
46
|
+
# @return true if all of keys provably have the same hash_slot under
|
47
|
+
# all styles by virtue of having a single hash_tag, false otherwise.
|
48
|
+
#
|
49
|
+
def all_in_one_slot?(*keys, namespace: nil, styles: DEFAULT_STYLES)
|
50
|
+
begin
|
51
|
+
all_in_one_slot!(*keys, namespace: namespace, styles: styles)
|
52
|
+
rescue Redis::ImpendingCrossSlotError
|
53
|
+
return false
|
54
|
+
else
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Like all_in_one_slot?, mismatch raises Redis::ImpendingCrossSlotError.
|
60
|
+
#
|
61
|
+
# @param keys String keys to be tested
|
62
|
+
#
|
63
|
+
# @param namespace String or nil if non-nil, applied as a prefix to
|
64
|
+
# all keys as per the redis-namespace gem before testing.
|
65
|
+
#
|
66
|
+
# @param styles Array of Symbols and/or Regexps as per hash_tag().
|
67
|
+
#
|
68
|
+
# @return true if all of keys will hash to the same slot in all of
|
69
|
+
# the styles, false if there is any doubt.
|
70
|
+
#
|
71
|
+
# @return true if all of keys provably have the same hash_slot
|
72
|
+
# under all styles by virtue of having a single hash_tag.
|
73
|
+
#
|
74
|
+
# @raises Redis::ImpendingCrossSlotError if, for any styles, the
|
75
|
+
# keys have a different hash_tag hence will not provably have the
|
76
|
+
# same hash_slot
|
77
|
+
#
|
78
|
+
def all_in_one_slot!(*keys, namespace: nil, styles: DEFAULT_STYLES)
|
79
|
+
nkeys = namespace ? keys.map { |key| "#{namespace}:#{key}" } : keys
|
80
|
+
style2slot = Hash.new
|
81
|
+
problems = []
|
82
|
+
styles.each do |style|
|
83
|
+
tags = nkeys.map { |nkey| hash_tag(nkey,style: style) }.uniq
|
84
|
+
next if tags.size <= 1
|
85
|
+
problems << "style #{style} sees tags #{tags.join(',')}"
|
86
|
+
end
|
87
|
+
if 0 != problems.size
|
88
|
+
err = "CROSSSLOT"
|
89
|
+
err += " namespace=#{namespace}"
|
90
|
+
err += " keys=#{keys}"
|
91
|
+
err += " problems=#{problems}"
|
92
|
+
raise Redis::ImpendingCrossSlotError, err
|
93
|
+
end
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
# Computes the hash tag for a given key under a given Redis
|
98
|
+
# clustering algorithm.
|
99
|
+
#
|
100
|
+
# The :style => :rc implementation matches Redis Cluster exactly
|
101
|
+
# and is taken largely from the reference example provided in
|
102
|
+
# http://redis.io/topics/cluster-spec.
|
103
|
+
#
|
104
|
+
# The :style => :rlec implementation is partly speculative. It is
|
105
|
+
# mostly interpreted from the default RedisLabs Enterprise Cluster
|
106
|
+
# document
|
107
|
+
# https://redislabs.com/redis-enterprise-documentation/concepts-architecture/architecture/database-clustering/
|
108
|
+
# plus our experience at ProsperWorks that, out of the box, RLEC
|
109
|
+
# uses the *last* {}-expr, not the first as in RC, from :rc (which
|
110
|
+
# we would not care about), they are also structually different
|
111
|
+
# (which can cause bugs unless we take special care). :rc uses
|
112
|
+
# the first {}-expr in the, :rlec uses the last {}-expr.
|
113
|
+
#
|
114
|
+
# @param String key to be hashed
|
115
|
+
#
|
116
|
+
# @param Symbol :rc or rlec or Regexp which defines one capture group
|
117
|
+
#
|
118
|
+
# @param String the tag extracted from key as appropriate for :style.
|
119
|
+
#
|
120
|
+
def hash_tag(key, style: DEFAULT_STYLE)
|
121
|
+
regexp = nil
|
122
|
+
case style
|
123
|
+
when :rc
|
124
|
+
regexp = /{([^}]*)}/ # RC uses the first {}-expr
|
125
|
+
when :rlec
|
126
|
+
regexp = /.*\{(.*)\}.*/ # RLEC default per docs, uses last {}-expr
|
127
|
+
when Regexp
|
128
|
+
regexp = style # you can define your own
|
129
|
+
end
|
130
|
+
if !regexp
|
131
|
+
raise ArgumentError, "bogus style #{style}"
|
132
|
+
end
|
133
|
+
match = regexp.match(key)
|
134
|
+
return match ? match[1] : key
|
135
|
+
end
|
136
|
+
|
137
|
+
# Computes the Redis hash_slot for a given key.
|
138
|
+
#
|
139
|
+
# Uses :style as per hash_tag, but performs hashing as per RC
|
140
|
+
# only. We know through documentation and experimentation that RC
|
141
|
+
# uses crc16() and modulo 16384. We do not know what RLEC does,
|
142
|
+
# but until we have a better model we assume it is the same. This
|
143
|
+
# is probably a false assumption since the RLEC docs state that
|
144
|
+
# the number of shards can vary from cluster to cluster. But for
|
145
|
+
# many analyses, using the same hash as RC is still useful.
|
146
|
+
#
|
147
|
+
# @param String key to be hashed
|
148
|
+
#
|
149
|
+
# @param Symbol :rc or :rlec or Regexp which defines one capture group
|
150
|
+
#
|
151
|
+
# @param non-negative Integer the hash which Redis will use to slot key
|
152
|
+
#
|
153
|
+
def hash_slot(key, style: DEFAULT_STYLE)
|
154
|
+
tag = hash_tag(key, style: style)
|
155
|
+
crc16(tag) % 16384
|
156
|
+
end
|
157
|
+
|
158
|
+
# Computes the Redis crc16 for a given key, as per the reference
|
159
|
+
# implementation provided in http://redis.io/topics/cluster-spec.
|
160
|
+
#
|
161
|
+
# This implementation is taken largely from that reference document,
|
162
|
+
# changed only slightly to port to Ruby.
|
163
|
+
#
|
164
|
+
# @param String key
|
165
|
+
#
|
166
|
+
# @param non-negative Integer the crc16 which Redis will use to
|
167
|
+
# compute a hash_key.
|
168
|
+
#
|
169
|
+
def crc16(key)
|
170
|
+
crc = 0
|
171
|
+
key.each_char do |char|
|
172
|
+
crc = ((crc << 8) & 0xFFFF) ^ CRC16TAB[((crc >> 8) ^ char.ord) & 0x00FF]
|
173
|
+
end
|
174
|
+
crc
|
175
|
+
end
|
176
|
+
|
177
|
+
CRC16TAB ||= [
|
178
|
+
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
|
179
|
+
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
|
180
|
+
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
|
181
|
+
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
|
182
|
+
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
|
183
|
+
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
|
184
|
+
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
|
185
|
+
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
|
186
|
+
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
|
187
|
+
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
|
188
|
+
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
|
189
|
+
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
|
190
|
+
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
|
191
|
+
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
|
192
|
+
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
|
193
|
+
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
|
194
|
+
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
|
195
|
+
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
|
196
|
+
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
|
197
|
+
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
|
198
|
+
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
|
199
|
+
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
|
200
|
+
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
|
201
|
+
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
|
202
|
+
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
|
203
|
+
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
|
204
|
+
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
|
205
|
+
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
|
206
|
+
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
|
207
|
+
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
|
208
|
+
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
|
209
|
+
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
|
210
|
+
].freeze
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Redis
|
2
|
+
module KeyHash
|
3
|
+
#
|
4
|
+
# Version plan:
|
5
|
+
#
|
6
|
+
# 0.0.1 - still in Prosperworks/ALI/vendor/gems/redis-key_hash
|
7
|
+
#
|
8
|
+
# 0.0.2 - broke out into Prosperworks/redis-key_hash
|
9
|
+
#
|
10
|
+
# 0.1.0 - big README.md and Rdoc update, open repo
|
11
|
+
#
|
12
|
+
# 0.2.0 - solicit and incorporate initial feedback from select
|
13
|
+
# beta external users
|
14
|
+
#
|
15
|
+
VERSION = "0.0.2" # broken into standalone repo, not polished
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'redis/key_hash/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "redis-key_hash"
|
7
|
+
spec.version = Redis::KeyHash::VERSION
|
8
|
+
spec.authors = [
|
9
|
+
"jhwillett"
|
10
|
+
]
|
11
|
+
spec.email = [
|
12
|
+
"jhw@prosperworks.com"
|
13
|
+
]
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.summary = 'Tests Redis Cluster key hash slot agreement'
|
17
|
+
spec.homepage = 'https://github.com/ProsperWorks/redis-key_hash'
|
18
|
+
spec.description = %{
|
19
|
+
redis-key_hash provides tests of key hash slot agreement for use with
|
20
|
+
Redis Cluster and RedisLabs Enterprise Cluster.
|
21
|
+
|
22
|
+
Redis Cluster (RC) and RedisLabs Enterprise Cluster (RLEC) both
|
23
|
+
require that all keys in multi-key operations hash to the same node.
|
24
|
+
They use slightly different default hashing algorithms and RLEC offers
|
25
|
+
customizable hash pattersn.
|
26
|
+
|
27
|
+
It is impossible to predict which nodes will host each shard, and
|
28
|
+
difficult to predict which slot will host each key. But it is easy to
|
29
|
+
identify the key hash tag which RC or RLEC will use to select a shard.
|
30
|
+
Where key hash tags agree, we can be certain that slots and nodes will
|
31
|
+
also agree - even if hash tag disagreement does not always imply slot
|
32
|
+
or node disagreement.
|
33
|
+
|
34
|
+
By pulling this check into Ruby we can arrange to fail fast, before
|
35
|
+
sending a command to Redis which is at risk of CROSSLOT failure. We
|
36
|
+
can also validate key management schemes in unit tests which run
|
37
|
+
without support services or with a non-sharded Redis.
|
38
|
+
}
|
39
|
+
|
40
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
41
|
+
f.match(%r{^(test|spec|features)/})
|
42
|
+
end
|
43
|
+
spec.require_paths = ["lib"]
|
44
|
+
|
45
|
+
# We use "foo: bar" syntax liberally, not the older ":foo => bar".
|
46
|
+
# Possibly other Ruby 2-isms as well.
|
47
|
+
#
|
48
|
+
spec.required_ruby_version = '~> 2.0'
|
49
|
+
|
50
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
51
|
+
spec.add_development_dependency "rake", "~> 10.5"
|
52
|
+
spec.add_development_dependency "minitest", "~> 5.10"
|
53
|
+
|
54
|
+
# This gem is pure Ruby, no weird dependencies.
|
55
|
+
#
|
56
|
+
spec.platform = Gem::Platform::RUBY
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis-key_hash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- jhwillett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.10'
|
55
|
+
description: |2
|
56
|
+
|
57
|
+
redis-key_hash provides tests of key hash slot agreement for use with
|
58
|
+
Redis Cluster and RedisLabs Enterprise Cluster.
|
59
|
+
|
60
|
+
Redis Cluster (RC) and RedisLabs Enterprise Cluster (RLEC) both
|
61
|
+
require that all keys in multi-key operations hash to the same node.
|
62
|
+
They use slightly different default hashing algorithms and RLEC offers
|
63
|
+
customizable hash pattersn.
|
64
|
+
|
65
|
+
It is impossible to predict which nodes will host each shard, and
|
66
|
+
difficult to predict which slot will host each key. But it is easy to
|
67
|
+
identify the key hash tag which RC or RLEC will use to select a shard.
|
68
|
+
Where key hash tags agree, we can be certain that slots and nodes will
|
69
|
+
also agree - even if hash tag disagreement does not always imply slot
|
70
|
+
or node disagreement.
|
71
|
+
|
72
|
+
By pulling this check into Ruby we can arrange to fail fast, before
|
73
|
+
sending a command to Redis which is at risk of CROSSLOT failure. We
|
74
|
+
can also validate key management schemes in unit tests which run
|
75
|
+
without support services or with a non-sharded Redis.
|
76
|
+
email:
|
77
|
+
- jhw@prosperworks.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- ".travis.yml"
|
84
|
+
- Gemfile
|
85
|
+
- LICENSE
|
86
|
+
- README.md
|
87
|
+
- Rakefile
|
88
|
+
- bin/console
|
89
|
+
- bin/setup
|
90
|
+
- lib/redis/impending_cross_slot_error.rb
|
91
|
+
- lib/redis/key_hash.rb
|
92
|
+
- lib/redis/key_hash/version.rb
|
93
|
+
- redis-key_hash.gemspec
|
94
|
+
homepage: https://github.com/ProsperWorks/redis-key_hash
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - "~>"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '2.0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.4.8
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Tests Redis Cluster key hash slot agreement
|
118
|
+
test_files: []
|