Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.redisson.spring.data.connection.RedissonClusterConnection Maven / Gradle / Ivy
/**
* Copyright (c) 2013-2024 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.data.connection;
import org.redisson.api.BatchResult;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.client.codec.ByteArrayCodec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.client.protocol.decoder.ObjectDecoder;
import org.redisson.client.protocol.decoder.ObjectListReplayDecoder;
import org.redisson.client.protocol.decoder.StringMapDataDecoder;
import org.redisson.command.CommandBatchService;
import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.MasterSlaveEntry;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.redis.connection.ClusterInfo;
import org.springframework.data.redis.connection.DefaultedRedisClusterConnection;
import org.springframework.data.redis.connection.RedisClusterNode;
import org.springframework.data.redis.connection.RedisClusterNode.SlotRange;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanCursor;
import org.springframework.data.redis.core.ScanIteration;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
/**
*
* @author Nikita Koksharov
*
*/
public class RedissonClusterConnection extends RedissonConnection implements DefaultedRedisClusterConnection {
private static final RedisStrictCommand> CLUSTER_NODES =
new RedisStrictCommand>("CLUSTER", "NODES", new ObjectDecoder(new RedisClusterNodeDecoder()));
public RedissonClusterConnection(RedissonClient redisson) {
super(redisson);
}
@Override
public Iterable clusterGetNodes() {
return read(null, StringCodec.INSTANCE, CLUSTER_NODES);
}
@Override
public Collection clusterGetSlaves(RedisClusterNode master) {
Iterable res = clusterGetNodes();
RedisClusterNode masterNode = null;
for (Iterator iterator = res.iterator(); iterator.hasNext();) {
RedisClusterNode redisClusterNode = iterator.next();
if (master.getHost().equals(redisClusterNode.getHost())
&& master.getPort().equals(redisClusterNode.getPort())) {
masterNode = redisClusterNode;
break;
}
}
if (masterNode == null) {
throw new IllegalStateException("Unable to find master node: " + master);
}
for (Iterator iterator = res.iterator(); iterator.hasNext();) {
RedisClusterNode redisClusterNode = iterator.next();
if (redisClusterNode.getMasterId() == null
|| !redisClusterNode.getMasterId().equals(masterNode.getId())) {
iterator.remove();
}
}
return (Collection) res;
}
@Override
public Map> clusterGetMasterSlaveMap() {
Iterable res = clusterGetNodes();
Set masters = new HashSet();
for (Iterator iterator = res.iterator(); iterator.hasNext();) {
RedisClusterNode redisClusterNode = iterator.next();
if (redisClusterNode.isMaster()) {
masters.add(redisClusterNode);
}
}
Map> result = new HashMap>();
for (Iterator iterator = res.iterator(); iterator.hasNext();) {
RedisClusterNode redisClusterNode = iterator.next();
for (RedisClusterNode masterNode : masters) {
if (redisClusterNode.getMasterId() != null
&& redisClusterNode.getMasterId().equals(masterNode.getId())) {
Collection list = result.get(masterNode);
if (list == null) {
list = new ArrayList();
result.put(masterNode, list);
}
list.add(redisClusterNode);
}
}
}
return result;
}
@Override
public Integer clusterGetSlotForKey(byte[] key) {
RFuture f = executorService.readAsync((String)null, StringCodec.INSTANCE, RedisCommands.KEYSLOT, key);
return syncFuture(f);
}
@Override
public RedisClusterNode clusterGetNodeForSlot(int slot) {
Iterable res = clusterGetNodes();
for (RedisClusterNode redisClusterNode : res) {
if (redisClusterNode.isMaster() && redisClusterNode.getSlotRange().contains(slot)) {
return redisClusterNode;
}
}
return null;
}
@Override
public RedisClusterNode clusterGetNodeForKey(byte[] key) {
int slot = executorService.getConnectionManager().calcSlot(key);
return clusterGetNodeForSlot(slot);
}
@Override
public ClusterInfo clusterGetClusterInfo() {
RFuture> f = executorService.readAsync((String)null, StringCodec.INSTANCE, RedisCommands.CLUSTER_INFO);
Map entries = syncFuture(f);
Properties props = new Properties();
for (Entry entry : entries.entrySet()) {
props.setProperty(entry.getKey(), entry.getValue());
}
return new ClusterInfo(props);
}
@Override
public void clusterAddSlots(RedisClusterNode node, int... slots) {
RedisClient entry = getEntry(node);
List params = convert(slots);
RFuture> f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CLUSTER_ADDSLOTS, params.toArray());
syncFuture(f);
}
protected List convert(int... slots) {
List params = new ArrayList();
for (int slot : slots) {
params.add(slot);
}
return params;
}
@Override
public void clusterAddSlots(RedisClusterNode node, SlotRange range) {
clusterAddSlots(node, range.getSlotsArray());
}
@Override
public Long clusterCountKeysInSlot(int slot) {
RedisClusterNode node = clusterGetNodeForSlot(slot);
MasterSlaveEntry entry = executorService.getConnectionManager().getEntry(new InetSocketAddress(node.getHost(), node.getPort()));
RFuture f = executorService.readAsync(entry, StringCodec.INSTANCE, RedisCommands.CLUSTER_COUNTKEYSINSLOT, slot);
return syncFuture(f);
}
@Override
public void clusterDeleteSlots(RedisClusterNode node, int... slots) {
RedisClient entry = getEntry(node);
List params = convert(slots);
RFuture f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CLUSTER_DELSLOTS, params.toArray());
syncFuture(f);
}
@Override
public void clusterDeleteSlotsInRange(RedisClusterNode node, SlotRange range) {
clusterDeleteSlots(node, range.getSlotsArray());
}
@Override
public void clusterForget(RedisClusterNode node) {
RFuture f = executorService.writeAsync((String)null, StringCodec.INSTANCE, RedisCommands.CLUSTER_FORGET, node.getId());
syncFuture(f);
}
@Override
public void clusterMeet(RedisClusterNode node) {
Assert.notNull(node, "Cluster node must not be null for CLUSTER MEET command!");
Assert.hasText(node.getHost(), "Node to meet cluster must have a host!");
Assert.isTrue(node.getPort() > 0, "Node to meet cluster must have a port greater 0!");
RFuture f = executorService.writeAsync((String)null, StringCodec.INSTANCE, RedisCommands.CLUSTER_MEET, node.getHost(), node.getPort());
syncFuture(f);
}
@Override
public void clusterSetSlot(RedisClusterNode node, int slot, AddSlots mode) {
RedisClient entry = getEntry(node);
RFuture> f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CLUSTER_SETSLOT, slot, mode);
syncFuture(f);
}
private static final RedisStrictCommand> CLUSTER_GETKEYSINSLOT = new RedisStrictCommand>("CLUSTER", "GETKEYSINSLOT", new ObjectListReplayDecoder());
@Override
public List clusterGetKeysInSlot(int slot, Integer count) {
RFuture> f = executorService.readAsync((String)null, ByteArrayCodec.INSTANCE, CLUSTER_GETKEYSINSLOT, slot, count);
return syncFuture(f);
}
@Override
public void clusterReplicate(RedisClusterNode master, RedisClusterNode slave) {
RedisClient entry = getEntry(master);
RFuture f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CLUSTER_REPLICATE, slave.getId());
syncFuture(f);
}
@Override
public String ping(RedisClusterNode node) {
return execute(node, RedisCommands.PING);
}
@Override
public void bgReWriteAof(RedisClusterNode node) {
execute(node, RedisCommands.BGREWRITEAOF);
}
@Override
public void bgSave(RedisClusterNode node) {
execute(node, RedisCommands.BGSAVE);
}
@Override
public Long lastSave(RedisClusterNode node) {
return execute(node, RedisCommands.LASTSAVE);
}
@Override
public void save(RedisClusterNode node) {
execute(node, RedisCommands.SAVE);
}
@Override
public Long dbSize(RedisClusterNode node) {
return execute(node, RedisCommands.DBSIZE);
}
private T execute(RedisClusterNode node, RedisCommand command) {
RedisClient entry = getEntry(node);
RFuture f = executorService.writeAsync(entry, StringCodec.INSTANCE, command);
return syncFuture(f);
}
protected RedisClient getEntry(RedisClusterNode node) {
InetSocketAddress addr = new InetSocketAddress(node.getHost(), node.getPort());
MasterSlaveEntry entry = executorService.getConnectionManager().getEntry(addr);
ClientConnectionsEntry e = entry.getEntry(addr);
return e.getClient();
}
@Override
public void flushDb(RedisClusterNode node) {
execute(node, RedisCommands.FLUSHDB);
}
@Override
public void flushAll(RedisClusterNode node) {
execute(node, RedisCommands.FLUSHALL);
}
@Override
public Properties info(RedisClusterNode node) {
Map info = execute(node, RedisCommands.INFO_ALL);
Properties result = new Properties();
for (Entry entry : info.entrySet()) {
result.setProperty(entry.getKey(), entry.getValue());
}
return result;
}
@Override
public Properties info(RedisClusterNode node, String section) {
RedisStrictCommand> command = new RedisStrictCommand>("INFO", section, new StringMapDataDecoder());
Map info = execute(node, command);
Properties result = new Properties();
for (Entry entry : info.entrySet()) {
result.setProperty(entry.getKey(), entry.getValue());
}
return result;
}
private final RedisStrictCommand> KEYS = new RedisStrictCommand<>("KEYS");
@Override
public Set keys(RedisClusterNode node, byte[] pattern) {
RedisClient entry = getEntry(node);
RFuture> f = executorService.readAsync(entry, ByteArrayCodec.INSTANCE, KEYS, pattern);
Collection keys = syncFuture(f);
return new HashSet<>(keys);
}
@Override
public byte[] randomKey(RedisClusterNode node) {
RedisClient entry = getEntry(node);
RFuture f = executorService.readRandomAsync(entry, ByteArrayCodec.INSTANCE, RedisCommands.RANDOM_KEY);
return syncFuture(f);
}
@Override
public void shutdown(RedisClusterNode node) {
RedisClient entry = getEntry(node);
RFuture f = executorService.readAsync(entry, ByteArrayCodec.INSTANCE, RedisCommands.SHUTDOWN);
syncFuture(f);
}
@Override
public Properties getConfig(RedisClusterNode node, String pattern) {
RedisClient entry = getEntry(node);
RFuture> f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CONFIG_GET, pattern);
List r = syncFuture(f);
if (r != null) {
return Converters.toProperties(r);
}
return null;
}
@Override
public void setConfig(RedisClusterNode node, String param, String value) {
RedisClient entry = getEntry(node);
RFuture f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CONFIG_SET, param, value);
syncFuture(f);
}
@Override
public void resetConfigStats(RedisClusterNode node) {
RedisClient entry = getEntry(node);
RFuture f = executorService.writeAsync(entry, StringCodec.INSTANCE, RedisCommands.CONFIG_RESETSTAT);
syncFuture(f);
}
@Override
public Long time(RedisClusterNode node) {
RedisClient entry = getEntry(node);
RFuture f = executorService.readAsync(entry, LongCodec.INSTANCE, RedisCommands.TIME_LONG);
return syncFuture(f);
}
private static final StringToRedisClientInfoConverter CONVERTER = new StringToRedisClientInfoConverter();
@Override
public List getClientList(RedisClusterNode node) {
RedisClient entry = getEntry(node);
RFuture> f = executorService.readAsync(entry, StringCodec.INSTANCE, RedisCommands.CLIENT_LIST);
List list = syncFuture(f);
return CONVERTER.convert(list.toArray(new String[list.size()]));
}
@Override
public Cursor scan(RedisClusterNode node, ScanOptions options) {
return new ScanCursor(0, options) {
private RedisClient client = getEntry(node);
@Override
protected ScanIteration doScan(long cursorId, ScanOptions options) {
if (isQueueing() || isPipelined()) {
throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode.");
}
if (client == null) {
return null;
}
List args = new ArrayList();
if (cursorId == 101010101010101010L) {
cursorId = 0;
}
args.add(Long.toUnsignedString(cursorId));
if (options.getPattern() != null) {
args.add("MATCH");
args.add(options.getPattern());
}
if (options.getCount() != null) {
args.add("COUNT");
args.add(options.getCount());
}
RFuture> f = executorService.readAsync(client, ByteArrayCodec.INSTANCE, RedisCommands.SCAN, args.toArray());
ListScanResult res = syncFuture(f);
String pos = res.getPos();
client = res.getRedisClient();
if ("0".equals(pos)) {
client = null;
}
return new ScanIteration(Long.parseUnsignedLong(pos), res.getValues());
}
}.open();
}
@Override
public void rename(byte[] oldName, byte[] newName) {
if (isPipelined()) {
throw new InvalidDataAccessResourceUsageException("Clustered rename is not supported in a pipeline");
}
if (redisson.getConnectionManager().calcSlot(oldName) == redisson.getConnectionManager().calcSlot(newName)) {
super.rename(oldName, newName);
return;
}
final byte[] value = dump(oldName);
if (null != value) {
final Long sourceTtlInSeconds = ttl(oldName);
final long ttlInMilliseconds;
if (null != sourceTtlInSeconds && sourceTtlInSeconds > 0) {
ttlInMilliseconds = sourceTtlInSeconds * 1000;
} else {
ttlInMilliseconds = 0;
}
restore(newName, ttlInMilliseconds, value);
del(oldName);
}
}
@Override
public Boolean renameNX(byte[] oldName, byte[] newName) {
if (isPipelined()) {
throw new InvalidDataAccessResourceUsageException("Clustered rename is not supported in a pipeline");
}
if (redisson.getConnectionManager().calcSlot(oldName) == redisson.getConnectionManager().calcSlot(newName)) {
return super.renameNX(oldName, newName);
}
final byte[] value = dump(oldName);
if (null != value && !exists(newName)) {
final Long sourceTtlInSeconds = ttl(oldName);
final long ttlInMilliseconds;
if (null != sourceTtlInSeconds && sourceTtlInSeconds > 0) {
ttlInMilliseconds = sourceTtlInSeconds * 1000;
} else {
ttlInMilliseconds = 0;
}
restore(newName, ttlInMilliseconds, value);
del(oldName);
return true;
}
return false;
}
@Override
public Long del(byte[]... keys) {
if (isQueueing() || isPipelined()) {
for (byte[] key: keys) {
write(key, LongCodec.INSTANCE, RedisCommands.DEL, key);
}
return null;
}
CommandBatchService es = new CommandBatchService(executorService);
for (byte[] key: keys) {
es.writeAsync(key, StringCodec.INSTANCE, RedisCommands.DEL, key);
}
BatchResult b = (BatchResult) es.execute();
return b.getResponses().stream().collect(Collectors.summarizingLong(v -> v)).getSum();
}
@Override
public List mGet(byte[]... keys) {
if (isQueueing() || isPipelined()) {
for (byte[] key : keys) {
read(key, ByteArrayCodec.INSTANCE, RedisCommands.GET, key);
}
return null;
}
CommandBatchService es = new CommandBatchService(executorService);
for (byte[] key: keys) {
es.readAsync(key, ByteArrayCodec.INSTANCE, RedisCommands.GET, key);
}
BatchResult r = (BatchResult) es.execute();
return r.getResponses();
}
@Override
public Boolean mSet(Map tuple) {
if (isQueueing() || isPipelined()) {
for (Entry entry: tuple.entrySet()) {
write(entry.getKey(), StringCodec.INSTANCE, RedisCommands.SET, entry.getKey(), entry.getValue());
}
return true;
}
CommandBatchService es = new CommandBatchService(executorService);
for (Entry entry: tuple.entrySet()) {
es.writeAsync(entry.getKey(), StringCodec.INSTANCE, RedisCommands.SET, entry.getKey(), entry.getValue());
}
es.execute();
return true;
}
}