diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java index 352fee80a8..b7a0cae4d9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java @@ -5,8 +5,12 @@ import java.io.Serializable; import java.util.Collections; import java.util.List; +import java.util.Set; +import com.google.common.collect.Lists; import com.google.common.net.HostAndPort; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** * Represents a range of slots together with its master and slaves. @@ -18,9 +22,17 @@ public class ClusterSlotRange implements Serializable { private int from; private int to; + + @Deprecated private HostAndPort master; + + private RedisClusterNode masterNode; + + @Deprecated private List slaves = Collections.emptyList(); + private List slaveNodes = Collections.emptyList(); + public ClusterSlotRange() { } @@ -32,7 +44,9 @@ public ClusterSlotRange() { * @param to to slot * @param master master for the slots, may be {@literal null} * @param slaves list of slaves must not be {@literal null} but may be empty + * @deprecated Use {@link #ClusterSlotRange(int, int, RedisClusterNode, List)} */ + @Deprecated public ClusterSlotRange(int from, int to, HostAndPort master, List slaves) { checkArgument(master != null, "master must not be null"); @@ -40,10 +54,63 @@ public ClusterSlotRange(int from, int to, HostAndPort master, List this.from = from; this.to = to; + this.masterNode = toRedisClusterNode(master, null, Collections.singleton(RedisClusterNode.NodeFlag.MASTER)); + this.slaveNodes = toRedisClusterNodes(slaves, null, Collections.singleton(RedisClusterNode.NodeFlag.SLAVE)); this.master = master; this.slaves = slaves; } + /** + * Constructs a {@link ClusterSlotRange} + * + * @param from from slot + * @param to to slot + * @param masterNode master for the slots, may be {@literal null} + * @param slaveNodes list of slaves must not be {@literal null} but may be empty + */ + public ClusterSlotRange(int from, int to, RedisClusterNode masterNode, List slaveNodes) { + + checkArgument(masterNode != null, "masterNode must not be null"); + checkArgument(slaveNodes != null, "slaveNodes must not be null"); + + this.from = from; + this.to = to; + this.master = toHostAndPort(masterNode); + this.slaves = toHostAndPorts(slaveNodes); + this.masterNode = masterNode; + this.slaveNodes = slaveNodes; + } + + private HostAndPort toHostAndPort(RedisClusterNode redisClusterNode) { + RedisURI uri = redisClusterNode.getUri(); + return HostAndPort.fromParts(uri.getHost(), uri.getPort()); + } + + private List toHostAndPorts(List nodes) { + List result = Lists.newArrayList(); + for (RedisClusterNode node : nodes) { + result.add(toHostAndPort(node)); + } + return result; + } + + private RedisClusterNode toRedisClusterNode(HostAndPort hostAndPort, String slaveOf, Set flags) { + RedisClusterNode redisClusterNode = new RedisClusterNode(); + redisClusterNode.setUri(RedisURI + .create(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(RedisURI.DEFAULT_REDIS_PORT))); + redisClusterNode.setSlaveOf(slaveOf); + redisClusterNode.setFlags(flags); + return redisClusterNode; + } + + private List toRedisClusterNodes(List hostAndPorts, String slaveOf, Set flags) { + List result = Lists.newArrayList(); + for (HostAndPort hostAndPort : hostAndPorts) { + result.add(toRedisClusterNode(hostAndPort, slaveOf, flags)); + } + return result; + } + public int getFrom() { return from; } @@ -52,14 +119,40 @@ public int getTo() { return to; } + /** + * @deprecated Use {@link #getMasterNode()} to retrieve the {@code nodeId} and the {@code slaveOf} details. + * @return the master host and port + */ + @Deprecated public HostAndPort getMaster() { return master; } + /** + * @deprecated Use {@link #getSlaveNodes()} to retrieve the {@code nodeId} and the {@code slaveOf} details. + * @return the master host and port + */ + @Deprecated public List getSlaves() { return slaves; } + public RedisClusterNode getMasterNode() { + return masterNode; + } + + public void setMasterNode(RedisClusterNode masterNode) { + this.masterNode = masterNode; + } + + public List getSlaveNodes() { + return slaveNodes; + } + + public void setSlaveNodes(List slaveNodes) { + this.slaveNodes = slaveNodes; + } + public void setFrom(int from) { this.from = from; } @@ -85,8 +178,8 @@ public String toString() { sb.append(getClass().getSimpleName()); sb.append(" [from=").append(from); sb.append(", to=").append(to); - sb.append(", master=").append(master); - sb.append(", slaves=").append(slaves); + sb.append(", masterNode=").append(masterNode); + sb.append(", slaveNodes=").append(slaveNodes); sb.append(']'); return sb.toString(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java index fec3b35349..58bb147ce0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java @@ -6,8 +6,9 @@ import java.util.List; import com.google.common.collect.Lists; -import com.google.common.net.HostAndPort; import com.google.common.primitives.Ints; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** * Parser for redis CLUSTER SLOTS command output. @@ -64,16 +65,21 @@ private static ClusterSlotRange parseRange(List range) { int from = Ints.checkedCast(getLongFromIterator(iterator, 0)); int to = Ints.checkedCast(getLongFromIterator(iterator, 0)); - HostAndPort master = null; + RedisClusterNode master = null; - List slaves = Lists.newArrayList(); + List slaves = Lists.newArrayList(); if (iterator.hasNext()) { - master = getHostAndPort(iterator); + master = getRedisClusterNode(iterator); + if(master != null) { + master.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.MASTER)); + } } while (iterator.hasNext()) { - HostAndPort slave = getHostAndPort(iterator); + RedisClusterNode slave = getRedisClusterNode(iterator); if (slave != null) { + slave.setSlaveOf(master.getNodeId()); + slave.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.SLAVE)); slaves.add(slave); } } @@ -81,20 +87,28 @@ private static ClusterSlotRange parseRange(List range) { return new ClusterSlotRange(from, to, master, Collections.unmodifiableList(slaves)); } - private static HostAndPort getHostAndPort(Iterator iterator) { + private static RedisClusterNode getRedisClusterNode(Iterator iterator) { Object element = iterator.next(); if (element instanceof List) { List hostAndPortList = (List) element; - if (hostAndPortList.size() != 2) { + if (hostAndPortList.size() < 2) { return null; } Iterator hostAndPortIterator = hostAndPortList.iterator(); String host = (String) hostAndPortIterator.next(); int port = Ints.checkedCast(getLongFromIterator(hostAndPortIterator, 0)); - HostAndPort hostAndPort = HostAndPort.fromParts(host, port); + String nodeId; + + RedisClusterNode redisClusterNode = new RedisClusterNode(); + redisClusterNode.setUri(RedisURI.create(host, port)); + + if (hostAndPortIterator.hasNext()) { + nodeId = (String) hostAndPortIterator.next(); + redisClusterNode.setNodeId(nodeId); + } - return hostAndPort; + return redisClusterNode; } return null; diff --git a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java index d94151fa85..142d2d9bf1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java @@ -4,6 +4,7 @@ import java.util.List; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import org.junit.Test; import com.google.common.collect.ImmutableList; @@ -39,10 +40,71 @@ public void testParse() throws Exception { assertThat(result).hasSize(1); assertThat(result.get(0).getMaster()).isNotNull(); + assertThat(result.get(0).getMasterNode()).isNotNull(); } @Test public void testParseWithSlave() throws Exception { + List list = ImmutableList.of(Lists.newArrayList("0", "1", Lists.newArrayList("1", "2", "nodeId1"), Lists.newArrayList("1", 2, "nodeId2"))); + List result = ClusterSlotsParser.parse(list); + assertThat(result).hasSize(1); + ClusterSlotRange clusterSlotRange = result.get(0); + + assertThat(clusterSlotRange.getMaster()).isNotNull(); + assertThat(clusterSlotRange.getMaster().getHostText()).isEqualTo("1"); + assertThat(clusterSlotRange.getMaster().getPort()).isEqualTo(2); + + RedisClusterNode masterNode = clusterSlotRange.getMasterNode(); + assertThat(masterNode).isNotNull(); + assertThat(masterNode.getNodeId()).isEqualTo("nodeId1"); + assertThat(masterNode.getUri().getHost()).isEqualTo("1"); + assertThat(masterNode.getUri().getPort()).isEqualTo(2); + assertThat(masterNode.getFlags()).contains(RedisClusterNode.NodeFlag.MASTER); + + assertThat(clusterSlotRange.getSlaves()).hasSize(1); + assertThat(clusterSlotRange.getSlaveNodes()).hasSize(1); + + HostAndPort slave = clusterSlotRange.getSlaves().get(0); + assertThat(slave.getHostText()).isEqualTo("1"); + assertThat(slave.getPort()).isEqualTo(2); + + RedisClusterNode slaveNode = clusterSlotRange.getSlaveNodes().get(0); + + assertThat(slaveNode.getNodeId()).isEqualTo("nodeId2"); + assertThat(slaveNode.getSlaveOf()).isEqualTo("nodeId1"); + assertThat(slaveNode.getFlags()).contains(RedisClusterNode.NodeFlag.SLAVE); + } + + @Test + public void testHostAndPortConstructor() throws Exception { + + ClusterSlotRange clusterSlotRange = new ClusterSlotRange(100,200,HostAndPort.fromParts("1", 2), ImmutableList.of( + HostAndPort.fromParts("1", 2))); + + RedisClusterNode masterNode = clusterSlotRange.getMasterNode(); + assertThat(masterNode).isNotNull(); + assertThat(masterNode.getNodeId()).isNull(); + assertThat(masterNode.getUri().getHost()).isEqualTo("1"); + assertThat(masterNode.getUri().getPort()).isEqualTo(2); + assertThat(masterNode.getFlags()).contains(RedisClusterNode.NodeFlag.MASTER); + + assertThat(clusterSlotRange.getSlaves()).hasSize(1); + assertThat(clusterSlotRange.getSlaveNodes()).hasSize(1); + + HostAndPort slave = clusterSlotRange.getSlaves().get(0); + assertThat(slave.getHostText()).isEqualTo("1"); + assertThat(slave.getPort()).isEqualTo(2); + + RedisClusterNode slaveNode = clusterSlotRange.getSlaveNodes().get(0); + + assertThat(slaveNode.getNodeId()).isNull(); + assertThat(slaveNode.getSlaveOf()).isNull(); + assertThat(slaveNode.getFlags()).contains(RedisClusterNode.NodeFlag.SLAVE); + + } + + @Test + public void testParseWithSlaveAndNodeIds() throws Exception { List list = ImmutableList.of(Lists.newArrayList("0", "1", Lists.newArrayList("1", "2"), Lists.newArrayList("1", 2))); List result = ClusterSlotsParser.parse(list); assertThat(result).hasSize(1); @@ -72,6 +134,5 @@ public void testModel() throws Exception { range.setMaster(HostAndPort.fromHost("localhost")); assertThat(range.toString()).contains(ClusterSlotRange.class.getSimpleName()); - } }