23
23
import org .springframework .util .Assert ;
24
24
25
25
/**
26
+ * Utility class encapsulating functionality commonly used for cluster slot hashing.
27
+ *
26
28
* @author Christoph Strobl
29
+ * @author John Blum
27
30
* @since 1.7
28
31
*/
29
- public final class ClusterSlotHashUtil {
32
+ public abstract class ClusterSlotHashUtil {
30
33
31
34
public static final int SLOT_COUNT = 16384 ;
32
35
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 = '}' ;
35
38
36
39
private static final int [] LOOKUP_TABLE = { 0x0000 , 0x1021 , 0x2042 , 0x3063 , 0x4084 , 0x50A5 , 0x60C6 , 0x70E7 , 0x8108 ,
37
40
0x9129 , 0xA14A , 0xB16B , 0xC18C , 0xD1AD , 0xE1CE , 0xF1EF , 0x1231 , 0x0210 , 0x3273 , 0x2252 , 0x52B5 , 0x4294 , 0x72F7 ,
@@ -53,93 +56,109 @@ public final class ClusterSlotHashUtil {
53
56
0x6C07 , 0x5C64 , 0x4C45 , 0x3CA2 , 0x2C83 , 0x1CE0 , 0x0CC1 , 0xEF1F , 0xFF3E , 0xCF5D , 0xDF7C , 0xAF9B , 0xBFBA , 0x8FD9 ,
54
57
0x9FF8 , 0x6E17 , 0x7E36 , 0x4E55 , 0x5E74 , 0x2E93 , 0x3EB2 , 0x0ED1 , 0x1EF0 };
55
58
56
- private ClusterSlotHashUtil () {
57
-
58
- }
59
-
60
59
/**
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}.
64
65
*/
65
- public static boolean isSameSlotForAllKeys (Collection < ByteBuffer > keys ) {
66
+ public static boolean isSameSlotForAllKeys (byte []... keys ) {
66
67
67
68
Assert .notNull (keys , "Keys must not be null" );
68
69
69
- if (keys .size () <= 1 ) {
70
+ if (keys .length <= 1 ) {
70
71
return true ;
71
72
}
72
73
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 ;
77
83
}
78
84
79
85
/**
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)
82
92
* @since 2.0
83
93
*/
84
94
public static boolean isSameSlotForAllKeys (ByteBuffer ... keys ) {
85
95
86
96
Assert .notNull (keys , "Keys must not be null" );
97
+
87
98
return isSameSlotForAllKeys (Arrays .asList (keys ));
88
99
}
89
100
90
101
/**
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
93
109
*/
94
- public static boolean isSameSlotForAllKeys (byte []... keys ) {
110
+ public static boolean isSameSlotForAllKeys (Collection < ByteBuffer > keys ) {
95
111
96
112
Assert .notNull (keys , "Keys must not be null" );
97
113
98
- if (keys .length <= 1 ) {
114
+ if (keys .size () <= 1 ) {
99
115
return true ;
100
116
}
101
117
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 ));
109
122
}
110
123
111
124
/**
112
125
* Calculate the slot from the given key.
113
126
*
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[])
116
131
*/
117
132
public static int calculateSlot (String key ) {
118
133
119
134
Assert .hasText (key , "Key must not be null or empty" );
135
+
120
136
return calculateSlot (key .getBytes ());
121
137
}
122
138
123
139
/**
124
140
* Calculate the slot from the given key.
125
141
*
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.
128
144
*/
129
145
public static int calculateSlot (byte [] key ) {
130
146
131
147
Assert .notNull (key , "Key must not be null" );
132
148
133
149
byte [] finalKey = key ;
134
150
int start = indexOf (key , SUBKEY_START );
151
+
135
152
if (start != -1 ) {
153
+
136
154
int end = indexOf (key , start + 1 , SUBKEY_END );
137
- if (end != -1 && end != start + 1 ) {
138
155
156
+ if (end != -1 && end != start + 1 ) {
139
157
finalKey = new byte [end - (start + 1 )];
140
158
System .arraycopy (key , start + 1 , finalKey , 0 , finalKey .length );
141
159
}
142
160
}
161
+
143
162
return crc16 (finalKey ) % SLOT_COUNT ;
144
163
}
145
164
@@ -150,7 +169,6 @@ private static int indexOf(byte[] haystack, byte needle) {
150
169
private static int indexOf (byte [] haystack , int start , byte needle ) {
151
170
152
171
for (int i = start ; i < haystack .length ; i ++) {
153
-
154
172
if (haystack [i ] == needle ) {
155
173
return i ;
156
174
}
@@ -166,6 +184,7 @@ private static int crc16(byte[] bytes) {
166
184
for (byte b : bytes ) {
167
185
crc = ((crc << 8 ) ^ LOOKUP_TABLE [((crc >>> 8 ) ^ (b & 0xFF )) & 0xFF ]);
168
186
}
187
+
169
188
return crc & 0xFFFF ;
170
189
}
171
190
}
0 commit comments