Class: Redis::KeyHash
- Inherits:
-
Object
- Object
- Redis::KeyHash
- Defined in:
- lib/redis/key_hash.rb,
lib/redis/key_hash/version.rb
Overview
Namespace for key-hashing methods.
Constant Summary collapse
- VERSION =
Version plan/history:
0.0.1 - Still in Prosperworks/ALI/vendor/gems/redis-key_hash.
0.0.2 - Broke out into Prosperworks/redis-key_hash, make public.
0.0.3 - Fix :rc to match redis.io/topics/cluster-spec,
added Rubocop checks.0.0.4 - Verified existing behavior w/r/t Redis::Namespace.
Added more details in Redis::ImpendingCrossSlotError. Rubocop polish and defiance. Redis::KeyHash::ClassMethods inner-inner class removed. Redis::KeyHash changed to a class, not a module. Redis::ImpendingCrossSlotError changed from ArgumentError to Redis::RuntimeError.0.1.0 - (future) Big README.md and Rdoc update, solicit feedback
from select external beta users.0.2.0 - (future) Incorporate feedback, announce.
'0.0.4'.freeze
Class Method Summary collapse
-
.all_in_one_slot!(*keys, namespace: nil, styles: DEFAULT_STYLES) ⇒ Object
Like all_in_one_slot?, mismatch raises Redis::ImpendingCrossSlotError.
-
.all_in_one_slot?(*keys, namespace: nil, styles: DEFAULT_STYLES) ⇒ Boolean
Tests whether all of keys will hash to the same slot in all specified sharding styles.
-
.crc16(key) ⇒ Object
Computes the Redis crc16 for a given key, as per the reference implementation provided in redis.io/topics/cluster-spec.
-
.hash_slot(key, style: DEFAULT_STYLE) ⇒ Object
Computes the Redis hash_slot for a given key.
-
.hash_tag(key, style: DEFAULT_STYLE) ⇒ Object
Computes the hash tag for a given key under a given Redis clustering algorithm.
Class Method Details
.all_in_one_slot!(*keys, namespace: nil, styles: DEFAULT_STYLES) ⇒ Object
Like all_in_one_slot?, mismatch raises Redis::ImpendingCrossSlotError.
all keys as per the redis-namespace gem before testing.
the styles, false if there is any doubt.
under all styles by virtue of having a single hash_tag.
keys have a different hash_tag hence will not provably have the same hash_slot
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/redis/key_hash.rb', line 96 def self.all_in_one_slot!(*keys, namespace: nil, styles: DEFAULT_STYLES) namespaced_keys = keys if namespace # # Although Redis::Namespace.add_namespace is private, I have # confirmed that when namespace is the empty string, "key" # maps to ":key". # # That is, namespace nil has no effect, but namespace '' # results in a ':' prepended to every key. # # Naturally, this can affect the key's hash tag. # namespaced_keys = keys.map { |key| "#{namespace}:#{key}" } end problems = [] styles.each do |style| = namespaced_keys.map do |namespaced_key| hash_tag(namespaced_key,style: style) end.uniq next if .size <= 1 problems << "style #{style} sees tags #{tags.join(',')}" end if 0 != problems.size raise Redis::ImpendingCrossSlotError.new( namespace, keys, namespaced_keys, problems ) end true end |
.all_in_one_slot?(*keys, namespace: nil, styles: DEFAULT_STYLES) ⇒ Boolean
Tests whether all of keys will hash to the same slot in all specified sharding styles.
all keys as per the redis-namespace gem before testing.
all styles by virtue of having a single hash_tag, false otherwise.
69 70 71 72 73 74 75 |
# File 'lib/redis/key_hash.rb', line 69 def self.all_in_one_slot?(*keys, namespace: nil, styles: DEFAULT_STYLES) all_in_one_slot!(*keys, namespace: namespace, styles: styles) rescue Redis::ImpendingCrossSlotError return false else return true end |
.crc16(key) ⇒ Object
Computes the Redis crc16 for a given key, as per the reference implementation provided in redis.io/topics/cluster-spec.
This implementation is taken largely from that reference document, changed only slightly to port to Ruby.
compute a hash_key.
185 186 187 188 189 190 191 |
# File 'lib/redis/key_hash.rb', line 185 def self.crc16(key) crc = 0 key.each_char do |char| crc = ((crc<<8) & 0xFFFF) ^ CRC16TAB[((crc>>8) ^ char.ord) & 0x00FF] end crc end |
.hash_slot(key, style: DEFAULT_STYLE) ⇒ Object
Computes the Redis hash_slot for a given key.
Uses :style as per hash_tag, but performs hashing as per RC only. We know through documentation and experimentation that RC uses crc16() and modulo 16384. We do not know what RLEC does, but until we have a better model we assume it is the same. This is probably a false assumption since the RLEC docs state that the number of shards can vary from cluster to cluster. But for many analyses, using the same hash as RC is still useful.
169 170 171 172 |
# File 'lib/redis/key_hash.rb', line 169 def self.hash_slot(key, style: DEFAULT_STYLE) tag = hash_tag(key, style: style) crc16(tag) % 16384 end |
.hash_tag(key, style: DEFAULT_STYLE) ⇒ Object
Computes the hash tag for a given key under a given Redis clustering algorithm.
139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/redis/key_hash.rb', line 139 def self.hash_tag(key, style: DEFAULT_STYLE) regexp = nil if KNOWN_STYLES.key?(style) regexp = KNOWN_STYLES[style] # some are predefined elsif style.is_a?(Regexp) regexp = style # you can define your own end if !regexp raise ArgumentError, "bogus style #{style}" end match = regexp.match(key) match ? match[1] : key end |