2323import org .springframework .util .Assert ;
2424
2525/**
26+ * Utility class encapsulating functionality commonly used for cluster slot hashing.
27+ *
2628 * @author Christoph Strobl
29+ * @author John Blum
2730 * @since 1.7
2831 */
29- public final class ClusterSlotHashUtil {
32+ public abstract class ClusterSlotHashUtil {
3033
3134 public static final int SLOT_COUNT = 16384 ;
3235
33- private static final byte SUBKEY_START = '{' ;
34- private static final byte SUBKEY_END = '}' ;
36+ protected static final byte SUBKEY_START = '{' ;
37+ protected static final byte SUBKEY_END = '}' ;
3538
3639 private static final int [] LOOKUP_TABLE = { 0x0000 , 0x1021 , 0x2042 , 0x3063 , 0x4084 , 0x50A5 , 0x60C6 , 0x70E7 , 0x8108 ,
3740 0x9129 , 0xA14A , 0xB16B , 0xC18C , 0xD1AD , 0xE1CE , 0xF1EF , 0x1231 , 0x0210 , 0x3273 , 0x2252 , 0x52B5 , 0x4294 , 0x72F7 ,
@@ -53,93 +56,109 @@ public final class ClusterSlotHashUtil {
5356 0x6C07 , 0x5C64 , 0x4C45 , 0x3CA2 , 0x2C83 , 0x1CE0 , 0x0CC1 , 0xEF1F , 0xFF3E , 0xCF5D , 0xDF7C , 0xAF9B , 0xBFBA , 0x8FD9 ,
5457 0x9FF8 , 0x6E17 , 0x7E36 , 0x4E55 , 0x5E74 , 0x2E93 , 0x3EB2 , 0x0ED1 , 0x1EF0 };
5558
56- private ClusterSlotHashUtil () {
57-
58- }
59-
6059 /**
61- * @param keys must not be {@literal null}.
62- * @return
63- * @since 2.0
60+ * Determines whether all keys will hash to the same slot.
61+ *
62+ * @param keys array of keys to evaluate3; must not be {@literal null}.
63+ * @return a boolean value indicating whether all keys will hash to the same slot.
64+ * @throws IllegalArgumentException if the byte array of keys is {@literal null}.
6465 */
65- public static boolean isSameSlotForAllKeys (Collection < ByteBuffer > keys ) {
66+ public static boolean isSameSlotForAllKeys (byte []... keys ) {
6667
6768 Assert .notNull (keys , "Keys must not be null" );
6869
69- if (keys .size () <= 1 ) {
70+ if (keys .length <= 1 ) {
7071 return true ;
7172 }
7273
73- return isSameSlotForAllKeys ((byte [][]) keys .stream () //
74- .map (ByteBuffer ::duplicate ) //
75- .map (ByteUtils ::getBytes ) //
76- .toArray (byte [][]::new ));
74+ int slot = calculateSlot (keys [0 ]);
75+
76+ for (int i = 1 ; i < keys .length ; i ++) {
77+ if (slot != calculateSlot (keys [i ])) {
78+ return false ;
79+ }
80+ }
81+
82+ return true ;
7783 }
7884
7985 /**
80- * @param keys must not be {@literal null}.
81- * @return
86+ * Determines whether all keys will hash to the same slot.
87+ *
88+ * @param keys array of {@link ByteBuffer} objects containing the keys to evaluate; must not be {@literal null}.
89+ * @return a boolean value indicating whether all keys will hash to the same slot.
90+ * @throws IllegalArgumentException if the array of keys is {@literal null}.
91+ * @see #isSameSlotForAllKeys(Collection)
8292 * @since 2.0
8393 */
8494 public static boolean isSameSlotForAllKeys (ByteBuffer ... keys ) {
8595
8696 Assert .notNull (keys , "Keys must not be null" );
97+
8798 return isSameSlotForAllKeys (Arrays .asList (keys ));
8899 }
89100
90101 /**
91- * @param keys must not be {@literal null}.
92- * @return
102+ * Determines whether all keys will hash to the same slot.
103+ *
104+ * @param keys {@link Collection} of {@link ByteBuffer} objects containing the keys to evaluate;
105+ * must not be {@literal null}.
106+ * @return a boolean value indicating whether all keys will hash to the same slot.
107+ * @throws IllegalArgumentException if the {@link Collection} of keys is {@literal null}.
108+ * @since 2.0
93109 */
94- public static boolean isSameSlotForAllKeys (byte []... keys ) {
110+ public static boolean isSameSlotForAllKeys (Collection < ByteBuffer > keys ) {
95111
96112 Assert .notNull (keys , "Keys must not be null" );
97113
98- if (keys .length <= 1 ) {
114+ if (keys .size () <= 1 ) {
99115 return true ;
100116 }
101117
102- int slot = calculateSlot (keys [0 ]);
103- for (int i = 1 ; i < keys .length ; i ++) {
104- if (slot != calculateSlot (keys [i ])) {
105- return false ;
106- }
107- }
108- return true ;
118+ return isSameSlotForAllKeys (keys .stream ()
119+ .map (ByteBuffer ::duplicate )
120+ .map (ByteUtils ::getBytes )
121+ .toArray (byte [][]::new ));
109122 }
110123
111124 /**
112125 * Calculate the slot from the given key.
113126 *
114- * @param key must not be {@literal null} or empty.
115- * @return
127+ * @param key {@link String} containing the Redis key to evaluate; must not be {@literal null} or {@literal empty}.
128+ * @return the computed slot based on the given key.
129+ * @throws IllegalArgumentException if the given {@link String key} is {@literal null} or {@literal empty}.
130+ * @see #calculateSlot(byte[])
116131 */
117132 public static int calculateSlot (String key ) {
118133
119134 Assert .hasText (key , "Key must not be null or empty" );
135+
120136 return calculateSlot (key .getBytes ());
121137 }
122138
123139 /**
124140 * Calculate the slot from the given key.
125141 *
126- * @param key must not be {@literal null}.
127- * @return
142+ * @param key array of bytes containing the Redis key to evaluate; must not be {@literal null}.
143+ * @return the computed slot based on the given key.
128144 */
129145 public static int calculateSlot (byte [] key ) {
130146
131147 Assert .notNull (key , "Key must not be null" );
132148
133149 byte [] finalKey = key ;
134150 int start = indexOf (key , SUBKEY_START );
151+
135152 if (start != -1 ) {
153+
136154 int end = indexOf (key , start + 1 , SUBKEY_END );
137- if (end != -1 && end != start + 1 ) {
138155
156+ if (end != -1 && end != start + 1 ) {
139157 finalKey = new byte [end - (start + 1 )];
140158 System .arraycopy (key , start + 1 , finalKey , 0 , finalKey .length );
141159 }
142160 }
161+
143162 return crc16 (finalKey ) % SLOT_COUNT ;
144163 }
145164
@@ -150,7 +169,6 @@ private static int indexOf(byte[] haystack, byte needle) {
150169 private static int indexOf (byte [] haystack , int start , byte needle ) {
151170
152171 for (int i = start ; i < haystack .length ; i ++) {
153-
154172 if (haystack [i ] == needle ) {
155173 return i ;
156174 }
@@ -166,6 +184,7 @@ private static int crc16(byte[] bytes) {
166184 for (byte b : bytes ) {
167185 crc = ((crc << 8 ) ^ LOOKUP_TABLE [((crc >>> 8 ) ^ (b & 0xFF )) & 0xFF ]);
168186 }
187+
169188 return crc & 0xFFFF ;
170189 }
171190}
0 commit comments