@Override public byte[] randomKey() { List<RedisClusterNode> nodes = new ArrayList<>( connection.getTopologyProvider().getTopology().getActiveMasterNodes()); Set<RedisNode> inspectedNodes = new HashSet<>(nodes.size()); do { RedisClusterNode node = nodes.get(ThreadLocalRandom.current().nextInt(nodes.size())); while (inspectedNodes.contains(node)) { node = nodes.get(ThreadLocalRandom.current().nextInt(nodes.size())); } inspectedNodes.add(node); byte[] key = randomKey(node); if (key != null && key.length > 0) { return key; } } while (nodes.size() != inspectedNodes.size()); return null; }
@Nullable <T> T execute(String command, byte[] key, Collection<byte[]> args, Function<Client, T> responseMapper) { Assert.notNull(command, "Command must not be null!"); Assert.notNull(key, "Key must not be null!"); Assert.notNull(args, "Args must not be null!"); byte[][] commandArgs = getCommandArguments(key, args); RedisClusterNode keyMaster = topologyProvider.getTopology().getKeyServingMasterNode(key); return clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback<T>) client -> JedisClientUtils .execute(command, EMPTY_2D_BYTE_ARRAY, commandArgs, () -> client, responseMapper), keyMaster).getValue(); }
@Override public void clusterSetSlot(RedisClusterNode node, int slot, AddSlots mode) { Assert.notNull(node, "Node must not be null."); Assert.notNull(mode, "AddSlots mode must not be null."); RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(node); String nodeId = nodeToUse.getId(); clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback<String>) client -> { switch (mode) { case IMPORTING: return client.clusterSetSlotImporting(slot, nodeId); case MIGRATING: return client.clusterSetSlotMigrating(slot, nodeId); case STABLE: return client.clusterSetSlotStable(slot); case NODE: return client.clusterSetSlotNode(slot, nodeId); } throw new IllegalArgumentException(String.format("Unknown AddSlots mode '%s'.", mode)); }, node); }
@Override public Long pTtl(byte[] key) { Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback<Long>) client -> client.pttl(key), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue(); }
@Override public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(target, "Target node must not be null!"); int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; RedisClusterNode node = connection.getTopologyProvider().getTopology().lookup(target.getHost(), target.getPort()); executeCommandOnSingleNode(client -> client.migrate(JedisConverters.toBytes(target.getHost()), target.getPort(), key, dbIndex, timeoutToUse), node); }
@Override public Long pTtl(byte[] key, TimeUnit timeUnit) { Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode( (JedisClusterCommandCallback<Long>) client -> Converters.millisecondsToTimeUnit(client.pttl(key), timeUnit), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue(); }
@Override public Set<RedisClusterNode> clusterGetSlaves(RedisClusterNode master) { Assert.notNull(master, "Master cannot be null!"); RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); return JedisConverters.toSetOfRedisClusterNodes(clusterCommandExecutor .executeCommandOnSingleNode( (JedisClusterCommandCallback<List<String>>) client -> client.clusterSlaves(nodeToUse.getId()), master) .getValue()); }
@Nullable <T> T execute(String command, byte[] key, Collection<byte[]> args, Function<Client, T> responseMapper) { Assert.notNull(command, "Command must not be null!"); Assert.notNull(key, "Key must not be null!"); Assert.notNull(args, "Args must not be null!"); byte[][] commandArgs = getCommandArguments(key, args); RedisClusterNode keyMaster = topologyProvider.getTopology().getKeyServingMasterNode(key); return clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback<T>) client -> JedisClientUtils .execute(command, EMPTY_2D_BYTE_ARRAY, commandArgs, () -> client, responseMapper), keyMaster).getValue(); }
@Override public void clusterForget(RedisClusterNode node) { Set<RedisClusterNode> nodes = new LinkedHashSet<>(topologyProvider.getTopology().getActiveMasterNodes()); RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); nodes.remove(nodeToRemove); clusterCommandExecutor.executeCommandAsyncOnNodes( (JedisClusterCommandCallback<String>) client -> client.clusterForget(node.getId()), nodes); }
@Override public Map<RedisClusterNode, Collection<RedisClusterNode>> clusterGetMasterSlaveMap() { List<NodeResult<Collection<RedisClusterNode>>> nodeResults = clusterCommandExecutor .executeCommandAsyncOnNodes((JedisClusterCommandCallback<Collection<RedisClusterNode>>) client -> { // TODO: remove client.eval as soon as Jedis offers support for myid return JedisConverters.toSetOfRedisClusterNodes( client.clusterSlaves((String) client.eval("return redis.call('cluster', 'myid')", 0))); }, topologyProvider.getTopology().getActiveMasterNodes()).getResults(); Map<RedisClusterNode, Collection<RedisClusterNode>> result = new LinkedHashMap<>(); for (NodeResult<Collection<RedisClusterNode>> nodeResult : nodeResults) { result.put(nodeResult.getNode(), nodeResult.getValue()); } return result; }
@Override public byte[] dump(byte[] key) { Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback<byte[]>) client -> client.dump(key), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue(); }
@Override public Boolean pSetEx(byte[] key, long milliseconds, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return Converters.stringToBoolean(connection.getClusterCommandExecutor() .executeCommandOnSingleNode( (JedisClusterCommandCallback<String>) client -> client.psetex(key, milliseconds, value), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue()); }
@Override public RedisClusterNode clusterGetNodeForSlot(int slot) { for (RedisClusterNode node : topologyProvider.getTopology().getSlotServingNodes(slot)) { if (node.isMaster()) { return node; } } return null; }
@Override public void clusterReplicate(RedisClusterNode master, RedisClusterNode replica) { RedisClusterNode masterNode = topologyProvider.getTopology().lookup(master); clusterCommandExecutor.executeCommandOnSingleNode( (JedisClusterCommandCallback<String>) client -> client.clusterReplicate(masterNode.getId()), replica); }
@Override public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(target, "Target node must not be null!"); int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; RedisClusterNode node = connection.getTopologyProvider().getTopology().lookup(target.getHost(), target.getPort()); executeCommandOnSingleNode(client -> client.migrate(target.getHost(), target.getPort(), key, dbIndex, timeoutToUse), node); }
@Override public Long pTtl(byte[] key, TimeUnit timeUnit) { Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode( (JedisClusterCommandCallback<Long>) client -> Converters.millisecondsToTimeUnit(client.pttl(key), timeUnit), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue(); }
@Override public Set<RedisClusterNode> clusterGetNodes() { return topologyProvider.getTopology().getNodes(); }
@Override public Set<RedisClusterNode> clusterGetSlaves(RedisClusterNode master) { Assert.notNull(master, "Master cannot be null!"); RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); return JedisConverters.toSetOfRedisClusterNodes(clusterCommandExecutor .executeCommandOnSingleNode( (JedisClusterCommandCallback<List<String>>) client -> client.clusterSlaves(nodeToUse.getId()), master) .getValue()); }
@Override public void clusterForget(RedisClusterNode node) { Set<RedisClusterNode> nodes = new LinkedHashSet<>(topologyProvider.getTopology().getActiveMasterNodes()); RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); nodes.remove(nodeToRemove); clusterCommandExecutor.executeCommandAsyncOnNodes( (JedisClusterCommandCallback<String>) client -> client.clusterForget(node.getId()), nodes); }
@Override public Long pTtl(byte[] key) { Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback<Long>) client -> client.pttl(key), connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)) .getValue(); }