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.redkalex.cache.redis.RedissonCacheSource Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkalex.cache.redis;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
import java.util.logging.*;
import java.util.stream.Collectors;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.codec.*;
import org.redisson.client.protocol.*;
import org.redisson.config.*;
import org.redkale.annotation.AutoLoad;
import org.redkale.annotation.ResourceChanged;
import org.redkale.annotation.ResourceType;
import org.redkale.convert.Convert;
import org.redkale.inject.ResourceEvent;
import org.redkale.service.Local;
import org.redkale.source.*;
import org.redkale.util.*;
import static org.redkale.util.Utility.*;
/**
* //https://www.cnblogs.com/xiami2046/p/13934146.html
*
* @author zhangjx
*/
@Local
@AutoLoad(false)
@ResourceType(CacheSource.class)
@SourceType(RedisSource.class)
public class RedissonCacheSource extends RedisSource {
private final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
private List nodeAddrs;
private RedissonClient client;
// >
private final ConcurrentHashMap> pubsubListeners =
new ConcurrentHashMap<>();
private static final Codec SCAN_CODEC = new Codec() {
@Override
public Decoder getMapValueDecoder() {
return ByteArrayCodec.INSTANCE.getMapValueDecoder();
}
@Override
public Encoder getMapValueEncoder() {
return ByteArrayCodec.INSTANCE.getMapValueEncoder();
}
@Override
public Decoder getMapKeyDecoder() {
return StringCodec.INSTANCE.getMapKeyDecoder();
}
@Override
public Encoder getMapKeyEncoder() {
return StringCodec.INSTANCE.getMapKeyEncoder();
}
@Override
public Decoder getValueDecoder() {
return ByteArrayCodec.INSTANCE.getMapValueDecoder();
}
@Override
public Encoder getValueEncoder() {
return StringCodec.INSTANCE.getValueEncoder();
}
@Override
public ClassLoader getClassLoader() {
return ByteArrayCodec.INSTANCE.getClassLoader();
}
};
@Override
public void init(AnyValue conf) {
super.init(conf);
if (conf == null) {
conf = AnyValue.create();
}
initClient(conf);
}
private void initClient(AnyValue conf) {
RedisConfig config = RedisConfig.create(conf);
Config redisConfig = new Config();
String cluster = conf.getOrDefault("cluster", "");
BaseConfig baseConfig = null;
SingleServerConfig singleConfig = null;
ClusterServersConfig clusterConfig = null;
ReplicatedServersConfig replicateConfig = null;
SentinelServersConfig sentinelConfig = null;
int max = config.getMaxconns(2);
for (String addr : config.getAddresses()) {
if (config.getAddresses().size() == 1) { // 单体
if (singleConfig == null) {
singleConfig = redisConfig.useSingleServer();
singleConfig.setConnectionMinimumIdleSize(max / 2 + 1);
singleConfig.setConnectionPoolSize(max);
baseConfig = singleConfig;
}
singleConfig.setAddress(addr);
singleConfig.setDatabase(this.db);
} else if ("cluster".equalsIgnoreCase(cluster)) { // 集群
if (clusterConfig == null) {
clusterConfig = redisConfig.useClusterServers();
clusterConfig.setMasterConnectionMinimumIdleSize(max / 2 + 1);
clusterConfig.setMasterConnectionPoolSize(max);
clusterConfig.setSlaveConnectionMinimumIdleSize(max / 2 + 1);
clusterConfig.setSlaveConnectionPoolSize(max);
baseConfig = clusterConfig;
}
clusterConfig.addNodeAddress(addr);
} else if ("replicated".equalsIgnoreCase(cluster)) { // 主从
if (replicateConfig == null) {
replicateConfig = redisConfig.useReplicatedServers();
replicateConfig.setMasterConnectionMinimumIdleSize(max / 2 + 1);
replicateConfig.setMasterConnectionPoolSize(max);
replicateConfig.setSlaveConnectionMinimumIdleSize(max / 2 + 1);
replicateConfig.setSlaveConnectionPoolSize(max);
baseConfig = replicateConfig;
}
replicateConfig.addNodeAddress(addr);
replicateConfig.setDatabase(this.db);
} else if ("sentinel".equalsIgnoreCase(cluster)) { // 哨兵
if (sentinelConfig == null) {
sentinelConfig = redisConfig.useSentinelServers();
sentinelConfig.setMasterConnectionMinimumIdleSize(max / 2 + 1);
sentinelConfig.setMasterConnectionPoolSize(max);
sentinelConfig.setSlaveConnectionMinimumIdleSize(max / 2 + 1);
sentinelConfig.setSlaveConnectionPoolSize(max);
baseConfig = sentinelConfig;
}
sentinelConfig.addSentinelAddress(addr);
sentinelConfig.setDatabase(this.db);
}
if (baseConfig != null) { // 单个进程的不同自定义密码
if (config.getUsername() != null) {
baseConfig.setUsername(config.getUsername());
}
if (config.getPassword() != null) {
baseConfig.setPassword(config.getPassword());
}
}
}
if (baseConfig != null) { // 配置全局密码
String username = conf.getValue(CACHE_SOURCE_USER, "").trim();
String password = conf.getValue(CACHE_SOURCE_PASSWORD, "").trim();
String retryAttempts = conf.getValue("retryAttempts", "").trim();
String retryInterval = conf.getValue("retryInterval", "").trim();
if (!username.isEmpty()) {
baseConfig.setUsername(username);
}
if (!password.isEmpty()) {
baseConfig.setPassword(password);
}
if (!retryAttempts.isEmpty()) {
baseConfig.setRetryAttempts(Integer.parseInt(retryAttempts));
}
if (!retryInterval.isEmpty()) {
baseConfig.setRetryInterval(Integer.parseInt(retryInterval));
}
}
RedissonClient old = this.client;
this.client = Redisson.create(redisConfig);
this.nodeAddrs = config.getAddresses();
if (old != null) {
old.shutdown();
}
if (!pubsubListeners.isEmpty()) {
reloadSubConn();
}
// RTopic topic = client.getTopic("__keyevent@" + db + "__:expired", new StringCodec());
// topic.addListener(String.class, (CharSequence cs, String key) -> {
// if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE,
// RedissonCacheSource.class.getSimpleName() + "." + db + ": expired key=" + key + ", cs=" + cs);
// });
// if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedissonCacheSource.class.getSimpleName() + ":
// addrs=" + addresses + ", db=" + db);
}
@Override
@ResourceChanged
public void onResourceChange(ResourceEvent[] events) {
if (Utility.isEmpty(events)) {
return;
}
StringBuilder sb = new StringBuilder();
for (ResourceEvent event : events) {
sb.append("CacheSource(name=")
.append(resourceName())
.append(") change '")
.append(event.name())
.append("' to '")
.append(event.coverNewValue())
.append("'\r\n");
}
initClient(this.conf);
if (sb.length() > 0) {
logger.log(Level.INFO, sb.toString());
}
}
@Override
public final String getType() {
return "redis";
}
@Override
public String toString() {
return getClass().getSimpleName() + "{addrs=" + this.nodeAddrs + ", db=" + this.db + "}";
}
@Local
public org.redisson.api.RedissonClient getRedisClient() {
return client;
}
protected CompletableFuture toFuture(CompletionStage rf) {
return rf.toCompletableFuture();
}
protected CompletableFuture toFuture(String key, RedisCryptor cryptor, CompletionStage rf) {
return cryptor != null
? rf.toCompletableFuture().thenApply(v -> cryptor.decrypt(key, v))
: rf.toCompletableFuture();
}
protected CompletableFuture toFuture(
String key, RedisCryptor cryptor, Type type, CompletionStage rf) {
return rf.toCompletableFuture().thenApply(bs -> decryptValue(key, cryptor, type, bs));
}
protected CompletableFuture toFuture(
String key, RedisCryptor cryptor, Convert c, Type type, CompletionStage rf) {
return rf.toCompletableFuture().thenApply(bs -> decryptValue(key, cryptor, c, type, bs));
}
protected Collection getCollectionValue(
String key, Collection bytesResult, boolean set, Type componentType) {
final Collection rs = set ? new LinkedHashSet<>() : new ArrayList<>();
Collection kvs = bytesResult;
for (byte[] bs : kvs) {
if (bs == null) {
rs.add(null);
} else if (componentType == String.class) {
rs.add((T) decryptValue(key, cryptor, new String(bs, StandardCharsets.UTF_8)));
} else {
rs.add((T) decryptValue(key, cryptor, componentType, bs));
}
}
return rs;
}
protected List getSortedListValue(String key, Collection bytesResult) {
final List rs = new ArrayList<>();
Collection kvs = bytesResult;
for (org.redisson.client.protocol.ScoredEntry bs : kvs) {
rs.add(bs.getValue().toString());
}
return rs;
}
@Override
public void destroy(AnyValue conf) {
super.destroy(conf);
if (client != null) {
client.shutdown();
}
}
protected void reloadSubConn() {
// 重连时重新订阅
if (!pubsubListeners.isEmpty()) {
final Map, HashSet> listeners = new HashMap<>();
pubsubListeners.forEach((l, s) -> {
listeners.computeIfAbsent(l, x -> new HashSet<>()).addAll(s.keySet());
});
listeners.forEach((listener, topics) -> {
subscribeAsync(listener, topics.toArray(Creator.funcStringArray()));
});
}
}
@Override
public CompletableFuture isOpenAsync() {
return CompletableFuture.completedFuture(client != null && !client.isShutdown());
}
// ------------------------ 订阅发布 SUB/PUB ------------------------
@Override
public CompletableFuture> pubsubChannelsAsync(String pattern) {
throw new UnsupportedOperationException("Not supported yet."); // redission没有实现
}
@Override
public CompletableFuture subscribeAsync(CacheEventListener listener, String... topics) {
Objects.requireNonNull(listener);
final MessageListener msgListener = new MessageListener() {
@Override
public void onMessage(CharSequence channel, byte[] msg) {
pubSubExecutor().execute(() -> {
try {
listener.onMessage(channel.toString(), msg);
} catch (Throwable t) {
logger.log(
Level.SEVERE, "CacheSource subscribe message error, topic: " + channel.toString(), t);
}
});
}
};
CompletableFuture[] futures = new CompletableFuture[topics.length];
for (int i = 0; i < topics.length; i++) {
String topic = topics[i];
futures[i] = toFuture(client.getTopic(topic, ByteArrayCodec.INSTANCE)
.addListenerAsync(byte[].class, msgListener)
.thenApply(v -> {
pubsubListeners
.computeIfAbsent(listener, t -> new ConcurrentHashMap<>())
.put(topic, v);
return null;
}));
}
return futures.length == 1 ? futures[0] : CompletableFuture.allOf(futures);
}
@Override
public CompletableFuture publishAsync(String topic, byte[] message) {
Objects.requireNonNull(topic);
Objects.requireNonNull(message);
return toFuture(client.getTopic(topic, ByteArrayCodec.INSTANCE)
.publishAsync(message)
.thenApply(v -> v.intValue()));
}
@Override
public CompletableFuture unsubscribeAsync(CacheEventListener listener, String... topics) {
if (listener == null) { // 清掉指定topic的所有订阅者
Set delTopics = new HashSet<>();
if (Utility.isEmpty(topics)) {
pubsubListeners.values().forEach(m -> delTopics.addAll(m.keySet()));
} else {
delTopics.addAll(Arrays.asList(topics));
}
List> futures = new ArrayList<>();
delTopics.forEach(topic -> {
futures.add(
toFuture(client.getTopic(topic, ByteArrayCodec.INSTANCE).removeAllListenersAsync()));
});
return returnFutureSize(futures);
} else { // 清掉指定topic的指定订阅者
ConcurrentHashMap topicToIds = pubsubListeners.get(listener);
if (topicToIds == null || topicToIds.isEmpty()) { // 没有找到指定订阅者
return CompletableFuture.completedFuture(0);
} else { // 清掉指定订阅者的指定topic
if (Utility.isEmpty(topics)) {
return CompletableFuture.failedFuture(new RedkaleException("topics is empty"));
}
Predicate filter = t -> Utility.contains(topics, t);
List> futures = new ArrayList<>();
topicToIds.forEach((topic, id) -> {
if (filter.test(topic)) {
futures.add(toFuture(
client.getTopic(topic, ByteArrayCodec.INSTANCE).removeListenerAsync(id)));
}
});
return returnFutureSize(futures);
}
}
}
// --------------------- exists ------------------------------
@Override
public CompletableFuture existsAsync(String key) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.isExistsAsync());
}
// --------------------- get ------------------------------
@Override
public CompletableFuture getAsync(String key, Type type) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(key, cryptor, type, bucket.getAsync());
}
// --------------------- getex ------------------------------
@Override
public CompletableFuture getexAsync(String key, int expireSeconds, final Type type) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.getAndExpireAsync(Duration.ofSeconds(expireSeconds))
.thenApply(bs -> decryptValue(key, cryptor, type, bs)));
}
// --------------------- setex ------------------------------
@Override
public CompletableFuture setAsync(String key, Convert convert0, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.setAsync(
type == String.class
? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8)
: encryptValue(key, cryptor, type, convert0, value)));
}
@Override
public CompletableFuture setnxAsync(String key, Convert convert0, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.setIfAbsentAsync(
type == String.class
? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8)
: encryptValue(key, cryptor, type, convert0, value)));
}
@Override
public CompletableFuture getSetAsync(String key, Convert convert0, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
Convert c = convert0 == null ? this.convert : convert0;
return toFuture(bucket.getAndSetAsync(
type == String.class
? encryptValue(key, cryptor, String.valueOf(value))
.getBytes(StandardCharsets.UTF_8)
: encryptValue(key, cryptor, type, c, value))
.thenApply(old -> old == null ? null : (T) c.convertFrom(type, old)));
}
@Override
public CompletableFuture getDelAsync(String key, final Type type) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(key, cryptor, type, bucket.getAndDeleteAsync());
}
@Override
public CompletableFuture msetAsync(Serializable... keyVals) {
Map map = new LinkedHashMap<>();
for (int i = 0; i < keyVals.length; i += 2) {
String key = keyVals[i].toString();
Object val = keyVals[i + 1];
map.put(
key,
val instanceof String
? encryptValue(key, cryptor, val.toString()).getBytes(StandardCharsets.UTF_8)
: encryptValue(key, cryptor, this.convert, val));
}
final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE);
return toFuture(bucket.setAsync(map).thenApply(v -> null));
}
@Override
public CompletableFuture msetAsync(Map map) {
Map bs = new LinkedHashMap<>();
map.forEach((key, val) -> {
bs.put(
key.toString(),
val instanceof String
? encryptValue(key.toString(), cryptor, val.toString())
.getBytes(StandardCharsets.UTF_8)
: encryptValue(key.toString(), cryptor, this.convert, val));
});
final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE);
return toFuture(bucket.setAsync(bs).thenApply(v -> null));
}
@Override
public CompletableFuture msetnxAsync(Serializable... keyVals) {
Map map = new LinkedHashMap<>();
for (int i = 0; i < keyVals.length; i += 2) {
String key = keyVals[i].toString();
Object val = keyVals[i + 1];
map.put(
key,
val instanceof String
? encryptValue(key, cryptor, val.toString()).getBytes(StandardCharsets.UTF_8)
: encryptValue(key, cryptor, this.convert, val));
}
final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE);
return toFuture(bucket.trySetAsync(map).thenApply(v -> v.booleanValue()));
}
@Override
public CompletableFuture msetnxAsync(Map map) {
Map bs = new LinkedHashMap<>();
map.forEach((key, val) -> {
bs.put(
key.toString(),
val instanceof String
? encryptValue(key.toString(), cryptor, val.toString())
.getBytes(StandardCharsets.UTF_8)
: encryptValue(key.toString(), cryptor, this.convert, val));
});
final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE);
return toFuture(bucket.trySetAsync(bs).thenApply(v -> v.booleanValue()));
}
// --------------------- setex ------------------------------
@Override
public CompletableFuture setexAsync(
String key, int expireSeconds, Convert convert, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(
bucket.setAsync(encryptValue(key, cryptor, type, convert, value), expireSeconds, TimeUnit.SECONDS)
.thenApply(r -> null));
}
@Override
public CompletableFuture psetexAsync(
String key, long milliSeconds, Convert convert, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(
bucket.setAsync(encryptValue(key, cryptor, type, convert, value), milliSeconds, TimeUnit.MILLISECONDS)
.thenApply(r -> null));
}
// --------------------- setex ------------------------------
@Override
public CompletableFuture setnxexAsync(
String key, int expireSeconds, Convert convert0, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.setIfAbsentAsync(
encryptValue(key, cryptor, type, convert0, value), Duration.ofSeconds(expireSeconds)));
}
@Override
public CompletableFuture setnxpxAsync(
String key, long milliSeconds, Convert convert0, final Type type, T value) {
final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.setIfAbsentAsync(
encryptValue(key, cryptor, type, convert0, value), Duration.ofMillis(milliSeconds)));
}
// --------------------- expire ------------------------------
@Override
public CompletableFuture expireAsync(String key, int expireSeconds) {
return toFuture(client.getBucket(key)
.expireAsync(Duration.ofSeconds(expireSeconds))
.thenApply(r -> null));
}
@Override
public CompletableFuture pexpireAsync(String key, long milliSeconds) {
return toFuture(client.getBucket(key)
.expireAsync(Duration.ofMillis(milliSeconds))
.thenApply(r -> null));
}
@Override
public CompletableFuture expireAtAsync(String key, long secondsTime) {
return toFuture(client.getBucket(key)
.expireAsync(Instant.ofEpochSecond(secondsTime))
.thenApply(r -> null));
}
@Override
public CompletableFuture pexpireAtAsync(String key, long milliTime) {
return toFuture(client.getBucket(key)
.expireAsync(Instant.ofEpochMilli(milliTime))
.thenApply(r -> null));
}
// --------------------- ttl ------------------------------
@Override
public CompletableFuture ttlAsync(String key) {
return toFuture(client.getBucket(key).remainTimeToLiveAsync().thenApply(r -> r > 0 ? r / 1000 : r));
}
@Override
public CompletableFuture pttlAsync(String key) {
return toFuture(client.getBucket(key).remainTimeToLiveAsync());
}
@Override
public CompletableFuture expireTimeAsync(String key) {
return toFuture(client.getBucket(key).getExpireTimeAsync().thenApply(r -> r > 0 ? r / 1000 : r));
}
@Override
public CompletableFuture pexpireTimeAsync(String key) {
return toFuture(client.getBucket(key).getExpireTimeAsync());
}
// --------------------- persist ------------------------------
@Override
public CompletableFuture persistAsync(String key) {
return toFuture(client.getBucket(key).clearExpireAsync());
}
// --------------------- rename ------------------------------
@Override
public CompletableFuture renameAsync(String oldKey, String newKey) {
return toFuture(client.getBucket(oldKey).renameAsync(newKey).handle((v, t) -> t == null));
}
@Override
public CompletableFuture renamenxAsync(String oldKey, String newKey) {
return toFuture(client.getBucket(oldKey).renamenxAsync(newKey));
}
@Override
public CompletableFuture evalAsync(Type type, String script, List keys, String... args) {
String key = keys == null || keys.isEmpty() ? null : keys.get(0);
Object[] vals = args;
RScript.ReturnType rt = RScript.ReturnType.VALUE;
final Class t = TypeToken.typeToClass(type);
if (Collection.class.isAssignableFrom(t)) {
rt = RScript.ReturnType.MULTI;
} else if (Map.class.isAssignableFrom(t)) {
rt = RScript.ReturnType.MAPVALUE;
}
RScript.ReturnType rrt = rt;
return toFuture(client.getScript(StringCodec.INSTANCE)
.evalAsync(RScript.Mode.READ_WRITE, script, rrt, (List) keys, vals)
.thenApply(bs -> {
if (bs == null) {
return null;
}
if (TypeToken.primitiveToWrapper(t).isAssignableFrom(bs.getClass())) {
return (T) bs;
}
if (bs instanceof String) {
String val = (String) bs;
if (type == String.class) {
return val;
} else {
return (T) this.convert.convertFrom(type, val.getBytes(StandardCharsets.UTF_8));
}
}
return decryptValue(key, cryptor, type, (byte[]) bs);
}));
}
// --------------------- del ------------------------------
@Override
public CompletableFuture delAsync(String... keys) {
return toFuture(client.getKeys().deleteAsync(keys));
}
@Override
public CompletableFuture delexAsync(String key, String expectedValue) {
if (key == null) {
return CompletableFuture.completedFuture(0L);
}
return toFuture(client.getScript(StringCodec.INSTANCE)
.evalAsync(
RScript.Mode.READ_WRITE,
SCRIPT_DELEX,
RScript.ReturnType.INTEGER,
List.of(key),
expectedValue));
}
// --------------------- incrby ------------------------------
@Override
public CompletableFuture incrAsync(final String key) {
return toFuture(client.getAtomicLong(key).incrementAndGetAsync());
}
@Override
public CompletableFuture incrbyAsync(final String key, long num) {
return toFuture(client.getAtomicLong(key).addAndGetAsync(num));
}
@Override
public CompletableFuture incrbyFloatAsync(final String key, double num) {
return toFuture(client.getAtomicDouble(key).addAndGetAsync(num));
}
// --------------------- decrby ------------------------------
@Override
public CompletableFuture decrAsync(final String key) {
return toFuture(client.getAtomicLong(key).decrementAndGetAsync());
}
@Override
public CompletableFuture decrbyAsync(final String key, long num) {
return toFuture(client.getAtomicLong(key).addAndGetAsync(-num));
}
@Override
public CompletableFuture hdelAsync(final String key, String... fields) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.fastRemoveAsync(fields));
}
@Override
public CompletableFuture hlenAsync(final String key) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.sizeAsync().thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture> hkeysAsync(final String key) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.readAllKeySetAsync().thenApply(set -> set == null ? null : new ArrayList(set)));
}
@Override
public CompletableFuture hincrAsync(final String key, String field) {
RMap map = client.getMap(key, MapLongCodec.instance);
return toFuture(map.addAndGetAsync(field, 1L));
}
@Override
public CompletableFuture hincrbyAsync(final String key, String field, long num) {
RMap map = client.getMap(key, MapLongCodec.instance);
return toFuture(map.addAndGetAsync(field, num));
}
@Override
public CompletableFuture hincrbyFloatAsync(final String key, String field, double num) {
RMap map = client.getMap(key, MapDoubleCodec.instance);
return toFuture(map.addAndGetAsync(field, num));
}
@Override
public CompletableFuture hdecrAsync(final String key, String field) {
RMap map = client.getMap(key, MapLongCodec.instance);
return toFuture(map.addAndGetAsync(field, -1L));
}
@Override
public CompletableFuture hdecrbyAsync(final String key, String field, long num) {
RMap map = client.getMap(key, MapLongCodec.instance);
return toFuture(map.addAndGetAsync(field, -num));
}
@Override
public CompletableFuture hexistsAsync(final String key, String field) {
RMap map = client.getMap(key, MapLongCodec.instance);
return toFuture(map.containsKeyAsync(field));
}
@Override
public CompletableFuture hsetAsync(
final String key, final String field, final Convert convert0, final Type type, final T value) {
if (value == null) {
return CompletableFuture.completedFuture(null);
}
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.fastPutAsync(field, encryptValue(key, cryptor, type, convert0, value))
.thenApply(r -> null));
}
@Override
public CompletableFuture hsetnxAsync(
final String key, final String field, final Type type, final T value) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.fastPutIfAbsentAsync(field, encryptValue(key, cryptor, type, convert, value)));
}
@Override
public CompletableFuture hsetnxAsync(
final String key, final String field, final Convert convert0, final Type type, final T value) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.fastPutIfAbsentAsync(field, encryptValue(key, cryptor, type, convert0, value)));
}
@Override
public CompletableFuture hmsetAsync(final String key, final Serializable... values) {
Map vals = new LinkedHashMap<>();
for (int i = 0; i < values.length; i += 2) {
vals.put(String.valueOf(values[i]), encryptValue(key, cryptor, convert, values[i + 1]));
}
RMap rm = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(rm.putAllAsync(vals));
}
@Override
public CompletableFuture hmsetAsync(final String key, final Map map) {
Map vals = new LinkedHashMap<>();
map.forEach((k, v) -> {
vals.put(k.toString(), encryptValue(key, cryptor, convert, v));
});
RMap rm = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(rm.putAllAsync(vals));
}
@Override
public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.getAllAsync(Utility.ofSet(fields)).thenApply(rs -> {
List list = new ArrayList<>(fields.length);
for (String field : fields) {
byte[] bs = rs.get(field);
if (bs == null) {
list.add(null);
} else {
list.add(decryptValue(key, cryptor, type, bs));
}
}
return list;
}));
}
@Override
public CompletableFuture> hscanAsync(
final String key, final Type type, AtomicLong cursor, int limit, String pattern) {
RFuture future;
RScript script = client.getScript(SCAN_CODEC);
if (isEmpty(pattern)) {
if (limit > 0) {
String lua = "return redis.call('hscan', KEYS[1], ARGV[1], 'count', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
String.valueOf(limit));
} else {
String lua = "return redis.call('hscan', KEYS[1], ARGV[1]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY, lua, RScript.ReturnType.MULTI, List.of(key), cursor.toString());
}
} else {
if (limit > 0) {
String lua = "return redis.call('hscan', KEYS[1], ARGV[1], 'match', ARGV[2], 'count', ARGV[3]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
pattern,
String.valueOf(limit));
} else {
String lua = "return redis.call('hscan', KEYS[1], ARGV[1], 'match', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
pattern);
}
}
return toFuture(future.thenApply(result -> {
final Map rs = new LinkedHashMap<>();
List kvs = (List) result.get(1);
for (int i = 0; i < kvs.size(); i += 2) {
String field = new String(kvs.get(i), StandardCharsets.UTF_8);
byte[] bs = kvs.get(i + 1);
if (bs != null) {
rs.put(field, decryptValue(key, cryptor, type, bs));
}
}
cursor.set(Long.parseLong(new String((byte[]) result.get(0))));
return rs;
}));
}
@Override
public CompletableFuture> scanAsync(AtomicLong cursor, int limit, String pattern) {
RFuture future;
RScript script = client.getScript(SCAN_CODEC);
if (isEmpty(pattern)) {
if (limit > 0) {
String lua = "return redis.call('scan', ARGV[1], 'count', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(),
cursor.toString(),
String.valueOf(limit));
} else {
String lua = "return redis.call('scan', ARGV[1]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY, lua, RScript.ReturnType.MULTI, List.of(), cursor.toString());
}
} else {
if (limit > 0) {
String lua = "return redis.call('scan', ARGV[1], 'match', ARGV[2], 'count', ARGV[3]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(),
cursor.toString(),
pattern,
String.valueOf(limit));
} else {
String lua = "return redis.call('scan', ARGV[1], 'match', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY, lua, RScript.ReturnType.MULTI, List.of(), cursor.toString(), pattern);
}
}
return toFuture(future.thenApply(result -> {
final List rs = (List) getCollectionValue(null, (Collection) result.get(1), false, String.class);
cursor.set(Long.parseLong(new String((byte[]) result.get(0))));
return rs;
}));
}
@Override
public CompletableFuture> sscanAsync(
final String key, final Type componentType, AtomicLong cursor, int limit, String pattern) {
RFuture future;
RScript script = client.getScript(SCAN_CODEC);
if (isEmpty(pattern)) {
if (limit > 0) {
String lua = "return redis.call('sscan', KEYS[1], ARGV[1], 'count', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
String.valueOf(limit));
} else {
String lua = "return redis.call('sscan', KEYS[1], ARGV[1]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY, lua, RScript.ReturnType.MULTI, List.of(key), cursor.toString());
}
} else {
if (limit > 0) {
String lua = "return redis.call('sscan', KEYS[1], ARGV[1], 'match', ARGV[2], 'count', ARGV[3]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
pattern,
String.valueOf(limit));
} else {
String lua = "return redis.call('sscan', KEYS[1], ARGV[1], 'match', ARGV[2]);";
future = script.evalAsync(
RScript.Mode.READ_ONLY,
lua,
RScript.ReturnType.MULTI,
List.of(key),
cursor.toString(),
pattern);
}
}
return toFuture(future.thenApply(result -> {
final Set rs = (Set) getCollectionValue(key, (Collection) result.get(1), true, componentType);
cursor.set(Long.parseLong(new String((byte[]) result.get(0))));
return rs;
}));
}
@Override
public CompletableFuture hgetAsync(final String key, final String field, final Type type) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.getAsync(field).thenApply(r -> decryptValue(key, cryptor, type, r)));
}
@Override
public CompletableFuture hstrlenAsync(final String key, final String field) {
RMap map = client.getMap(key, MapByteArrayCodec.instance);
return toFuture(map.valueSizeAsync(field).thenApply(r -> r.longValue()));
}
// --------------------- collection ------------------------------
@Override
public CompletableFuture scardAsync(String key) {
return toFuture(client.getSet(key).sizeAsync().thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture> sdiffAsync(final String key, final Type componentType, final String... key2s) {
return toFuture(
client.getSet(key, ByteArrayCodec.INSTANCE).readDiffAsync(key2s).thenApply(result ->
(Set) getCollectionValue(key, result, true, componentType)));
}
@Override
public CompletableFuture smoveAsync(String key, String key2, Type componentType, T member) {
return toFuture(client.getSet(key, ByteArrayCodec.INSTANCE)
.moveAsync(key2, encryptValue(key, cryptor, componentType, convert, member)));
}
@Override
public CompletableFuture> srandmemberAsync(String key, Type componentType, int count) {
return toFuture(
client.getSet(key, ByteArrayCodec.INSTANCE).randomAsync(count).thenApply(result ->
(List) getCollectionValue(key, result, false, componentType)));
}
@Override
public CompletableFuture> smismembersAsync(final String key, final String... members) {
List bs = new ArrayList<>();
for (String m : members) {
bs.add(m.getBytes(StandardCharsets.UTF_8));
}
return toFuture(client.getSet(key, ByteArrayCodec.INSTANCE)
.containsEachAsync(bs)
.thenApply(result -> {
Set keys = new HashSet<>();
for (Object item : (List) result) {
keys.add(new String((byte[]) item, StandardCharsets.UTF_8));
}
List rs = new ArrayList<>();
for (String m : members) {
rs.add(keys.contains(m));
}
return rs;
}));
}
@Override
public CompletableFuture sdiffstoreAsync(final String key, final String srcKey, final String... srcKey2s) {
return toFuture(
client.getSet(key).diffAsync(Utility.append(srcKey, srcKey2s)).thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture> sinterAsync(
final String key, final Type componentType, final String... key2s) {
return toFuture(client.getSet(key, ByteArrayCodec.INSTANCE)
.readIntersectionAsync(key2s)
.thenApply(result -> (Set) getCollectionValue(key, result, true, componentType)));
}
@Override
public CompletableFuture sinterstoreAsync(final String key, final String srcKey, final String... srcKey2s) {
return toFuture(client.getSet(key)
.intersectionAsync(Utility.append(srcKey, srcKey2s))
.thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture> sunionAsync(
final String key, final Type componentType, final String... key2s) {
return toFuture(client.getSet(key, ByteArrayCodec.INSTANCE)
.readUnionAsync(key2s)
.thenApply(result -> (Set) getCollectionValue(key, result, true, componentType)));
}
@Override
public CompletableFuture sunionstoreAsync(final String key, final String srcKey, final String... srcKey2s) {
return toFuture(
client.getSet(key).unionAsync(Utility.append(srcKey, srcKey2s)).thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture> smembersAsync(String key, final Type componentType) {
return toFuture((CompletionStage)
client.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(result ->
(Set) getCollectionValue(key, result, true, componentType)));
}
@Override
public CompletableFuture> lrangeAsync(String key, final Type componentType, int start, int stop) {
return toFuture((CompletionStage) client.getList(key, ByteArrayCodec.INSTANCE)
.rangeAsync(start, stop)
.thenApply(result -> (List) getCollectionValue(key, result, false, componentType)));
}
@Override
public CompletableFuture> mgetAsync(final Type componentType, String... keys) {
return toFuture(
client.getBuckets(ByteArrayCodec.INSTANCE).getAsync(keys).thenApply(result -> {
List vs = new ArrayList();
for (String key : keys) {
vs.add(result.get(key));
}
return (List) getCollectionValue(keys[0], vs, false, componentType);
}));
}
@Override
public CompletableFuture> hgetallAsync(final String key, final Type type) {
return toFuture(
client.getMap(key, MapByteArrayCodec.instance).readAllMapAsync().thenApply(map -> {
Map rs = new LinkedHashMap();
map.forEach((k, v) -> rs.put(k.toString(), decryptValue(k.toString(), cryptor, type, (byte[]) v)));
return rs;
}));
}
@Override
public CompletableFuture> hvalsAsync(final String key, final Type type) {
return toFuture(client.getMap(key, MapByteArrayCodec.instance)
.readAllValuesAsync()
.thenApply(list -> {
List rs = new ArrayList<>();
for (Object v : list) {
rs.add(decryptValue(key, cryptor, type, (byte[]) v));
}
return rs;
}));
}
@Override
public CompletableFuture>> lrangesAsync(final Type componentType, final String... keys) {
final RBatch batch = client.createBatch();
for (String key : keys) {
batch.getList(key, ByteArrayCodec.INSTANCE).readAllAsync();
}
return toFuture(batch.executeAsync().thenApply(resps -> {
final Map> map = new LinkedHashMap<>();
List list = (List) resps.getResponses();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
List rs = new ArrayList<>();
for (Object item : list.get(i)) {
byte[] bs = (byte[]) item;
if (bs == null) {
rs.add(null);
} else {
rs.add(decryptValue(key, cryptor, componentType, bs));
}
}
map.put(key, rs);
}
return map;
}));
}
@Override
public CompletableFuture>> smembersAsync(final Type componentType, final String... keys) {
final RBatch batch = client.createBatch();
for (String key : keys) {
batch.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync();
}
return toFuture(batch.executeAsync().thenApply(resps -> {
final Map> map = new LinkedHashMap<>();
List list = (List) resps.getResponses();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
Set rs = new LinkedHashSet<>();
for (Object item : list.get(i)) {
byte[] bs = (byte[]) item;
if (bs == null) {
rs.add(null);
} else {
rs.add(decryptValue(key, cryptor, componentType, bs));
}
}
map.put(key, rs);
}
return map;
}));
}
// --------------------- existsItem ------------------------------
@Override
public CompletableFuture sismemberAsync(String key, final Type componentType, T value) {
final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.containsAsync(encryptValue(key, cryptor, componentType, convert, value)));
}
// --------------------- push ------------------------------
@Override
public CompletableFuture rpushAsync(String key, final Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(
bucket.addLastAsync(list.toArray(new byte[list.size()][])).thenApply(r -> null));
}
@Override
public CompletableFuture rpushxAsync(String key, final Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.isExistsAsync()
.thenCompose(b -> b
? bucket.addLastAsync(list.toArray(new byte[list.size()][]))
: CompletableFuture.completedFuture(null))
.thenApply(r -> null));
}
@Override
public CompletableFuture rpopAsync(String key, final Type componentType) {
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.pollLastAsync()).thenApply(v -> decryptValue(key, cryptor, componentType, v));
}
@Override
public CompletableFuture rpoplpushAsync(final String key, final String key2, final Type componentType) {
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.pollLastAndOfferFirstToAsync(key2))
.thenApply(v -> decryptValue(key, cryptor, componentType, v));
}
@Override
public CompletableFuture lpushAsync(String key, final Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(
bucket.addFirstAsync(list.toArray(new byte[list.size()][])).thenApply(r -> null));
}
@Override
public CompletableFuture lpushxAsync(String key, final Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.isExistsAsync()
.thenCompose(b -> b
? bucket.addFirstAsync(list.toArray(new byte[list.size()][]))
: CompletableFuture.completedFuture(null))
.thenApply(r -> null));
}
@Override
public CompletableFuture lpopAsync(String key, final Type componentType) {
final RDeque bucket = client.getDeque(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.pollFirstAsync()).thenApply(v -> decryptValue(key, cryptor, componentType, v));
}
@Override
public CompletableFuture lindexAsync(String key, Type componentType, int index) {
final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.getAsync(index)).thenApply(v -> decryptValue(key, cryptor, componentType, v));
}
@Override
public CompletableFuture linsertBeforeAsync(String key, Type componentType, T pivot, T value) {
final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.addBeforeAsync(
encryptValue(key, cryptor, componentType, convert, pivot),
encryptValue(key, cryptor, componentType, convert, value))
.thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture linsertAfterAsync(String key, Type componentType, T pivot, T value) {
final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.addAfterAsync(
encryptValue(key, cryptor, componentType, convert, pivot),
encryptValue(key, cryptor, componentType, convert, value))
.thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture llenAsync(String key) {
return toFuture(client.getList(key).sizeAsync().thenApply(v -> v.longValue()));
}
@Override
public CompletableFuture ltrimAsync(final String key, int start, int stop) {
final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.trimAsync(start, stop));
}
// --------------------- lrem ------------------------------
@Override
public CompletableFuture lremAsync(String key, final Type componentType, T value) {
return toFuture(client.getList(key, ByteArrayCodec.INSTANCE)
.removeAsync(encryptValue(key, cryptor, componentType, convert, value))
.thenApply(r -> r ? 1L : 0L));
}
// --------------------- sadd ------------------------------
@Override
public CompletableFuture saddAsync(String key, Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.addAllAsync(list).thenApply(r -> null));
}
@Override
public CompletableFuture spopAsync(String key, Type componentType) {
final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.removeRandomAsync()
.thenApply(bs -> bs == null ? null : decryptValue(key, cryptor, componentType, bs)));
}
@Override
public CompletableFuture> spopAsync(String key, int count, Type componentType) {
final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE);
return toFuture(bucket.removeRandomAsync(count).thenApply((Set bslist) -> {
if (isEmpty(bslist)) {
return new LinkedHashSet();
}
Set rs = new LinkedHashSet<>();
for (byte[] bs : bslist) {
rs.add(decryptValue(key, cryptor, componentType, bs));
}
return rs;
}));
}
@Override
public CompletableFuture sremAsync(String key, final Type componentType, T... values) {
List list = new ArrayList<>();
for (T value : values) {
list.add(encryptValue(key, cryptor, componentType, convert, value));
}
return toFuture(
client.getSet(key, ByteArrayCodec.INSTANCE).removeAllAsync(list).thenApply(r -> r ? 1L : 0L));
}
// --------------------- sorted set ------------------------------
@Override
public CompletableFuture