ClusterKeyRegistry.java
package redis.clients.jedis.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.IntPredicate;
import redis.clients.jedis.Protocol;
/**
* One registered hash tag per slot for cluster tests, shared by the mock-server fixtures and the
* scenario harness. The tag is found on first use and reused afterwards, so every test names a slot
* the same way. Every key handed out is {@code {tag}:name}: the tag pins the slot, the caller's
* name keeps keys of different tests (or workers) in the same slot apart. The bare tag is never
* exposed, so two callers cannot collide on a slot by accident.
*/
public final class ClusterKeyRegistry {
private static final ConcurrentMap<Integer, String> TAG_BY_SLOT = new ConcurrentHashMap<>();
private ClusterKeyRegistry() {
}
/** A key named {@code name} in {@code slot}. */
public static String keyForSlot(int slot, String name) {
return "{" + tagForSlot(slot) + "}:" + name;
}
/** A key named {@code name} in the first slot of the inclusive range {@code [from, to]}. */
public static String keyInRange(int from, int to, String name) {
if (from > to) {
throw new IllegalArgumentException("empty range: [" + from + ", " + to + "]");
}
return keyForSlot(from, name);
}
/** A key named {@code name} in the first slot satisfying {@code slotMatches}. */
public static String keyMatching(IntPredicate slotMatches, String name) {
for (int slot = 0; slot < Protocol.CLUSTER_HASHSLOTS; slot++) {
if (slotMatches.test(slot)) {
return keyForSlot(slot, name);
}
}
throw new IllegalArgumentException("no slot satisfies the predicate");
}
/** The registered tag of {@code slot}, found on first use. */
private static String tagForSlot(int slot) {
if (slot < 0 || slot >= Protocol.CLUSTER_HASHSLOTS) {
throw new IllegalArgumentException("slot out of range: " + slot);
}
return TAG_BY_SLOT.computeIfAbsent(slot, ClusterKeyRegistry::findTag);
}
/** The lowest decimal string whose CRC16 is {@code slot}; deterministic across runs. */
private static String findTag(int slot) {
for (int i = 0;; i++) {
String tag = Integer.toString(i);
if (JedisClusterCRC16.getSlot(tag) == slot) {
return tag;
}
}
}
}