From 80fe44d5d75a755331795a34fe0b5410829723a7 Mon Sep 17 00:00:00 2001 From: lxy <237809796@qq.com> Date: Tue, 2 Feb 2021 13:49:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Aredis=20=E7=BC=93?= =?UTF-8?q?=E5=AD=98=EF=BC=88=E4=BB=8E=20redkalex-plugin=20=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E8=87=B3=E6=AD=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/zdemo/cachex/MyRedisCacheSource.java | 419 +++ src/com/zdemo/cachex/RedisCacheSource.java | 2240 +++++++++++++++++ src/com/zdemo/cachex/RedisTest.java | 237 ++ .../zdemo/cachex/RedissionCacheSource.java | 1944 ++++++++++++++ 4 files changed, 4840 insertions(+) create mode 100644 src/com/zdemo/cachex/MyRedisCacheSource.java create mode 100644 src/com/zdemo/cachex/RedisCacheSource.java create mode 100644 src/com/zdemo/cachex/RedisTest.java create mode 100644 src/com/zdemo/cachex/RedissionCacheSource.java diff --git a/src/com/zdemo/cachex/MyRedisCacheSource.java b/src/com/zdemo/cachex/MyRedisCacheSource.java new file mode 100644 index 0000000..d7d6a7c --- /dev/null +++ b/src/com/zdemo/cachex/MyRedisCacheSource.java @@ -0,0 +1,419 @@ +package com.zdemo.cachex; + + +import org.redkale.convert.Convert; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.AutoLoad; +import org.redkale.util.ResourceType; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class MyRedisCacheSource extends RedisCacheSource { + //--------------------- oth ------------------------------ + public boolean setnx(String key, Object v) { + byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Serializable rs = send("SETNX", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + return rs == null ? false : (long) rs == 1; + } + //--------------------- oth ------------------------------ + + //--------------------- bit ------------------------------ + public boolean getBit(String key, int offset) { + byte[][] bytes = Stream.of(key, offset).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Serializable v = send("GETBIT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + return v == null ? false : (long) v == 1; + } + + public void setBit(String key, int offset, boolean bool) { + byte[][] bytes = Stream.of(key, offset, bool ? 1 : 0).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("SETBIT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + //--------------------- bit ------------------------------ + //--------------------- lock ------------------------------ + // 尝试加锁,成功返回0,否则返回上一锁剩余毫秒值 + public int tryLock(String key, int millis) { + byte[][] bytes = Stream.of("" + + "if (redis.call('exists',KEYS[1]) == 0) then " + + "redis.call('psetex', KEYS[1], ARGV[1], 1) " + + "return 0; " + + "else " + + "return redis.call('PTTL', KEYS[1]); " + + "end; ", 1, key, millis).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + int n = (int) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); + return n; + } + + // 加锁 + public void lock(String key, int millis) { + int i; + do { + i = tryLock(key, millis); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } while (i > 0); + } + + // 解锁 + public void unlock(String key) { + remove(key); + } + + + //--------------------- key ------------------------------ + + public long getTtl(String key) { + return (long) send("TTL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); + } + + public long getPttl(String key) { + return (long) send("PTTL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); + } + + public int remove(String... keys) { + if (keys == null || keys.length == 0) { + return 0; + } + List para = new ArrayList<>(); + para.add("" + + " local args = ARGV;" + + " local x = 0;" + + " for i,v in ipairs(args) do" + + " local inx = redis.call('del', v);" + + " if(inx > 0) then" + + " x = x + 1;" + + " end" + + " end" + + " return x;"); + + para.add("0"); + for (Object field : keys) { + para.add(String.valueOf(field)); + } + byte[][] bytes = para.stream().map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + return (int) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); + } + + //--------------------- hmget ------------------------------ + public V getHm(String key, T field) { + // return (V) send("HMGET", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).join(); + Map map = getHms(key, field); + return map.get(field); + } + + public Map getHms(String key, T... field) { + if (field == null || field.length == 0) { + return new HashMap<>(); + } + byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(field)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Map result = new HashMap<>(); + + List vs = (List) send("HMGET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + for (int i = 0; i < field.length; i++) { // /*vs != null && vs.size() > i &&*/ + if (vs.get(i) == null) { + continue; + } + result.put(field[i], vs.get(i)); + } + + return result; + } + + public Map getHmall(String key) { + List vs = (List) send("HGETALL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); + Map result = new HashMap<>(vs.size() / 2); + for (int i = 0; i < vs.size(); i += 2) { + result.put(String.valueOf(vs.get(i)), vs.get(i + 1)); + } + + return result; + } + + //--------------------- hmset、hmdel、incr ------------------------------ + public void setHm(String key, T field, V value) { + byte[][] bytes = Stream.of(key, field, value).map(x -> x.toString().getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("HMSET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + public void setHms(String key, Map kv) { + List args = new ArrayList(); + args.add(key); + + kv.forEach((k, v) -> { + args.add(String.valueOf(k)); + args.add(String.valueOf(v)); + }); + + byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("HMSET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + public Long incrHm(String key, T field, long n) { + byte[][] bytes = Stream.of(key, String.valueOf(field), String.valueOf(n)).map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + return (Long) send("HINCRBY", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + public Double incrHm(String key, T field, double n) { + byte[][] bytes = Stream.of(key, String.valueOf(field), String.valueOf(n)).map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Serializable v = send("HINCRBYFLOAT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + if (v == null) { + return null; + } + return Double.parseDouble(String.valueOf(v)); + } + + public void hdel(String key, T... field) { + byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(field)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("HDEL", null, (Type) null, key, bytes).join(); + } + + public List zexists(String key, T... fields) { + if (fields == null || fields.length == 0) { + return new ArrayList<>(); + } + List para = new ArrayList<>(); + para.add("" + + " local key = KEYS[1];" + + " local args = ARGV;" + + " local result = {};" + + " for i,v in ipairs(args) do" + + " local inx = redis.call('ZREVRANK', key, v);" + + " if(inx) then" + + " table.insert(result,1,v);" + + " end" + + " end" + + " return result;"); + para.add("1"); + para.add(key); + for (Object field : fields) { + para.add(String.valueOf(field)); + } + byte[][] bytes = para.stream().map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + return (List) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); + } + + //--------------------- ------------------------------ + //--------------------- list ------------------------------ + public CompletableFuture appendListItemsAsync(String key, V... values) { + byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(values)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + return (CompletableFuture) send("RPUSH", null, (Type) null, key, bytes); + } + + public CompletableFuture lpushListItemAsync(String key, V value) { + return (CompletableFuture) send("LPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + public void lpushListItem(String key, V value) { + lpushListItemAsync(key, value).join(); + } + + public void appendListItems(String key, V... values) { + appendListItemsAsync(key, values).join(); + } + + public void appendSetItems(String key, V... values) { + // todo: + for (V v : values) { + appendSetItem(key, v); + } + } + + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + public CompletableFuture> getCollectionAsync(String key, int offset, int limit) { + return (CompletableFuture) send("OBJECT", null, (Type) null, key, "ENCODING".getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(null); + if (new String((byte[]) t).contains("list")) { //list + return send("LRANGE", CacheEntryType.OBJECT, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(offset).getBytes(StandardCharsets.UTF_8), String.valueOf(offset + limit - 1).getBytes(StandardCharsets.UTF_8)); + } else { + return send("SMEMBERS", CacheEntryType.OBJECT, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + public Collection getCollection(String key, int offset, int limit) { + return getCollectionAsync(key, offset, limit).join(); + } + + public V brpop(String key, int seconds) { + byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(seconds)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + return (V) send("BRPOP", null, (Type) null, key, bytes).join(); + } + + //--------------------- zset ------------------------------ + public void zadd(String key, Map kv) { + if (kv == null || kv.isEmpty()) { + return; + } + List args = new ArrayList(); + args.add(key); + + kv.forEach((k, v) -> { + args.add(String.valueOf(v)); + args.add(String.valueOf(k)); + }); + + byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("ZADD", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + public double zincr(String key, Object number, N n) { + byte[][] bytes = Stream.of(key, n, number).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Serializable v = send("ZINCRBY", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + return Double.parseDouble(String.valueOf(v)); + } + + public void zrem(String key, V... vs) { + List args = new ArrayList(); + args.add(key); + for (V v : vs) { + args.add(String.valueOf(v)); + } + byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + send("ZREM", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + } + + public int getZrank(String key, V v) { + byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Long t = (Long) send("ZRANK", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + return t == null ? -1 : (int) (long) t; + } + + public int getZrevrank(String key, V v) { + byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Long t = (Long) send("ZREVRANK", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + return t == null ? -1 : (int) (long) t; + } + + //ZRANGE/ZREVRANGE key start stop + public List getZset(String key) { + byte[][] bytes = Stream.of(key, 0, -1).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + List vs2 = new ArrayList(vs.size()); + + for (int i = 0; i < vs.size(); ++i) { + if (i % 2 == 1) { + vs2.add(this.convert.convertFrom(this.objValueType, String.valueOf(vs.get(i)))); + } else { + vs2.add(vs.get(i)); + } + } + + return vs2; + } + + public List getZset(String key, int offset, int limit) { + byte[][] bytes = Stream.of(key, offset, offset + limit - 1).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + List vs2 = new ArrayList(vs.size()); + + for (int i = 0; i < vs.size(); ++i) { + if (i % 2 == 1) { + vs2.add(this.convert.convertFrom(this.objValueType, String.valueOf(vs.get(i)))); + } else { + vs2.add(vs.get(i)); + } + } + + return vs2; + } + + public LinkedHashMap getZsetLongScore(String key) { + LinkedHashMap map = getZsetDoubleScore(key); + if (map.isEmpty()) { + return new LinkedHashMap<>(); + } + + LinkedHashMap map2 = new LinkedHashMap<>(map.size()); + map.forEach((k, v) -> map2.put(k, (long) (double) v)); + return map2; + } + + public LinkedHashMap getZsetItemsLongScore(String key) { + byte[][] bytes = Stream.of(key, 0, -1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 0; i < vs.size(); i += 2) { + map.put((V) vs.get(i), (long) Double.parseDouble((String) vs.get(i + 1))); + } + return map; + } + + public Long getZsetLongScore(String key, V v) { + Double score = getZsetDoubleScore(key, v); + if (score == null) { + return null; + } + return (long) (double) score; + } + + public LinkedHashMap getZsetDoubleScore(String key) { + byte[][] bytes = Stream.of(key, 0, -1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 0; i < vs.size(); i += 2) { + map.put((V) vs.get(i), Double.parseDouble((String) vs.get(i + 1))); + } + return map; + } + + public Double getZsetDoubleScore(String key, V v) { + byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + Serializable zscore = send("ZSCORE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + if (zscore == null) { + return null; + } + + return Double.parseDouble(String.valueOf(zscore)); + } + + public LinkedHashMap getZsetLongScore(String key, int offset, int limit) { + byte[][] bytes = Stream.of(key, offset, offset + limit - 1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 0; i < vs.size(); i += 2) { + map.put((V) vs.get(i), (long) Double.parseDouble((String) vs.get(i + 1))); + } + return map; + } + + public LinkedHashMap getZsetDoubleScore(String key, int offset, int limit) { + byte[][] bytes = Stream.of(key, offset, offset + limit - 1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); + List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); + + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 0; i < vs.size(); i += 2) { + map.put((V) vs.get(i), Double.parseDouble(vs.get(i + 1) + "")); + } + return map; + } + + // ---------- + protected byte[] formatValue(CacheEntryType cacheType, Convert convert0, Type resultType, Object value) { + if (value == null) return "null".getBytes(StandardCharsets.UTF_8); + if (convert0 == null) convert0 = convert; + if (cacheType == CacheEntryType.LONG || cacheType == CacheEntryType.ATOMIC) + return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + if (cacheType == CacheEntryType.STRING) return convert0.convertToBytes(String.class, value); + + if (value instanceof String) return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + if (value instanceof Number) return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); + } +} diff --git a/src/com/zdemo/cachex/RedisCacheSource.java b/src/com/zdemo/cachex/RedisCacheSource.java new file mode 100644 index 0000000..a1583e2 --- /dev/null +++ b/src/com/zdemo/cachex/RedisCacheSource.java @@ -0,0 +1,2240 @@ +/* + * 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 com.zdemo.cachex; + +import org.redkale.convert.Convert; +import org.redkale.convert.bson.BsonByteBufferWriter; +import org.redkale.convert.json.JsonConvert; +import org.redkale.convert.json.JsonFactory; +import org.redkale.net.AsyncConnection; +import org.redkale.net.Transport; +import org.redkale.net.TransportFactory; +import org.redkale.service.AbstractService; +import org.redkale.service.Local; +import org.redkale.service.Service; +import org.redkale.source.CacheSource; +import org.redkale.source.Flipper; +import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Type; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 详情见: https://redkale.org + * + * @param Value + * @author zhangjx + */ +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedisCacheSource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { + + protected static final byte DOLLAR_BYTE = '$'; + + protected static final byte ASTERISK_BYTE = '*'; + + protected static final byte PLUS_BYTE = '+'; + + protected static final byte MINUS_BYTE = '-'; + + protected static final byte COLON_BYTE = ':'; + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + @Resource + protected JsonConvert defaultConvert; + + @Resource(name = "$_convert") + protected JsonConvert convert; + + protected Type objValueType = String.class; + + protected Map passwords; + + protected List nodeAddrs; + + protected int db; + + protected Transport transport; + + @Override + public void init(AnyValue conf) { + if (this.convert == null) this.convert = this.defaultConvert; + if (conf == null) conf = new AnyValue.DefaultAnyValue(); + + AnyValue prop = conf.getAnyValue("properties"); + if (prop != null) { + String storeValueStr = prop.getValue("value-type"); + if (storeValueStr != null) { + try { + this.initValueType(Thread.currentThread().getContextClassLoader().loadClass(storeValueStr)); + } catch (Throwable e) { + logger.log(Level.SEVERE, this.getClass().getSimpleName() + " load key & value store class (" + storeValueStr + ") error", e); + } + } + } + final int bufferCapacity = conf.getIntValue("bufferCapacity", 8 * 1024); + final int bufferPoolSize = conf.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 8); + final int threads = conf.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 8); + final int readTimeoutSeconds = conf.getIntValue("readTimeoutSeconds", TransportFactory.DEFAULT_READTIMEOUTSECONDS); + final int writeTimeoutSeconds = conf.getIntValue("writeTimeoutSeconds", TransportFactory.DEFAULT_WRITETIMEOUTSECONDS); + final List addresses = new ArrayList<>(); + Map passwords0 = new HashMap<>(); + for (AnyValue node : conf.getAnyValues("node")) { + String addrstr = node.getValue("addr"); + InetSocketAddress addr = null; + if (addrstr.startsWith("redis://")) { + addrstr = addrstr.substring("redis://".length()); + int pos = addrstr.indexOf(':'); + addr = new InetSocketAddress(addrstr.substring(0, pos), Integer.parseInt(addrstr.substring(pos + 1))); + addresses.add(addr); + } else { + addr = new InetSocketAddress(addrstr, node.getIntValue("port")); + addresses.add(addr); + } + String password = node.getValue("password", "").trim(); + if (!password.isEmpty()) passwords0.put(addr, password.getBytes(StandardCharsets.UTF_8)); + String db0 = node.getValue("db", "").trim(); + if (!db0.isEmpty()) this.db = Integer.valueOf(db0); + } + if (!passwords0.isEmpty()) this.passwords = passwords0; + this.nodeAddrs = addresses; + TransportFactory transportFactory = TransportFactory.create(threads, bufferPoolSize, bufferCapacity, readTimeoutSeconds, writeTimeoutSeconds); + this.transport = transportFactory.createTransportTCP("Redis-Transport", null, addresses); + this.transport.setSemaphore(new Semaphore(conf.getIntValue("maxconns", threads))); + if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedisCacheSource.class.getSimpleName() + ": addrs=" + addresses + ", db=" + db); + + } + + @Override //ServiceLoader时判断配置是否符合当前实现类 + public boolean match(AnyValue config) { + if (config == null) return false; + AnyValue[] nodes = config.getAnyValues("node"); + if (nodes == null || nodes.length == 0) return false; + for (AnyValue node : nodes) { + if (node.getValue("addr") != null && node.getValue("port") != null) return true; + if (node.getValue("addr") != null && node.getValue("addr").startsWith("redis://")) return true; + } + return false; + } + + public void updateRemoteAddresses(final Collection addresses) { + this.transport.updateRemoteAddresses(addresses); + } + + @Override + @Deprecated + public final void initValueType(Type valueType) { + this.objValueType = valueType == null ? String.class : valueType; + } + + @Override + @Deprecated + public final void initTransient(boolean flag) { + } + + @Override + public final String getType() { + return "redis"; + } + + public static void main(String[] args) throws Exception { + DefaultAnyValue conf = new DefaultAnyValue().addValue("maxconns", "1"); + conf.addValue("node", new DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6363")); + + RedisCacheSource source = new RedisCacheSource(); + source.defaultConvert = JsonFactory.root().getConvert(); + source.init(conf); + InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 7788); + try { + System.out.println("------------------------------------"); + source.removeAsync("stritem1"); + source.removeAsync("stritem2"); + source.setStringAsync("stritem1", "value1"); + source.setStringAsync("stritem2", "value2"); + System.out.println("stritem开头的key有两个: " + source.queryKeysStartsWith("stritem")); + System.out.println("[有值] MGET : " + source.getStringMap("stritem1", "stritem2")); + System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("stritem1", "stritem2"))); + + source.remove("intitem1"); + source.remove("intitem2"); + source.setLong("intitem1", 333); + source.setLong("intitem2", 444); + System.out.println("[有值] MGET : " + source.getStringMap("intitem1", "intitem22", "intitem2")); + System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("intitem1", "intitem22", "intitem2"))); + source.remove("objitem1"); + source.remove("objitem2"); + source.set("objitem1", Flipper.class, new Flipper(10)); + source.set("objitem2", Flipper.class, new Flipper(20)); + System.out.println("[有值] MGET : " + source.getMap(Flipper.class, "objitem1", "objitem2")); + + source.remove("key1"); + source.remove("key2"); + source.remove("300"); + source.set(1000, "key1", String.class, "value1"); + source.set("key1", String.class, "value1"); + source.setString("keystr1", "strvalue1"); + source.setLong("keylong1", 333L); + source.set("300", String.class, "4000"); + source.getAndRefresh("key1", 3500, String.class); + System.out.println("[有值] 300 GET : " + source.get("300", String.class)); + System.out.println("[有值] key1 GET : " + source.get("key1", String.class)); + System.out.println("[无值] key2 GET : " + source.get("key2", String.class)); + System.out.println("[有值] keystr1 GET : " + source.getString("keystr1")); + System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L)); + System.out.println("[有值] key1 EXISTS : " + source.exists("key1")); + System.out.println("[无值] key2 EXISTS : " + source.exists("key2")); + + source.remove("keys3"); + source.appendListItem("keys3", String.class, "vals1"); + source.appendListItem("keys3", String.class, "vals2"); + System.out.println("-------- keys3 追加了两个值 --------"); + System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3", String.class)); + System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3")); + source.removeListItem("keys3", String.class, "vals1"); + System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3", String.class)); + source.getCollectionAndRefresh("keys3", 3000, String.class); + + source.remove("stringmap"); + source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("a", "aa", "b", "bb")); + source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("c", "cc", "d", "dd")); + System.out.println("[两值] stringmap VALUES : " + source.getCollectionAsync("stringmap", JsonConvert.TYPE_MAP_STRING_STRING).join()); + + source.remove("sets3"); + source.remove("sets4"); + source.appendSetItem("sets3", String.class, "setvals1"); + source.appendSetItem("sets3", String.class, "setvals2"); + source.appendSetItem("sets3", String.class, "setvals1"); + source.appendSetItem("sets4", String.class, "setvals2"); + source.appendSetItem("sets4", String.class, "setvals1"); + System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3", String.class)); + System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3")); + System.out.println("[有值] sets3-setvals2 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals2")); + System.out.println("[有值] sets3-setvals3 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals3")); + source.removeSetItem("sets3", String.class, "setvals1"); + System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3", String.class)); + System.out.println("sets3 大小 : " + source.getCollectionSize("sets3")); + System.out.println("all keys: " + source.queryKeys()); + System.out.println("key startkeys: " + source.queryKeysStartsWith("key")); + System.out.println("newnum 值 : " + source.incr("newnum")); + System.out.println("newnum 值 : " + source.decr("newnum")); + System.out.println("sets3&sets4: " + source.getStringCollectionMap(true, "sets3", "sets4")); + System.out.println("------------------------------------"); + source.set("myaddr", InetSocketAddress.class, addr); + System.out.println("myaddrstr: " + source.getString("myaddr")); + System.out.println("myaddr: " + source.get("myaddr", InetSocketAddress.class)); + source.remove("myaddrs"); + source.remove("myaddrs2"); + source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); + System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); + source.removeSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); + source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); + System.out.println("myaddrs&myaddrs2: " + source.getCollectionMap(true, InetSocketAddress.class, "myaddrs", "myaddrs2")); + System.out.println("------------------------------------"); + source.remove("myaddrs"); + Type mapType = new TypeToken>() { + }.getType(); + Map map = new HashMap<>(); + map.put("a", 1); + map.put("b", 2); + source.set("mapvals", mapType, map); + System.out.println("mapvals: " + source.get("mapvals", mapType)); + + source.remove("byteskey"); + source.setBytes("byteskey", new byte[]{1, 2, 3}); + System.out.println("byteskey 值 : " + Arrays.toString(source.getBytes("byteskey"))); + //h + source.remove("hmap"); + source.hincr("hmap", "key1"); + System.out.println("hmap.key1 值 : " + source.hgetLong("hmap", "key1", -1)); + source.hmset("hmap", "key2", "haha", "key3", 333); + source.hmset("hmap", "sm", (HashMap) Utility.ofMap("a", "aa", "b", "bb")); + System.out.println("hmap.sm 值 : " + source.hget("hmap", "sm", JsonConvert.TYPE_MAP_STRING_STRING)); + System.out.println("hmap.[key1,key2,key3] 值 : " + source.hmget("hmap", String.class, "key1", "key2", "key3")); + System.out.println("hmap.keys 四值 : " + source.hkeys("hmap")); + source.hremove("hmap", "key1", "key3"); + System.out.println("hmap.keys 两值 : " + source.hkeys("hmap")); + System.out.println("hmap.key2 值 : " + source.hgetString("hmap", "key2")); + System.out.println("hmap列表(2)大小 : " + source.hsize("hmap")); + + source.remove("hmaplong"); + source.hincr("hmaplong", "key1", 10); + source.hsetLong("hmaplong", "key2", 30); + System.out.println("hmaplong.所有两值 : " + source.hmap("hmaplong", long.class, 0, 10)); + + source.remove("hmapstr"); + source.hsetString("hmapstr", "key1", "str10"); + source.hsetString("hmapstr", "key2", null); + System.out.println("hmapstr.所有一值 : " + source.hmap("hmapstr", String.class, 0, 10)); + + source.remove("hmapstrmap"); + source.hset("hmapstrmap", "key1", JsonConvert.TYPE_MAP_STRING_STRING, (HashMap) Utility.ofMap("ks11", "vv11")); + source.hset("hmapstrmap", "key2", JsonConvert.TYPE_MAP_STRING_STRING, null); + System.out.println("hmapstrmap.无值 : " + source.hmap("hmapstrmap", JsonConvert.TYPE_MAP_STRING_STRING, 0, 10, "key2*")); + + source.remove("popset"); + source.appendStringSetItem("popset", "111"); + source.appendStringSetItem("popset", "222"); + source.appendStringSetItem("popset", "333"); + source.appendStringSetItem("popset", "444"); + source.appendStringSetItem("popset", "555"); + System.out.println("SPOP一个元素:" + source.spopStringSetItem("popset")); + System.out.println("SPOP两个元素:" + source.spopStringSetItem("popset", 2)); + System.out.println("SPOP五个元素:" + source.spopStringSetItem("popset", 5)); + source.appendLongSetItem("popset", 111); + source.appendLongSetItem("popset", 222); + source.appendLongSetItem("popset", 333); + source.appendLongSetItem("popset", 444); + source.appendLongSetItem("popset", 555); + System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); + System.out.println("SPOP两个元素:" + source.spopLongSetItem("popset", 2)); + System.out.println("SPOP五个元素:" + source.spopLongSetItem("popset", 5)); + System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); + + //清除 + int rs = source.remove("stritem1"); + System.out.println("删除stritem1个数: " + rs); + source.remove("popset"); + source.remove("stritem2"); + source.remove("intitem1"); + source.remove("intitem2"); + source.remove("keylong1"); + source.remove("keystr1"); + source.remove("mapvals"); + source.remove("myaddr"); + source.remove("myaddrs2"); + source.remove("newnum"); + source.remove("objitem1"); + source.remove("objitem2"); + source.remove("key1"); + source.remove("key2"); + source.remove("keys3"); + source.remove("sets3"); + source.remove("sets4"); + source.remove("myaddrs"); + source.remove("300"); + source.remove("stringmap"); + source.remove("hmap"); + source.remove("hmaplong"); + source.remove("hmapstr"); + source.remove("hmapstrmap"); + source.remove("byteskey"); + System.out.println("------------------------------------"); +// System.out.println("--------------测试大文本---------------"); +// HashMap bigmap = new HashMap<>(); +// StringBuilder sb = new StringBuilder(); +// sb.append("起始"); +// for (int i = 0; i < 1024 * 1024; i++) { +// sb.append("abcde"); +// } +// sb.append("结束"); +// bigmap.put("val", sb.toString()); +// System.out.println("文本长度: " + sb.length()); +// source.set("bigmap", JsonConvert.TYPE_MAP_STRING_STRING, bigmap); +// System.out.println("写入完成"); +// for (int i = 0; i < 1; i++) { +// HashMap fs = (HashMap) source.get("bigmap", JsonConvert.TYPE_MAP_STRING_STRING); +// System.out.println("内容长度: " + fs.get("val").length()); +// } + source.remove("bigmap"); + + } finally { + source.close(); + } + } + + @Override + public void close() throws Exception { //在 Application 关闭时调用 + destroy(null); + } + + @Override + public String resourceName() { + Resource res = this.getClass().getAnnotation(Resource.class); + return res == null ? "" : res.name(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{addrs = " + this.nodeAddrs + ", db=" + this.db + "}"; + } + + @Override + public void destroy(AnyValue conf) { + if (transport != null) transport.close(); + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + return (CompletableFuture) send("EXISTS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean exists(String key) { + return existsAsync(key).join(); + } + + //--------------------- get ------------------------------ + @Override + @Deprecated + public CompletableFuture getAsync(String key) { + return (CompletableFuture) send("GET", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture getAsync(String key, Type type) { + return (CompletableFuture) send("GET", CacheEntryType.OBJECT, type, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture getStringAsync(String key) { + return (CompletableFuture) send("GET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + return ((CompletableFuture) send("GET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8))).thenApplyAsync(v -> v == null ? defValue : v); + } + + @Override + @Deprecated + public V get(String key) { + return getAsync(key).join(); + } + + @Override + public T get(String key, final Type type) { + return (T) getAsync(key, type).join(); + } + + @Override + public String getString(String key) { + return getStringAsync(key).join(); + } + + @Override + public long getLong(String key, long defValue) { + return getLongAsync(key, defValue).join(); + } + + //--------------------- getAndRefresh ------------------------------ + @Override + @Deprecated + public CompletableFuture getAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getAsync(key)); + } + + @Override + public CompletableFuture getAndRefreshAsync(String key, int expireSeconds, final Type type) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getAsync(key, type)); + } + + @Override + @Deprecated + public V getAndRefresh(String key, final int expireSeconds) { + return getAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public T getAndRefresh(String key, final int expireSeconds, final Type type) { + return (T) getAndRefreshAsync(key, expireSeconds, type).join(); + } + + @Override + public CompletableFuture getStringAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getStringAsync(key)); + } + + @Override + public String getStringAndRefresh(String key, final int expireSeconds) { + return getStringAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture getLongAndRefreshAsync(String key, int expireSeconds, long defValue) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getLongAsync(key, defValue)); + } + + @Override + public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { + return getLongAndRefreshAsync(key, expireSeconds, defValue).join(); + } + + //--------------------- refresh ------------------------------ + @Override + public CompletableFuture refreshAsync(String key, int expireSeconds) { + return setExpireSecondsAsync(key, expireSeconds); + } + + @Override + public void refresh(String key, final int expireSeconds) { + setExpireSeconds(key, expireSeconds); + } + + //--------------------- set ------------------------------ + @Override + @Deprecated + public CompletableFuture setAsync(String key, V value) { + CacheEntryType cet = this.objValueType == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; + return (CompletableFuture) send("SET", cet, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, T value) { + CacheEntryType cet = value instanceof CharSequence ? CacheEntryType.STRING : CacheEntryType.OBJECT; + return (CompletableFuture) send("SET", cet, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, convert, (Type) null, value)); + } + + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + CacheEntryType cet = type == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; + return (CompletableFuture) send("SET", cet, type, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, (Convert) null, type, value)); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, final Type type, T value) { + CacheEntryType cet = type == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; + return (CompletableFuture) send("SET", cet, type, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, convert, type, value)); + } + + @Override + @Deprecated + public void set(final String key, V value) { + setAsync(key, value).join(); + } + + @Override + public void set(final String key, final Convert convert, T value) { + setAsync(key, convert, value).join(); + } + + @Override + public void set(final String key, final Type type, T value) { + setAsync(key, type, value).join(); + } + + @Override + public void set(String key, final Convert convert, final Type type, T value) { + setAsync(key, convert, type, value).join(); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return (CompletableFuture) send("SET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public void setString(String key, String value) { + setStringAsync(key, value).join(); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return (CompletableFuture) send("SET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + @Override + public void setLong(String key, long value) { + setLongAsync(key, value).join(); + } + + //--------------------- set ------------------------------ + @Override + @Deprecated + public CompletableFuture setAsync(int expireSeconds, String key, V value) { + return (CompletableFuture) setAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, T value) { + return (CompletableFuture) setAsync(key, convert, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, final Type type, T value) { + return (CompletableFuture) setAsync(key, type, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, final Type type, T value) { + return (CompletableFuture) setAsync(key, convert, type, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + @Deprecated + public void set(int expireSeconds, String key, V value) { + setAsync(expireSeconds, key, value).join(); + } + + @Override + public void set(int expireSeconds, String key, Convert convert, T value) { + setAsync(expireSeconds, key, convert, value).join(); + } + + @Override + public void set(int expireSeconds, String key, final Type type, T value) { + setAsync(expireSeconds, key, type, value).join(); + } + + @Override + public void set(int expireSeconds, String key, Convert convert, final Type type, T value) { + setAsync(expireSeconds, key, convert, type, value).join(); + } + + @Override + public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { + return (CompletableFuture) setStringAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public void setString(int expireSeconds, String key, String value) { + setStringAsync(expireSeconds, key, value).join(); + } + + @Override + public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { + return (CompletableFuture) setLongAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public void setLong(int expireSeconds, String key, long value) { + setLongAsync(expireSeconds, key, value).join(); + } + + //--------------------- setExpireSeconds ------------------------------ + @Override + public CompletableFuture setExpireSecondsAsync(String key, int expireSeconds) { + return (CompletableFuture) send("EXPIRE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void setExpireSeconds(String key, int expireSeconds) { + setExpireSecondsAsync(key, expireSeconds).join(); + } + + //--------------------- remove ------------------------------ + @Override + public CompletableFuture removeAsync(String key) { + return (CompletableFuture) send("DEL", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public int remove(String key) { + return removeAsync(key).join(); + } + + //--------------------- incr ------------------------------ + @Override + public long incr(final String key) { + return incrAsync(key).join(); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return (CompletableFuture) send("INCR", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public long incr(final String key, long num) { + return incrAsync(key, num).join(); + } + + @Override + public CompletableFuture incrAsync(final String key, long num) { + return (CompletableFuture) send("INCRBY", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); + } + + //--------------------- decr ------------------------------ + @Override + public long decr(final String key) { + return decrAsync(key).join(); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return (CompletableFuture) send("DECR", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public long decr(final String key, long num) { + return decrAsync(key, num).join(); + } + + @Override + public CompletableFuture decrAsync(final String key, long num) { + return (CompletableFuture) send("DECRBY", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public int hremove(final String key, String... fields) { + return hremoveAsync(key, fields).join(); + } + + @Override + public int hsize(final String key) { + return hsizeAsync(key).join(); + } + + @Override + public List hkeys(final String key) { + return hkeysAsync(key).join(); + } + + @Override + public long hincr(final String key, String field) { + return hincrAsync(key, field).join(); + } + + @Override + public long hincr(final String key, String field, long num) { + return hincrAsync(key, field, num).join(); + } + + @Override + public long hdecr(final String key, String field) { + return hdecrAsync(key, field).join(); + } + + @Override + public long hdecr(final String key, String field, long num) { + return hdecrAsync(key, field, num).join(); + } + + @Override + public boolean hexists(final String key, String field) { + return hexistsAsync(key, field).join(); + } + + @Override + public void hset(final String key, final String field, final Convert convert, final T value) { + hsetAsync(key, field, convert, value).join(); + } + + @Override + public void hset(final String key, final String field, final Type type, final T value) { + hsetAsync(key, field, type, value).join(); + } + + @Override + public void hset(final String key, final String field, final Convert convert, final Type type, final T value) { + hsetAsync(key, field, convert, type, value).join(); + } + + @Override + public void hsetString(final String key, final String field, final String value) { + hsetStringAsync(key, field, value).join(); + } + + @Override + public void hsetLong(final String key, final String field, final long value) { + hsetLongAsync(key, field, value).join(); + } + + @Override + public void hmset(final String key, final Serializable... values) { + hmsetAsync(key, values).join(); + } + + @Override + public List hmget(final String key, final Type type, final String... fields) { + return hmgetAsync(key, type, fields).join(); + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { + return (Map) hmapAsync(key, type, offset, limit, pattern).join(); + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit) { + return (Map) hmapAsync(key, type, offset, limit).join(); + } + + @Override + public T hget(final String key, final String field, final Type type) { + return (T) hgetAsync(key, field, type).join(); + } + + @Override + public String hgetString(final String key, final String field) { + return hgetStringAsync(key, field).join(); + } + + @Override + public long hgetLong(final String key, final String field, long defValue) { + return hgetLongAsync(key, field, defValue).join(); + } + + @Override + public CompletableFuture hremoveAsync(final String key, String... fields) { + byte[][] bs = new byte[fields.length + 1][]; + bs[0] = key.getBytes(StandardCharsets.UTF_8); + for (int i = 0; i < fields.length; i++) { + bs[i + 1] = fields[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("HDEL", CacheEntryType.MAP, (Type) null, key, bs); + } + + @Override + public CompletableFuture hsizeAsync(final String key) { + return (CompletableFuture) send("HLEN", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + return (CompletableFuture) send("HKEYS", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + return hincrAsync(key, field, 1); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field, long num) { + return (CompletableFuture) send("HINCRBY", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + return hincrAsync(key, field, -1); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field, long num) { + return hincrAsync(key, field, -num); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + return (CompletableFuture) send("HEXISTS", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value) { + return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, convert, null, value)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + return (CompletableFuture) send("HSET", CacheEntryType.MAP, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, null, type, value)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + return (CompletableFuture) send("HSET", CacheEntryType.MAP, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, convert, type, value)); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, null, null, value)); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, null, null, value)); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Serializable... values) { + byte[][] bs = new byte[values.length + 1][]; + bs[0] = key.getBytes(StandardCharsets.UTF_8); + for (int i = 0; i < values.length; i += 2) { + bs[i + 1] = String.valueOf(values[i]).getBytes(StandardCharsets.UTF_8); + bs[i + 2] = formatValue(CacheEntryType.MAP, null, null, values[i + 1]); + } + return (CompletableFuture) send("HMSET", CacheEntryType.MAP, (Type) null, key, bs); + } + + @Override + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { + byte[][] bs = new byte[fields.length + 1][]; + bs[0] = key.getBytes(StandardCharsets.UTF_8); + for (int i = 0; i < fields.length; i++) { + bs[i + 1] = fields[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("HMGET", CacheEntryType.MAP, type, key, bs); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { + return hmapAsync(key, type, offset, limit, null); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { + byte[][] bs = new byte[pattern == null || pattern.isEmpty() ? 4 : 6][limit]; + int index = -1; + bs[++index] = key.getBytes(StandardCharsets.UTF_8); + bs[++index] = String.valueOf(offset).getBytes(StandardCharsets.UTF_8); + if (pattern != null && !pattern.isEmpty()) { + bs[++index] = "MATCH".getBytes(StandardCharsets.UTF_8); + bs[++index] = pattern.getBytes(StandardCharsets.UTF_8); + } + bs[++index] = "COUNT".getBytes(StandardCharsets.UTF_8); + bs[++index] = String.valueOf(limit).getBytes(StandardCharsets.UTF_8); + return (CompletableFuture) send("HSCAN", CacheEntryType.MAP, type, key, bs); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + return (CompletableFuture) send("HGET", CacheEntryType.OBJECT, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + return (CompletableFuture) send("HGET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + return (CompletableFuture) send("HGET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApplyAsync(v -> v == null ? defValue : v); + } + + //--------------------- collection ------------------------------ + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(0); + String rs = new String((byte[]) t); + if (rs.contains("zset")) { // ziplist + return send("ZCARD", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); + } else if (rs.contains("list")) { //list + return send("LLEN", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); + } else if (rs.contains("hash")) { + return send("HLEN", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); + } else { + return send("SCARD", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + @Override + public int getCollectionSize(String key) { + return getCollectionSizeAsync(key).join(); + } + + @Override + @Deprecated + public CompletableFuture> getCollectionAsync(String key) { + return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(null); + String str = new String((byte[]) t); + if (str.contains("list")) { //list + return send("LRANGE", CacheEntryType.OBJECT, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); + } else if (str.contains("none")) { + return CompletableFuture.completedFuture(new ArrayList<>()); + } else { + return send("SMEMBERS", CacheEntryType.OBJECT, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return (CompletableFuture) send("TYPE", null, componentType, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(null); + if (new String((byte[]) t).contains("list")) { //list + return send("LRANGE", CacheEntryType.OBJECT, componentType, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); + } else { + return send("SMEMBERS", CacheEntryType.OBJECT, componentType, true, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + @Override + public CompletableFuture> getLongMapAsync(String... keys) { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < bs.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("MGET", CacheEntryType.LONG, null, false, keys[0], bs).thenApply(r -> { + List list = (List) r; + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keys.length; i++) { + Object obj = list.get(i); + if (obj != null) map.put(keys[i], list.get(i)); + } + return map; + }); + } + + @Override + public CompletableFuture getLongArrayAsync(String... keys) { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < bs.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("MGET", CacheEntryType.LONG, null, false, keys[0], bs).thenApply(r -> { + List list = (List) r; + Long[] rs = new Long[keys.length]; + for (int i = 0; i < keys.length; i++) { + Number obj = (Number) list.get(i); + rs[i] = obj == null ? null : obj.longValue(); + } + return rs; + }); + } + + @Override + public CompletableFuture getStringArrayAsync(String... keys) { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < bs.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("MGET", CacheEntryType.STRING, null, false, keys[0], bs).thenApply(r -> { + List list = (List) r; + String[] rs = new String[keys.length]; + for (int i = 0; i < keys.length; i++) { + Object obj = list.get(i); + rs[i] = obj == null ? null : obj.toString(); + } + return rs; + }); + } + + @Override + public CompletableFuture> getStringMapAsync(String... keys) { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < bs.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("MGET", CacheEntryType.STRING, null, false, keys[0], bs).thenApply(r -> { + List list = (List) r; + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keys.length; i++) { + Object obj = list.get(i); + if (obj != null) map.put(keys[i], list.get(i)); + } + return map; + }); + } + + @Override + public CompletableFuture> getMapAsync(final Type componentType, String... keys) { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < bs.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return (CompletableFuture) send("MGET", CacheEntryType.OBJECT, componentType, false, keys[0], bs).thenApply(r -> { + List list = (List) r; + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keys.length; i++) { + Object obj = list.get(i); + if (obj != null) map.put(keys[i], list.get(i)); + } + return map; + }); + } + + @Override + public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("LRANGE", CacheEntryType.OBJECT, componentType, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("SMEMBERS", CacheEntryType.OBJECT, componentType, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + @Deprecated + public Collection getCollection(String key) { + return getCollectionAsync(key).join(); + } + + @Override + public Collection getCollection(String key, final Type componentType) { + return (Collection) getCollectionAsync(key, componentType).join(); + } + + @Override + public Map getLongMap(final String... keys) { + return getLongMapAsync(keys).join(); + } + + @Override + public Long[] getLongArray(final String... keys) { + return getLongArrayAsync(keys).join(); + } + + @Override + public Map getStringMap(final String... keys) { + return getStringMapAsync(keys).join(); + } + + @Override + public String[] getStringArray(final String... keys) { + return getStringArrayAsync(keys).join(); + } + + @Override + public Map getMap(final Type componentType, final String... keys) { + return (Map) getMapAsync(componentType, keys).join(); + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + return (Map) getCollectionMapAsync(set, componentType, keys).join(); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(null); + if (new String((byte[]) t).contains("list")) { //list + return send("LRANGE", CacheEntryType.STRING, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); + } else { + return send("SMEMBERS", CacheEntryType.STRING, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("LRANGE", CacheEntryType.STRING, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("SMEMBERS", CacheEntryType.STRING, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Collection getStringCollection(String key) { + return getStringCollectionAsync(key).join(); + } + + @Override + public Map> getStringCollectionMap(final boolean set, String... keys) { + return getStringCollectionMapAsync(set, keys).join(); + } + + @Override + public CompletableFuture> getLongCollectionAsync(String key) { + return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + if (t == null) return CompletableFuture.completedFuture(null); + if (new String((byte[]) t).contains("list")) { //list + return send("LRANGE", CacheEntryType.LONG, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); + } else { + return send("SMEMBERS", CacheEntryType.LONG, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); + } + }); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("LRANGE", CacheEntryType.LONG, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = send("SMEMBERS", CacheEntryType.LONG, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { + if (c != null) { + synchronized (map) { + map.put(key, (Collection) c); + } + } + }); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Collection getLongCollection(String key) { + return getLongCollectionAsync(key).join(); + } + + @Override + public Map> getLongCollectionMap(final boolean set, String... keys) { + return getLongCollectionMapAsync(set, keys).join(); + } + + //--------------------- getCollectionAndRefresh ------------------------------ + @Override + @Deprecated + public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key)); + } + + @Override + public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds, final Type componentType) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); + } + + @Override + @Deprecated + public Collection getCollectionAndRefresh(String key, final int expireSeconds) { + return getCollectionAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public Collection getCollectionAndRefresh(String key, final int expireSeconds, final Type componentType) { + return (Collection) getCollectionAndRefreshAsync(key, expireSeconds, componentType).join(); + } + + @Override + public CompletableFuture> getStringCollectionAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); + } + + @Override + public Collection getStringCollectionAndRefresh(String key, final int expireSeconds) { + return getStringCollectionAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture> getLongCollectionAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); + } + + @Override + public Collection getLongCollectionAndRefresh(String key, final int expireSeconds) { + return getLongCollectionAndRefreshAsync(key, expireSeconds).join(); + } + + //--------------------- existsItem ------------------------------ + @Override + @Deprecated + public boolean existsSetItem(String key, V value) { + return existsSetItemAsync(key, value).join(); + } + + @Override + public boolean existsSetItem(String key, final Type componentType, T value) { + return existsSetItemAsync(key, componentType, value).join(); + } + + @Override + @Deprecated + public CompletableFuture existsSetItemAsync(String key, V value) { + return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture existsSetItemAsync(String key, final Type componentType, T value) { + return (CompletableFuture) send("SISMEMBER", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); + } + + @Override + public boolean existsStringSetItem(String key, String value) { + return existsStringSetItemAsync(key, value).join(); + } + + @Override + public CompletableFuture existsStringSetItemAsync(String key, String value) { + return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public boolean existsLongSetItem(String key, long value) { + return existsLongSetItemAsync(key, value).join(); + } + + @Override + public CompletableFuture existsLongSetItemAsync(String key, long value) { + return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + //--------------------- appendListItem ------------------------------ + @Override + @Deprecated + public CompletableFuture appendListItemAsync(String key, V value) { + return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture appendListItemAsync(String key, final Type componentType, T value) { + return (CompletableFuture) send("RPUSH", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); + } + + @Override + @Deprecated + public void appendListItem(String key, V value) { + appendListItemAsync(key, value).join(); + } + + @Override + public void appendListItem(String key, final Type componentType, T value) { + appendListItemAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture appendStringListItemAsync(String key, String value) { + return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public void appendStringListItem(String key, String value) { + appendStringListItemAsync(key, value).join(); + } + + @Override + public CompletableFuture appendLongListItemAsync(String key, long value) { + return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + @Override + public void appendLongListItem(String key, long value) { + appendLongListItemAsync(key, value).join(); + } + + //--------------------- removeListItem ------------------------------ + @Override + @Deprecated + public CompletableFuture removeListItemAsync(String key, V value) { + return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture removeListItemAsync(String key, final Type componentType, T value) { + return (CompletableFuture) send("LREM", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); + } + + @Override + @Deprecated + public int removeListItem(String key, V value) { + return removeListItemAsync(key, value).join(); + } + + @Override + public int removeListItem(String key, final Type componentType, T value) { + return removeListItemAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture removeStringListItemAsync(String key, String value) { + return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public int removeStringListItem(String key, String value) { + return removeStringListItemAsync(key, value).join(); + } + + @Override + public CompletableFuture removeLongListItemAsync(String key, long value) { + return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + @Override + public int removeLongListItem(String key, long value) { + return removeLongListItemAsync(key, value).join(); + } + + //--------------------- appendSetItem ------------------------------ + @Override + @Deprecated + public CompletableFuture appendSetItemAsync(String key, V value) { + return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture appendSetItemAsync(String key, Type componentType, T value) { + return (CompletableFuture) send("SADD", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); + } + + @Override + public CompletableFuture spopSetItemAsync(String key, Type componentType) { + return (CompletableFuture) send("SPOP", CacheEntryType.OBJECT, componentType, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { + return (CompletableFuture) send("SPOP", CacheEntryType.OBJECT, componentType, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture spopStringSetItemAsync(String key) { + return (CompletableFuture) send("SPOP", CacheEntryType.STRING, String.class, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture> spopStringSetItemAsync(String key, int count) { + return (CompletableFuture) send("SPOP", CacheEntryType.STRING, String.class, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture spopLongSetItemAsync(String key) { + return (CompletableFuture) send("SPOP", CacheEntryType.LONG, long.class, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture> spopLongSetItemAsync(String key, int count) { + return (CompletableFuture) send("SPOP", CacheEntryType.LONG, long.class, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); + } + + @Override + @Deprecated + public void appendSetItem(String key, V value) { + appendSetItemAsync(key, value).join(); + } + + @Override + public void appendSetItem(String key, final Type componentType, T value) { + appendSetItemAsync(key, componentType, value).join(); + } + + @Override + public T spopSetItem(String key, final Type componentType) { + return (T) spopSetItemAsync(key, componentType).join(); + } + + @Override + public List spopSetItem(String key, int count, final Type componentType) { + return (List) spopSetItemAsync(key, count, componentType).join(); + } + + @Override + public String spopStringSetItem(String key) { + return spopStringSetItemAsync(key).join(); + } + + @Override + public List spopStringSetItem(String key, int count) { + return spopStringSetItemAsync(key, count).join(); + } + + @Override + public Long spopLongSetItem(String key) { + return spopLongSetItemAsync(key).join(); + } + + @Override + public List spopLongSetItem(String key, int count) { + return spopLongSetItemAsync(key, count).join(); + } + + @Override + public CompletableFuture appendStringSetItemAsync(String key, String value) { + return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public void appendStringSetItem(String key, String value) { + appendStringSetItemAsync(key, value).join(); + } + + @Override + public CompletableFuture appendLongSetItemAsync(String key, long value) { + return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + @Override + public void appendLongSetItem(String key, long value) { + appendLongSetItemAsync(key, value).join(); + } + + //--------------------- removeSetItem ------------------------------ + @Override + @Deprecated + public CompletableFuture removeSetItemAsync(String key, V value) { + return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); + } + + @Override + public CompletableFuture removeSetItemAsync(String key, final Type componentType, T value) { + return (CompletableFuture) send("SREM", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); + } + + @Override + @Deprecated + public int removeSetItem(String key, V value) { + return removeSetItemAsync(key, value).join(); + } + + @Override + public int removeSetItem(String key, final Type componentType, T value) { + return removeSetItemAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture removeStringSetItemAsync(String key, String value) { + return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); + } + + @Override + public int removeStringSetItem(String key, String value) { + return removeStringSetItemAsync(key, value).join(); + } + + @Override + public CompletableFuture removeLongSetItemAsync(String key, long value) { + return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); + } + + @Override + public int removeLongSetItem(String key, long value) { + return removeLongSetItemAsync(key, value).join(); + } + + //--------------------- queryKeys ------------------------------ + @Override + public List queryKeys() { + return queryKeysAsync().join(); + } + + @Override + public List queryKeysStartsWith(String startsWith) { + return queryKeysStartsWithAsync(startsWith).join(); + } + + @Override + public List queryKeysEndsWith(String endsWith) { + return queryKeysEndsWithAsync(endsWith).join(); + } + + @Override + public byte[] getBytes(final String key) { + return getBytesAsync(key).join(); + } + + @Override + public byte[] getBytesAndRefresh(final String key, final int expireSeconds) { + return getBytesAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public void setBytes(final String key, final byte[] value) { + setBytesAsync(key, value).join(); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final byte[] value) { + setBytesAsync(expireSeconds, key, value).join(); + } + + @Override + public void setBytes(final String key, final Convert convert, final Type type, final T value) { + setBytesAsync(key, convert, type, value).join(); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { + setBytesAsync(expireSeconds, key, convert, type, value).join(); + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + return (CompletableFuture) send("GET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getBytesAsync(key)); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final byte[] value) { + return (CompletableFuture) send("SET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), value); + + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value) { + return (CompletableFuture) setBytesAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value) { + return (CompletableFuture) send("SET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), convert.convertToBytes(type, value)); + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { + return (CompletableFuture) setBytesAsync(key, convert.convertToBytes(type, value)).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); + } + + @Override + public CompletableFuture> queryKeysAsync() { + return (CompletableFuture) send("KEYS", null, (Type) null, "*", new byte[]{(byte) '*'}); + } + + @Override + public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { + if (startsWith == null) return queryKeysAsync(); + String key = startsWith + "*"; + return (CompletableFuture) send("KEYS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { + if (endsWith == null) return queryKeysAsync(); + String key = "*" + endsWith; + return (CompletableFuture) send("KEYS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); + } + + //--------------------- getKeySize ------------------------------ + @Override + public int getKeySize() { + return getKeySizeAsync().join(); + } + + @Override + public CompletableFuture getKeySizeAsync() { + return (CompletableFuture) send("DBSIZE", null, (Type) null, null); + } + + //--------------------- queryList ------------------------------ + @Override + public List> queryList() { + return queryListAsync().join(); + } + + @Override + public CompletableFuture>> queryListAsync() { + return CompletableFuture.completedFuture(new ArrayList<>()); //不返回数据 + } + + //--------------------- send ------------------------------ + private byte[] formatValue(CacheEntryType cacheType, Convert convert0, Type resultType, Object value) { + if (value == null) return "null".getBytes(StandardCharsets.UTF_8); + if (value instanceof byte[]) return (byte[]) value; + if (convert0 == null) convert0 = convert; + if (cacheType == CacheEntryType.MAP) { + if ((value instanceof CharSequence) || (value instanceof Number)) { + return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + } + if (objValueType == String.class && !(value instanceof CharSequence)) resultType = value.getClass(); + return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); + } + if (cacheType == CacheEntryType.LONG || cacheType == CacheEntryType.ATOMIC || value.getClass() == String.class) + return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + if (cacheType == CacheEntryType.STRING) return convert0.convertToBytes(String.class, value); + return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); + } + + protected CompletableFuture send(final String command, final CacheEntryType cacheType, final Type resultType, final String key, final byte[]... args) { + return send(command, cacheType, resultType, false, key, args); + } + + protected CompletableFuture send(final String command, final CacheEntryType cacheType, final Type resultType, final boolean set, final String key, final byte[]... args) { + return send(null, command, cacheType, resultType, set, key, args); + } + + private CompletableFuture send(final CompletionHandler callback, final String command, final CacheEntryType cacheType, final Type resultType, final boolean set, final String key, final byte[]... args) { + final BsonByteBufferWriter writer = new BsonByteBufferWriter(transport.getBufferSupplier()); + writer.writeTo(ASTERISK_BYTE); + writer.writeTo(String.valueOf(args.length + 1).getBytes(StandardCharsets.UTF_8)); + writer.writeTo((byte) '\r', (byte) '\n'); + writer.writeTo(DOLLAR_BYTE); + writer.writeTo(String.valueOf(command.length()).getBytes(StandardCharsets.UTF_8)); + writer.writeTo((byte) '\r', (byte) '\n'); + writer.writeTo(command.getBytes(StandardCharsets.UTF_8)); + writer.writeTo((byte) '\r', (byte) '\n'); + + for (final byte[] arg : args) { + writer.writeTo(DOLLAR_BYTE); + writer.writeTo(String.valueOf(arg.length).getBytes(StandardCharsets.UTF_8)); + writer.writeTo((byte) '\r', (byte) '\n'); + writer.writeTo(arg); + writer.writeTo((byte) '\r', (byte) '\n'); + } + + final ByteBuffer[] buffers = writer.toBuffers(); + + final CompletableFuture future = callback == null ? new CompletableFuture<>() : null; + CompletableFuture connFuture = this.transport.pollConnection(null); + if (passwords != null) { + connFuture = connFuture.thenCompose(conn -> { + if (conn.getSubobject() != null) return CompletableFuture.completedFuture(conn); + byte[] password = passwords.get(conn.getRemoteAddress()); + if (password == null) return CompletableFuture.completedFuture(conn); + CompletableFuture rs = auth(conn, password, command); + if (db > 0) { + rs = rs.thenCompose(conn2 -> { + if (conn2.getSubobject() != null) return CompletableFuture.completedFuture(conn2); + return selectdb(conn2, db, command); + }); + } + return rs; + }); + } else if (db > 0) { + connFuture = connFuture.thenCompose(conn2 -> { + if (conn2.getSubobject() != null) return CompletableFuture.completedFuture(conn2); + return selectdb(conn2, db, command); + }); + } + connFuture.whenComplete((conn, ex) -> { + if (ex != null) { + transport.offerBuffer(buffers); + if (future == null) { + callback.failed(ex, null); + } else { + future.completeExceptionally(ex); + } + return; + } + conn.write(buffers, buffers, new CompletionHandler() { + @Override + public void completed(Integer result, ByteBuffer[] attachments) { + int index = -1; + try { + for (int i = 0; i < attachments.length; i++) { + if (attachments[i].hasRemaining()) { + index = i; + break; + } else { + transport.offerBuffer(attachments[i]); + } + } + if (index == 0) { + conn.write(attachments, attachments, this); + return; + } else if (index > 0) { + ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; + System.arraycopy(attachments, index, newattachs, 0, newattachs.length); + conn.write(newattachs, newattachs, this); + return; + } + //----------------------- 读取返回结果 ------------------------------------- + conn.read(new ReplyCompletionHandler(conn) { + @Override + public void completed(Integer result, ByteBuffer buffer) { + buffer.flip(); + try { + final byte sign = buffer.get(); + if (sign == PLUS_BYTE) { // + + byte[] bs = readBytes(buffer); + if (future == null) { + transport.offerConnection(false, conn); //必须在complete之前,防止并发是conn还没回收完毕 + callback.completed(null, key); + } else { + transport.offerConnection(false, conn); + future.complete(("SET".equals(command) || "HSET".equals(command)) ? null : bs); + } + } else if (sign == MINUS_BYTE) { // - + String bs = readString(buffer); + if (future == null) { + transport.offerConnection(false, conn); + callback.failed(new RuntimeException(bs), key); + } else { + transport.offerConnection(false, conn); + future.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); + } + } else if (sign == COLON_BYTE) { // : + long rs = readLong(buffer); + if (future == null) { + if (command.startsWith("INCR") || command.startsWith("DECR") || command.startsWith("HINCR")) { + transport.offerConnection(false, conn); + callback.completed(rs, key); + } else { + transport.offerConnection(false, conn); + callback.completed((command.endsWith("EXISTS") || "SISMEMBER".equals(command)) ? (rs > 0) : (("LLEN".equals(command) || "SCARD".equals(command) || "SREM".equals(command) || "LREM".equals(command) || "DEL".equals(command) || "HDEL".equals(command) || "HLEN".equals(command) || "DBSIZE".equals(command)) ? (int) rs : null), key); + } + } else { + if (command.startsWith("INCR") || command.startsWith("DECR") || command.startsWith("HINCR") || command.startsWith("HGET")) { + transport.offerConnection(false, conn); + future.complete(rs); + } else if (command.equals("ZRANK") || command.equals("ZREVRANK")) { + transport.offerConnection(false, conn); + future.complete(rs); + } else if (command.equals("GETBIT")) { + transport.offerConnection(false, conn); + future.complete(rs); + } else if (command.equals("TTL") || command.equals("PTTL")) { + transport.offerConnection(false, conn); + future.complete(rs); + } else if (command.equals("SETNX")) { + transport.offerConnection(false, conn); + future.complete(rs); + } else { + transport.offerConnection(false, conn); + future.complete((command.endsWith("EXISTS") || "SISMEMBER".equals(command)) ? (rs > 0) : (("LLEN".equals(command) || "SCARD".equals(command) || "SREM".equals(command) || "LREM".equals(command) || "DEL".equals(command) || "HDEL".equals(command) || "HLEN".equals(command) || "DBSIZE".equals(command) || "ZCARD".equals(command) || "EVAL".equals(command)) ? (int) rs : null)); + } + } + } else if (sign == DOLLAR_BYTE) { // $ + long val = readLong(buffer); + byte[] rs = val <= 0 ? null : readBytes(buffer); + Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); + if (future == null) { + transport.offerConnection(false, conn); + callback.completed((("SPOP".equals(command) || command.endsWith("GET") || rs == null) ? (ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, new String(rs, StandardCharsets.UTF_8))) : null), key); + } else { + transport.offerConnection(false, conn); + if ("ZSCORE".equals(command)) { + future.complete(ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, rs == null ? null : new String(rs, StandardCharsets.UTF_8))); + } else if (command.equals("HINCRBYFLOAT")) { + future.complete(new String(rs, StandardCharsets.UTF_8)); + } else { + future.complete("SPOP".equals(command) || command.endsWith("GET") || command.endsWith("ZINCRBY") ? (ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, rs == null ? null : new String(rs, StandardCharsets.UTF_8))) : rs); + } + } + } else if (sign == ASTERISK_BYTE) { // * + final int len = readInt(buffer); + if (len < 0) { + if (future == null) { + transport.offerConnection(false, conn); + callback.completed(null, key); + } else { + transport.offerConnection(false, conn); + future.complete((byte[]) null); + } + } else { + Object rsobj; + if (command.endsWith("SCAN")) { + LinkedHashMap rs = new LinkedHashMap(); + rsobj = rs; + for (int i = 0; i < len; i++) { + int l = readInt(buffer); + if (l > 0) { + readBytes(buffer); + } else { + while (buffer.hasRemaining()) { + readBytes(buffer); + String field = new String(readBytes(buffer), StandardCharsets.UTF_8); + String value = null; + if (readInt(buffer) > 0) { + value = new String(readBytes(buffer), StandardCharsets.UTF_8); + } + Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); + try { + rs.put(field, value == null ? null : (ct == String.class ? value : convert.convertFrom(ct, value))); + } catch (RuntimeException e) { + buffer.flip(); + byte[] bsss = new byte[buffer.remaining()]; + buffer.get(bsss); + logger.log(Level.SEVERE, "异常: " + new String(bsss)); + throw e; + } + } + } + } + } else { + Collection rs = set ? new HashSet() : new ArrayList(); + rsobj = rs; + boolean keys = "KEYS".equals(command) || "HKEYS".equals(command); + boolean mget = !keys && ("MGET".equals(command) || "HMGET".equals(command)); + boolean zsetscore = !keys && ("ZREVRANGE".equals(command) || "ZRANGE".equals(command)); + boolean hgetall = !keys && "HGETALL".equals(command); + boolean lpop = !keys && "BRPOP".equals(command); + Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); + for (int i = 0; i < len; i++) { + int l = readInt(buffer); + if (l > 0) { + // 1、zsetscore 查询 偶数元素统一返回 string 方法内自定义转换 + // 2、hgetall 基数元素返回 string + if ((zsetscore && rs.size() % 2 == 1) || (hgetall && rs.size() % 2 == 0)) { + rs.add(readString(buffer)); + } else if (lpop && i == 1) { + rsobj = convert.convertFrom(ct, new String(readBytes(buffer), StandardCharsets.UTF_8)); + } else { + rs.add(keys ? new String(readBytes(buffer), StandardCharsets.UTF_8) : (ct == String.class ? new String(readBytes(buffer), StandardCharsets.UTF_8) : convert.convertFrom(ct, new String(readBytes(buffer), StandardCharsets.UTF_8)))); + } + } else if (mget) { + rs.add(null); + } + } + } + if (future == null) { + transport.offerConnection(false, conn); + callback.completed(rsobj, key); + } else { + transport.offerConnection(false, conn); + future.complete((Serializable) rsobj); + } + } + } else { + String exstr = "Unknown reply: " + (char) sign; + if (future == null) { + transport.offerConnection(false, conn); + callback.failed(new RuntimeException(exstr), key); + } else { + transport.offerConnection(false, conn); + future.completeExceptionally(new RuntimeException(exstr)); + } + } + } catch (Exception e) { + logger.log(Level.WARNING, "", e); + failed(e, buffer); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + conn.offerBuffer(attachment); + transport.offerConnection(true, conn); + if (future == null) { + callback.failed(exc, attachments); + } else { + future.completeExceptionally(exc); + } + } + + }); + } catch (Exception e) { + failed(e, attachments); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer[] attachments) { + transport.offerConnection(true, conn); + if (future == null) { + callback.failed(exc, attachments); + } else { + future.completeExceptionally(exc); + } + } + }); + }); + return future; //.orTimeout(3, TimeUnit.SECONDS) JDK9以上才支持 + } + + private CompletableFuture selectdb(final AsyncConnection conn, final int db, final String command) { + final CompletableFuture rsfuture = new CompletableFuture(); + try { + final BsonByteBufferWriter dbwriter = new BsonByteBufferWriter(transport.getBufferSupplier()); + dbwriter.writeTo(ASTERISK_BYTE); + dbwriter.writeTo((byte) '2'); + dbwriter.writeTo((byte) '\r', (byte) '\n'); + dbwriter.writeTo(DOLLAR_BYTE); + dbwriter.writeTo((byte) '6'); + dbwriter.writeTo((byte) '\r', (byte) '\n'); + dbwriter.writeTo("SELECT".getBytes(StandardCharsets.UTF_8)); + dbwriter.writeTo((byte) '\r', (byte) '\n'); + + dbwriter.writeTo(DOLLAR_BYTE); + dbwriter.writeTo(String.valueOf(String.valueOf(db).length()).getBytes(StandardCharsets.UTF_8)); + dbwriter.writeTo((byte) '\r', (byte) '\n'); + dbwriter.writeTo(String.valueOf(db).getBytes(StandardCharsets.UTF_8)); + dbwriter.writeTo((byte) '\r', (byte) '\n'); + + final ByteBuffer[] authbuffers = dbwriter.toBuffers(); + conn.write(authbuffers, authbuffers, new CompletionHandler() { + @Override + public void completed(Integer result, ByteBuffer[] attachments) { + int index = -1; + try { + for (int i = 0; i < attachments.length; i++) { + if (attachments[i].hasRemaining()) { + index = i; + break; + } else { + transport.offerBuffer(attachments[i]); + } + } + if (index == 0) { + conn.write(attachments, attachments, this); + return; + } else if (index > 0) { + ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; + System.arraycopy(attachments, index, newattachs, 0, newattachs.length); + conn.write(newattachs, newattachs, this); + return; + } + //----------------------- 读取返回结果 ------------------------------------- + conn.read(new ReplyCompletionHandler(conn) { + @Override + public void completed(Integer result, ByteBuffer buffer) { + buffer.flip(); + try { + final byte sign = buffer.get(); + if (sign == PLUS_BYTE) { // + + byte[] bs = readBytes(buffer); + if ("OK".equalsIgnoreCase(new String(bs))) { + conn.setSubobject("authed+db"); + rsfuture.complete(conn); + } else { + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); + } + } else if (sign == MINUS_BYTE) { // - 异常 + String bs = readString(buffer); + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); + } else { + String exstr = "Unknown reply: " + (char) sign; + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException(exstr)); + } + } catch (Exception e) { + failed(e, buffer); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + conn.offerBuffer(buffer); + transport.offerConnection(true, conn); + rsfuture.completeExceptionally(exc); + } + + }); + } catch (Exception e) { + failed(e, attachments); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer[] attachments) { + transport.offerConnection(true, conn); + rsfuture.completeExceptionally(exc); + } + }); + } catch (Exception e) { + rsfuture.completeExceptionally(e); + } + return rsfuture; + } + + private CompletableFuture auth(final AsyncConnection conn, final byte[] password, final String command) { + final CompletableFuture rsfuture = new CompletableFuture(); + try { + final BsonByteBufferWriter authwriter = new BsonByteBufferWriter(transport.getBufferSupplier()); + authwriter.writeTo(ASTERISK_BYTE); + authwriter.writeTo((byte) '2'); + authwriter.writeTo((byte) '\r', (byte) '\n'); + authwriter.writeTo(DOLLAR_BYTE); + authwriter.writeTo((byte) '4'); + authwriter.writeTo((byte) '\r', (byte) '\n'); + authwriter.writeTo("AUTH".getBytes(StandardCharsets.UTF_8)); + authwriter.writeTo((byte) '\r', (byte) '\n'); + + authwriter.writeTo(DOLLAR_BYTE); + authwriter.writeTo(String.valueOf(password.length).getBytes(StandardCharsets.UTF_8)); + authwriter.writeTo((byte) '\r', (byte) '\n'); + authwriter.writeTo(password); + authwriter.writeTo((byte) '\r', (byte) '\n'); + + final ByteBuffer[] authbuffers = authwriter.toBuffers(); + conn.write(authbuffers, authbuffers, new CompletionHandler() { + @Override + public void completed(Integer result, ByteBuffer[] attachments) { + int index = -1; + try { + for (int i = 0; i < attachments.length; i++) { + if (attachments[i].hasRemaining()) { + index = i; + break; + } else { + transport.offerBuffer(attachments[i]); + } + } + if (index == 0) { + conn.write(attachments, attachments, this); + return; + } else if (index > 0) { + ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; + System.arraycopy(attachments, index, newattachs, 0, newattachs.length); + conn.write(newattachs, newattachs, this); + return; + } + //----------------------- 读取返回结果 ------------------------------------- + conn.read(new ReplyCompletionHandler(conn) { + @Override + public void completed(Integer result, ByteBuffer buffer) { + buffer.flip(); + try { + final byte sign = buffer.get(); + if (sign == PLUS_BYTE) { // + + byte[] bs = readBytes(buffer); + if ("OK".equalsIgnoreCase(new String(bs))) { + conn.setSubobject("authed"); + rsfuture.complete(conn); + } else { + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); + } + } else if (sign == MINUS_BYTE) { // - 异常 + String bs = readString(buffer); + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); + } else { + String exstr = "Unknown reply: " + (char) sign; + transport.offerConnection(false, conn); + rsfuture.completeExceptionally(new RuntimeException(exstr)); + } + } catch (Exception e) { + failed(e, buffer); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + conn.offerBuffer(buffer); + transport.offerConnection(true, conn); + rsfuture.completeExceptionally(exc); + } + + }); + } catch (Exception e) { + failed(e, attachments); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer[] attachments) { + transport.offerConnection(true, conn); + rsfuture.completeExceptionally(exc); + } + }); + } catch (Exception e) { + rsfuture.completeExceptionally(e); + } + return rsfuture; + } +} + +abstract class ReplyCompletionHandler implements CompletionHandler { + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + protected final ByteArray out = new ByteArray(); + + protected final AsyncConnection conn; + + public ReplyCompletionHandler(AsyncConnection conn) { + this.conn = conn; + } + + protected byte[] readBytes(ByteBuffer buffer) throws IOException { + readLine(buffer); + return out.getBytesAndClear(); + } + + protected String readString(ByteBuffer buffer) throws IOException { + readLine(buffer); + return out.toStringAndClear(null);//传null则表示使用StandardCharsets.UTF_8 + } + + protected int readInt(ByteBuffer buffer) throws IOException { + return (int) readLong(buffer); + } + + protected long readLong(ByteBuffer buffer) throws IOException { + readLine(buffer); + int start = 0; + if (out.get(0) == '$') start = 1; + boolean negative = out.get(start) == '-'; + long value = negative ? 0 : (out.get(start) - '0'); + for (int i = 1 + start; i < out.size(); i++) { + value = value * 10 + (out.get(i) - '0'); + } + out.clear(); + return negative ? -value : value; + } + + private void readLine(ByteBuffer buffer) throws IOException { + boolean has = buffer.hasRemaining(); + byte lasted = has ? buffer.get() : 0; + if (lasted == '\n' && !out.isEmpty() && out.getLastByte() == '\r') { + out.removeLastByte();//读掉 \r + //buffer.get();//读掉 \n + //logger.info("打印buffer.get()---> " + buffer.get()); + logger.info("--- 打印buffer start --- "); + return;//传null则表示使用StandardCharsets.UTF_8 + } + if (has) out.write(lasted); + while (buffer.hasRemaining()) { + byte b = buffer.get(); + if (b == '\n' && lasted == '\r') { + out.removeLastByte(); + return; + } + out.write(lasted = b); + } + //说明数据还没读取完 + buffer.clear(); + conn.readableByteChannel().read(buffer); + buffer.flip(); + readLine(buffer); + } + +} diff --git a/src/com/zdemo/cachex/RedisTest.java b/src/com/zdemo/cachex/RedisTest.java new file mode 100644 index 0000000..4ae18e6 --- /dev/null +++ b/src/com/zdemo/cachex/RedisTest.java @@ -0,0 +1,237 @@ +package com.zdemo.cachex; + +import org.redkale.convert.json.JsonFactory; +import org.redkale.util.AnyValue; + +import java.util.Map; + +public class RedisTest { + + static MyRedisCacheSource source = new MyRedisCacheSource(); + + static { + AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue(); + conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "47.111.150.118").addValue("port", "6064").addValue("password", "*Zhong9307!").addValue("db", 2)); + + source.defaultConvert = JsonFactory.root().getConvert(); + source.initValueType(String.class); //value用String类型 + source.init(conf); + } + + public static void main(String[] args) { + + //System.out.println(source.remove("a", "b")); + + // bit + /*source.initValueType(Integer.class); + source.remove("a"); + boolean a = source.getBit("a", 1); + System.out.println(a); + + source.setBit("a", 1, true); + a = source.getBit("a", 1); + System.out.println("bit-a-1: " + a); + + source.setBit("a", 1, false); + a = source.getBit("a", 1); + System.out.println("bit-a-1: " + a);*/ + + source.remove("a"); + + // setnx + System.out.println(source.setnx("a", 1)); + source.remove("a"); + System.out.println(source.setnx("a", 1)); + + /*int[] arr = {0}; + ExecutorService executor = Executors.newFixedThreadPool(10); + CountDownLatch latch = new CountDownLatch(10_0000); + for (int i = 0; i < 10_0000; i++) { + executor.submit(() -> { + try { + source.lock("a", 50000); + arr[0]++; + System.out.println("Thread: " + Thread.currentThread().getName()); + Thread.sleep(2000); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + source.unlock("a"); + latch.countDown(); + } + }); + } + try { + latch.await(); + System.out.println("n=" + arr[0]); + executor.shutdown(); + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + + + /*List list = (List) source.getCollection("gamerank-comment-stat"); + System.out.println(list);*/ + + /*for (int i = 0; i < 10; i++) { + String brpop = source.brpop("z", 2); + System.out.println(brpop); + }*/ + + // key 测试 + /*source.set("a", "123321"); + System.out.println(source.get("a")); // 123321 + System.out.println(source.getTtl("a")); // -1 + System.out.println(source.getPttl("a")); // -1 + System.out.println(source.getPttl("x")); // -2*/ + + // hashmap 测试 + /*source.remove("sk"); + source.setHm("sk", "a", "1"); + source.setHm("sk", "b", "2"); + System.out.println(source.getHm("sk", "a")); // 1 + source.remove("sk"); + + source.setHms("sk", Map.of("b", "5", "c", "3", "a", "1")); + source.hdel("sk", "a"); + + Map map = source.getHms("sk", "a", "x", "b", "c", "f"); // {b=5, c=3} + System.out.println(map); + System.out.println(source.getHmall("sk")); //{b=5, c=3} + System.out.println(source.incrHm("sk", "b", 1.1d)); // b = 6.1 + System.out.println(source.incrHm("sk", "c", 1)); // c = 4 + System.out.println(source.getHmall("sk")); //{b=6.1, c=4} + + System.out.println("--------------"); + System.out.println(source.hexists("sk", "b")); // true + System.out.println(source.getCollectionSize("sk")); // 2*/ + + + Map hms = source.getHms("supportusers", "5-kfeu0f", "xxxx", "3-0kbt7u8t", "95q- "); + hms.forEach((k, v) -> { + System.out.println(k + " : " + v); + }); + + + /*MyRedisCacheSource source2 = new MyRedisCacheSource(); + source2.defaultConvert = JsonFactory.root().getConvert(); + source2.initValueType(String.class); //value用String类型 + source2.init(conf);*/ + + /*Map gcMap = source.getHmall("hot-gamecomment"); + gcMap.forEach((k,v) -> { + System.out.println(k + " : " + v); + });*/ + + + //Map gameinfo = source.getHms("gameinfo", "22759", "22838", "10097", "22751", "22632", "22711", "22195", "15821", "10099", "16313", "11345", "10534", "22768", "22647", "22924", "18461", "15871", "17099", "22640", "22644", "10744", "10264", "18032", "22815", "13584", "10031", "22818", "22452", "22810", "10513", "10557", "15848", "11923", "15920", "22808", "20073", "22809", "15840", "12332", "15803", "10597", "22624", "17113", "19578", "22664", "22621", "20722", "16226", "10523", "12304", "10597","11923","10031"); + //Map gameinfo = source.getHms("gameinfo", "22759","22838","10097","22751","22632","22711","22195","15821","10099","16313","11345","10534","22768","22647","22924","18461","15871","17099","22363","22640","22644","10744","10264","18032","22815","13584","22818","22452","22810","10513","10557","15848","15920","22808","20073","22809","15840","12332","15803","10597","22624","17113","19578","22627","22664","22621","20722","16226","10523","12304"); + + /*gameinfo.forEach((k,v ) -> { + System.out.println(v); + });*/ + + + /*source.queryKeysStartsWith("articlebean:").forEach(x -> { + System.out.println(x); + //source.remove(x); + //System.out.println(source.getHmall(x)); + });*/ + + // list 测试 + /*MyRedisCacheSource sourceInt = new MyRedisCacheSource(); + sourceInt.defaultConvert = JsonFactory.root().getConvert(); + sourceInt.initValueType(Integer.class); //value用String类型 + sourceInt.init(conf); + sourceInt.remove("list"); + Collection list = sourceInt.getCollection("list"); + System.out.println(list); + for (int i = 1; i <= 10; i++) { + sourceInt.appendListItem("list", i); + } + System.out.println(sourceInt.getCollection("list")); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + sourceInt.appendListItems("list", 11, 12, 13); + System.out.println(sourceInt.getCollection("list")); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + System.out.println(sourceInt.getCollection("list", 0, 5)); // [1, 2, 3, 4, 5] + System.out.println(sourceInt.getCollectionSize("list")); // 13 + + List ids = new ArrayList<>(100); + for (int i = 0; i < 5000; i++) { + ids.add(i); + } + sourceInt.remove("abx"); + sourceInt.appendListItems("abx", ids.toArray(Integer[]::new)); + System.out.println(sourceInt.getCollection("abx"));*/ + + /*System.out.println(sourceInt.getCollectionSize("recommend-user-quality")); + Collection uid = sourceInt.getCollection("recommend-user-quality"); + System.out.println(uid);*/ + + // zset 测试 + /*source.initValueType(String.class); //value用Integer类型 + source.remove("zx"); + source.zadd("zx", Map.of("a", 1, "b", 2)); + + source.zadd("zx", Map.of("a", 1, "c", 5L)); + source.zadd("zx", Map.of("x", 20, "j", 3.5)); + source.zadd("zx", Map.of("f", System.currentTimeMillis(), "c", 5L)); + source.zadd("zx", Map.of("a", 1, "c", 5L)); + + System.out.println(source.zincr("zx", "a", 1.34)); // 2.34 + System.out.println(source.getZsetDoubleScore("zx")); // {f=1592924555704, x=20, c=5, j=3, b=2.34, a=1} + source.zrem("zx", "b", "c", "e", "x"); + System.out.println(source.getZsetLongScore("zx")); // {f=1592924555704, j=3, a=2} + + System.out.println("--------------"); + System.out.println(source.getZsetLongScore("zx", "f")); + + System.out.println(source.getZrevrank("zx", "f")); // 0 + System.out.println(source.getZrank("zx", "f")); // 2 + System.out.println(source.getZrank("zx", "Y")); // -1 + System.out.println(source.getCollectionSize("zx")); // 3 + + System.out.println(source.getZset("zx")); + System.out.println(source.zexists("zx", "f", "x", "a"));*/ + + /*LocalDate date = LocalDate.of(2019, 12, 31); + for (int i = 0; i < 60; i++) { + LocalDate localDate = date.plusDays(-i); + String day = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); + System.out.println(String.format("mkdir %s; mv *%s*.zip %s", day, day, day)); + }*/ + + + /*MyRedisCacheSource source = new MyRedisCacheSource(); + source.defaultConvert = JsonFactory.root().getConvert(); + source.initValueType(UserDetail.class); + source.init(conf); + + + Map map = source.getHmall("user-detail"); + + Integer[] array = map.values().stream().map(x -> x.getUserid()).toArray(Integer[]::new); + + System.out.println(JsonConvert.root().convertTo(array)); + + Map hms = source.getHms("user-detail", 11746, 11988, 11504, 11987, 11745, 11503, 11748, 11506, 11747, 11989, 11505, 11508, 11507, 11509, 11980, 11740, 11982, 11981, 11984, 11742, 11500, 11983, 11741, 11502, 11744, 11986, 11985, 11501, 11743, 11999, 11757, 11515, 1, 11514, 11998, 11756, 2, 11517, 11516, 11758, 3, 11519, 4, 5, 11518, 6, 7, 11991, 8, 11990, 9, 11993, 11751, 11750, 11992, 11753, 11511, 11995, 11994, 11510, 11752, 11755, 11513, 11997, 11512, 11996, 11754, 11724, 11966, 11965, 11723, 11968, 11726, 11967, 11725, 11728, 11969, 11727, 11729, 11960, 11720, 11962, 11961, 11722, 11964, 11721); + + System.out.println(hms.size());*/ + + /*source.getCollection("article-comment-list", 19, 1).forEach(x -> System.out.println(x)); + + + while (true) { + System.out.println("---" + Utility.now() + "---"); + source.getHmall("ck").forEach((k, v) -> { + System.out.println(k + ":" + v); + }); + try { + Thread.sleep(60 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }*/ + } +} diff --git a/src/com/zdemo/cachex/RedissionCacheSource.java b/src/com/zdemo/cachex/RedissionCacheSource.java new file mode 100644 index 0000000..59e0b9d --- /dev/null +++ b/src/com/zdemo/cachex/RedissionCacheSource.java @@ -0,0 +1,1944 @@ +/* + * 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; + +import java.io.*; +import java.lang.reflect.Type; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.*; +import java.util.stream.Collectors; +import javax.annotation.Resource; +import org.redisson.Redisson; +import org.redisson.api.*; +import org.redisson.config.*; +import org.redkale.convert.Convert; +import org.redkale.convert.json.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.service.*; +import org.redkale.source.*; +import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; + +*/ +/** + * //https://www.cnblogs.com/xiami2046/p/13934146.html + * + * @author zhangjx + *//* + +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedissionCacheSource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + @Resource + protected JsonConvert defaultConvert; + + @Resource(name = "$_convert") + protected JsonConvert convert; + + protected Type objValueType = String.class; + + protected List nodeAddrs; + + protected int db; + + protected RedissonClient redisson; + + @Override + public void init(AnyValue conf) { + if (this.convert == null) this.convert = this.defaultConvert; + if (conf == null) conf = new AnyValue.DefaultAnyValue(); + + final List addresses = new ArrayList<>(); + Config config = new Config(); + AnyValue[] nodes = conf.getAnyValues("node"); + String type = conf.getOrDefault("type", ""); + BaseConfig baseConfig = null; + for (AnyValue node : nodes) { + String addr = node.getValue("addr"); + addresses.add(addr); + String db0 = node.getValue("db", "").trim(); + if (!db0.isEmpty()) this.db = Integer.valueOf(db0); + if (nodes.length == 1) { + baseConfig = config.useSingleServer(); + config.useSingleServer().setAddress(addr); + config.useSingleServer().setDatabase(this.db); + } else if ("masterslave".equalsIgnoreCase(type)) { //主从 + baseConfig = config.useMasterSlaveServers(); + if (node.get("master") != null) { + config.useMasterSlaveServers().setMasterAddress(addr); + } else { + config.useMasterSlaveServers().addSlaveAddress(addr); + } + config.useMasterSlaveServers().setDatabase(this.db); + } else if ("cluster".equalsIgnoreCase(type)) { //集群 + baseConfig = config.useClusterServers(); + config.useClusterServers().addNodeAddress(addr); + } else if ("replicated".equalsIgnoreCase(type)) { // + baseConfig = config.useReplicatedServers(); + config.useReplicatedServers().addNodeAddress(addr); + config.useReplicatedServers().setDatabase(this.db); + } else if ("sentinel".equalsIgnoreCase(type)) { // + baseConfig = config.useSentinelServers(); + config.useSentinelServers().addSentinelAddress(addr); + config.useSentinelServers().setDatabase(this.db); + } + } + if (baseConfig != null) { + String username = conf.getValue("username", "").trim(); + String password = conf.getValue("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)); + } + this.redisson = Redisson.create(config); + this.nodeAddrs = addresses; + if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedisCacheSource.class.getSimpleName() + ": addrs=" + addresses + ", db=" + db); + + } + + @Override //ServiceLoader时判断配置是否符合当前实现类 + public boolean match(AnyValue config) { + if (config == null) return false; + AnyValue[] nodes = config.getAnyValues("node"); + if (nodes == null || nodes.length == 0) return false; + for (AnyValue node : nodes) { + String val = node.getValue("addr"); + if (val != null && val.startsWith("redis://")) return true; + } + return false; + } + + @Override + @Deprecated + public final void initValueType(Type valueType) { + this.objValueType = valueType == null ? String.class : valueType; + } + + @Override + @Deprecated + public final void initTransient(boolean flag) { + } + + @Override + public final String getType() { + return "redis"; + } + + protected CompletableFuture completableFuture(CompletionStage rf) { + CompletableFuture future = new CompletableFuture(); + rf.whenComplete((r, t) -> { + if (t != null) { + future.completeExceptionally(t); + } else { + future.complete(r); + } + }); + return future; + } + + public static void main(String[] args) throws Exception { + DefaultAnyValue conf = new DefaultAnyValue().addValue("maxconns", "1"); + conf.addValue("node", new DefaultAnyValue().addValue("addr", "redis://127.0.0.1:6363")); + + RedissionCacheSource source = new RedissionCacheSource(); + source.defaultConvert = JsonFactory.root().getConvert(); + source.init(conf); + InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 7788); + try { + System.out.println("------------------------------------"); + source.removeAsync("stritem1"); + source.removeAsync("stritem2"); + source.setStringAsync("stritem1", "value1"); + source.setStringAsync("stritem2", "value2"); + System.out.println("stritem开头的key有两个: " + source.queryKeysStartsWith("stritem")); + System.out.println("[有值] MGET : " + source.getStringMap("stritem1", "stritem2")); + System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("stritem1", "stritem2"))); + + source.remove("intitem1"); + source.remove("intitem2"); + source.setLong("intitem1", 333); + source.setLong("intitem2", 444); + System.out.println("[有值] MGET : " + source.getStringMap("intitem1", "intitem22", "intitem2")); + System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("intitem1", "intitem22", "intitem2"))); + source.remove("objitem1"); + source.remove("objitem2"); + source.set("objitem1", Flipper.class, new Flipper(10)); + source.set("objitem2", Flipper.class, new Flipper(20)); + System.out.println("[有值] MGET : " + source.getMap(Flipper.class, "objitem1", "objitem2")); + + source.remove("key1"); + source.remove("key2"); + source.remove("300"); + source.set(1000, "key1", String.class, "value1"); + source.set("key1", String.class, "value1"); + source.setString("keystr1", "strvalue1"); + source.setLong("keylong1", 333L); + source.set("300", String.class, "4000"); + source.getAndRefresh("key1", 3500, String.class); + System.out.println("[有值] 300 GET : " + source.get("300", String.class)); + System.out.println("[有值] key1 GET : " + source.get("key1", String.class)); + System.out.println("[无值] key2 GET : " + source.get("key2", String.class)); + System.out.println("[有值] keystr1 GET : " + source.getString("keystr1")); + System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L)); + System.out.println("[有值] key1 EXISTS : " + source.exists("key1")); + System.out.println("[无值] key2 EXISTS : " + source.exists("key2")); + + source.remove("keys3"); + source.appendListItem("keys3", String.class, "vals1"); + source.appendListItem("keys3", String.class, "vals2"); + System.out.println("-------- keys3 追加了两个值 --------"); + System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3", String.class)); + System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3")); + source.removeListItem("keys3", String.class, "vals1"); + System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3", String.class)); + source.getCollectionAndRefresh("keys3", 3000, String.class); + + source.remove("stringmap"); + source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("a", "aa", "b", "bb")); + source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("c", "cc", "d", "dd")); + System.out.println("[两值] stringmap VALUES : " + source.getCollectionAsync("stringmap", JsonConvert.TYPE_MAP_STRING_STRING).join()); + + source.remove("sets3"); + source.remove("sets4"); + source.appendSetItem("sets3", String.class, "setvals1"); + source.appendSetItem("sets3", String.class, "setvals2"); + source.appendSetItem("sets3", String.class, "setvals1"); + source.appendSetItem("sets4", String.class, "setvals2"); + source.appendSetItem("sets4", String.class, "setvals1"); + System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3", String.class)); + System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3")); + System.out.println("[有值] sets3-setvals2 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals2")); + System.out.println("[有值] sets3-setvals3 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals3")); + source.removeSetItem("sets3", String.class, "setvals1"); + System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3", String.class)); + System.out.println("sets3 大小 : " + source.getCollectionSize("sets3")); + System.out.println("all keys: " + source.queryKeys()); + System.out.println("key startkeys: " + source.queryKeysStartsWith("key")); + System.out.println("newnum 值 : " + source.incr("newnum")); + System.out.println("newnum 值 : " + source.decr("newnum")); + System.out.println("sets3&sets4: " + source.getStringCollectionMap(true, "sets3", "sets4")); + System.out.println("------------------------------------"); + source.set("myaddr", InetSocketAddress.class, addr); + System.out.println("myaddrstr: " + source.getString("myaddr")); + System.out.println("myaddr: " + source.get("myaddr", InetSocketAddress.class)); + source.remove("myaddrs"); + source.remove("myaddrs2"); + source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); + System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); + source.removeSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); + source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); + source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); + System.out.println("myaddrs&myaddrs2: " + source.getCollectionMap(true, InetSocketAddress.class, "myaddrs", "myaddrs2")); + System.out.println("------------------------------------"); + source.remove("myaddrs"); + Type mapType = new TypeToken>() { + }.getType(); + Map map = new HashMap<>(); + map.put("a", 1); + map.put("b", 2); + source.set("mapvals", mapType, map); + System.out.println("mapvals: " + source.get("mapvals", mapType)); + + source.remove("byteskey"); + source.setBytes("byteskey", new byte[]{1, 2, 3}); + System.out.println("byteskey 值 : " + Arrays.toString(source.getBytes("byteskey"))); + //h + source.remove("hmap"); + source.hincr("hmap", "key1"); + System.out.println("hmap.key1 值 : " + source.hgetLong("hmap", "key1", -1)); + source.hmset("hmap", "key2", "haha", "key3", 333); + source.hmset("hmap", "sm", (HashMap) Utility.ofMap("a", "aa", "b", "bb")); + System.out.println("hmap.sm 值 : " + source.hget("hmap", "sm", JsonConvert.TYPE_MAP_STRING_STRING)); + System.out.println("hmap.[key1,key2,key3] 值 : " + source.hmget("hmap", String.class, "key1", "key2", "key3")); + System.out.println("hmap.keys 四值 : " + source.hkeys("hmap")); + source.hremove("hmap", "key1", "key3"); + System.out.println("hmap.keys 两值 : " + source.hkeys("hmap")); + System.out.println("hmap.key2 值 : " + source.hgetString("hmap", "key2")); + System.out.println("hmap列表(2)大小 : " + source.hsize("hmap")); + + source.remove("hmaplong"); + source.hincr("hmaplong", "key1", 10); + source.hsetLong("hmaplong", "key2", 30); + System.out.println("hmaplong.所有两值 : " + source.hmap("hmaplong", long.class, 0, 10)); + + source.remove("hmapstr"); + source.hsetString("hmapstr", "key1", "str10"); + source.hsetString("hmapstr", "key2", null); + System.out.println("hmapstr.所有一值 : " + source.hmap("hmapstr", String.class, 0, 10)); + + source.remove("hmapstrmap"); + source.hset("hmapstrmap", "key1", JsonConvert.TYPE_MAP_STRING_STRING, (HashMap) Utility.ofMap("ks11", "vv11")); + source.hset("hmapstrmap", "key2", JsonConvert.TYPE_MAP_STRING_STRING, null); + System.out.println("hmapstrmap.无值 : " + source.hmap("hmapstrmap", JsonConvert.TYPE_MAP_STRING_STRING, 0, 10, "key2*")); + + source.remove("popset"); + source.appendStringSetItem("popset", "111"); + source.appendStringSetItem("popset", "222"); + source.appendStringSetItem("popset", "333"); + source.appendStringSetItem("popset", "444"); + source.appendStringSetItem("popset", "555"); + System.out.println("SPOP一个元素:" + source.spopStringSetItem("popset")); + System.out.println("SPOP两个元素:" + source.spopStringSetItem("popset", 2)); + System.out.println("SPOP五个元素:" + source.spopStringSetItem("popset", 5)); + source.appendLongSetItem("popset", 111); + source.appendLongSetItem("popset", 222); + source.appendLongSetItem("popset", 333); + source.appendLongSetItem("popset", 444); + source.appendLongSetItem("popset", 555); + System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); + System.out.println("SPOP两个元素:" + source.spopLongSetItem("popset", 2)); + System.out.println("SPOP五个元素:" + source.spopLongSetItem("popset", 5)); + System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); + + //清除 + int rs = source.remove("stritem1"); + System.out.println("删除stritem1个数: " + rs); + source.remove("popset"); + source.remove("stritem2"); + source.remove("intitem1"); + source.remove("intitem2"); + source.remove("keylong1"); + source.remove("keystr1"); + source.remove("mapvals"); + source.remove("myaddr"); + source.remove("myaddrs2"); + source.remove("newnum"); + source.remove("objitem1"); + source.remove("objitem2"); + source.remove("key1"); + source.remove("key2"); + source.remove("keys3"); + source.remove("sets3"); + source.remove("sets4"); + source.remove("myaddrs"); + source.remove("300"); + source.remove("stringmap"); + source.remove("hmap"); + source.remove("hmaplong"); + source.remove("hmapstr"); + source.remove("hmapstrmap"); + source.remove("byteskey"); + System.out.println("------------------------------------"); +// System.out.println("--------------测试大文本---------------"); +// HashMap bigmap = new HashMap<>(); +// StringBuilder sb = new StringBuilder(); +// sb.append("起始"); +// for (int i = 0; i < 1024 * 1024; i++) { +// sb.append("abcde"); +// } +// sb.append("结束"); +// bigmap.put("val", sb.toString()); +// System.out.println("文本长度: " + sb.length()); +// source.set("bigmap", JsonConvert.TYPE_MAP_STRING_STRING, bigmap); +// System.out.println("写入完成"); +// for (int i = 0; i < 1; i++) { +// HashMap fs = (HashMap) source.get("bigmap", JsonConvert.TYPE_MAP_STRING_STRING); +// System.out.println("内容长度: " + fs.get("val").length()); +// } + source.remove("bigmap"); + + } finally { + source.close(); + } + } + + @Override + public void close() throws Exception { //在 Application 关闭时调用 + destroy(null); + } + + @Override + public String resourceName() { + Resource res = this.getClass().getAnnotation(Resource.class); + return res == null ? "" : res.name(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{addrs = " + this.nodeAddrs + ", db=" + this.db + "}"; + } + + @Override + public void destroy(AnyValue conf) { + if (redisson != null) redisson.shutdown(); + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.isExistsAsync()); + } + + @Override + public boolean exists(String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.isExists(); + } + + //--------------------- get ------------------------------ + @Override + @Deprecated + public CompletableFuture getAsync(String key) { + return getAsync(key, objValueType); + } + + @Override + public CompletableFuture getAsync(String key, Type type) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAsync().thenApply(bs -> bs == null ? null : convert.convertFrom(type, bs))); + } + + @Override + public CompletableFuture getStringAsync(String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.getAsync()); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + return completableFuture(bucket.getAsync()); + } + + @Override + @Deprecated + public V get(String key) { + return get(key, objValueType); + } + + @Override + public T get(String key, final Type type) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + byte[] bs = bucket.get(); + return bs == null ? null : convert.convertFrom(type, bs); + } + + @Override + public String getString(String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + return bucket.get(); + } + + @Override + public long getLong(String key, long defValue) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + return bucket.get(); + } + + //--------------------- getAndRefresh ------------------------------ + @Override + @Deprecated + public CompletableFuture getAndRefreshAsync(String key, int expireSeconds) { + return getAndRefreshAsync(key, expireSeconds, objValueType); + } + + @Override + public CompletableFuture getAndRefreshAsync(String key, int expireSeconds, final Type type) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAsync().thenCompose(bs -> { + T rs = convert.convertFrom(type, bs); + if (rs == null) return CompletableFuture.completedFuture(null); + return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); + })); + } + + @Override + @Deprecated + public V getAndRefresh(String key, final int expireSeconds) { + return getAndRefresh(key, expireSeconds, objValueType); + } + + @Override + public T getAndRefresh(String key, final int expireSeconds, final Type type) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + T rs = convert.convertFrom(type, bucket.get()); + if (rs == null) return rs; + bucket.expire(expireSeconds, TimeUnit.SECONDS); + return rs; + } + + @Override + public CompletableFuture getStringAndRefreshAsync(String key, int expireSeconds) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.getAsync().thenCompose(rs -> { + if (rs == null) return CompletableFuture.completedFuture(null); + return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); + })); + } + + @Override + public String getStringAndRefresh(String key, final int expireSeconds) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + String rs = bucket.get(); + if (rs == null) return rs; + bucket.expire(expireSeconds, TimeUnit.SECONDS); + return rs; + } + + @Override + public CompletableFuture getLongAndRefreshAsync(String key, int expireSeconds, long defValue) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + return completableFuture(bucket.getAsync().thenCompose(rs -> { + if (rs == null) return CompletableFuture.completedFuture(defValue); + return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); + })); + } + + @Override + public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + long rs = bucket.get(); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + return rs; + } + + //--------------------- refresh ------------------------------ + @Override + public CompletableFuture refreshAsync(String key, int expireSeconds) { + final RBucket bucket = redisson.getBucket(key); + return completableFuture(bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public void refresh(String key, final int expireSeconds) { + final RBucket bucket = redisson.getBucket(key); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + //--------------------- set ------------------------------ + @Override + @Deprecated + public CompletableFuture setAsync(String key, V value) { + return setAsync(key, objValueType, value); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert0, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? this.convert : convert0).convertToBytes(value))); + } + + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(this.convert.convertToBytes(type, value))); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert0, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? this.convert : convert0).convertToBytes(type, value))); + } + + @Override + @Deprecated + public void set(final String key, V value) { + set(key, objValueType, value); + } + + @Override + public void set(final String key, final Convert convert0, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? this.convert : convert0).convertToBytes(value)); + } + + @Override + public void set(final String key, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set(this.convert.convertToBytes(type, value)); + } + + @Override + public void set(String key, final Convert convert0, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? this.convert : convert0).convertToBytes(type, value)); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return completableFuture(redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE).setAsync(value)); + } + + @Override + public void setString(String key, String value) { + redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE).set(value); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return completableFuture(redisson.getAtomicLong(key).setAsync(value)); + } + + @Override + public void setLong(String key, long value) { + redisson.getAtomicLong(key).set(value); + } + + //--------------------- set ------------------------------ + @Override + @Deprecated + public CompletableFuture setAsync(int expireSeconds, String key, V value) { + return setAsync(expireSeconds, key, objValueType, value); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert0, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(convert.convertToBytes(type, value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert0, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); + } + + @Override + @Deprecated + public void set(int expireSeconds, String key, V value) { + set(expireSeconds, key, objValueType, value); + } + + @Override + public void set(int expireSeconds, String key, Convert convert0, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? convert : convert0).convertToBytes(value)); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public void set(int expireSeconds, String key, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set(convert.convertToBytes(type, value)); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public void set(int expireSeconds, String key, Convert convert0, final Type type, T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.setAsync(value).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); + } + + @Override + public void setString(int expireSeconds, String key, String value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); + bucket.set(value); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + return completableFuture(bucket.setAsync(value).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); + } + + @Override + public void setLong(int expireSeconds, String key, long value) { + final RAtomicLong bucket = redisson.getAtomicLong(key); + bucket.set(value); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + //--------------------- setExpireSeconds ------------------------------ + @Override + public CompletableFuture setExpireSecondsAsync(String key, int expireSeconds) { + return completableFuture(redisson.getBucket(key).expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public void setExpireSeconds(String key, int expireSeconds) { + redisson.getBucket(key).expire(expireSeconds, TimeUnit.SECONDS); + } + + //--------------------- remove ------------------------------ + @Override + public CompletableFuture removeAsync(String key) { + return completableFuture(redisson.getBucket(key).deleteAsync().thenApply(rs -> rs ? 1 : 0)); + } + + @Override + public int remove(String key) { + return redisson.getBucket(key).delete() ? 1 : 0; + } + + //--------------------- incr ------------------------------ + @Override + public long incr(final String key) { + return redisson.getAtomicLong(key).incrementAndGet(); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return completableFuture(redisson.getAtomicLong(key).incrementAndGetAsync()); + } + + @Override + public long incr(final String key, long num) { + return redisson.getAtomicLong(key).addAndGet(num); + } + + @Override + public CompletableFuture incrAsync(final String key, long num) { + return completableFuture(redisson.getAtomicLong(key).addAndGetAsync(num)); + } + + //--------------------- decr ------------------------------ + @Override + public long decr(final String key) { + return redisson.getAtomicLong(key).decrementAndGet(); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return completableFuture(redisson.getAtomicLong(key).decrementAndGetAsync()); + } + + @Override + public long decr(final String key, long num) { + return redisson.getAtomicLong(key).addAndGet(-num); + } + + @Override + public CompletableFuture decrAsync(final String key, long num) { + return completableFuture(redisson.getAtomicLong(key).addAndGetAsync(-num)); + } + + @Override + public int hremove(final String key, String... fields) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return (int) map.fastRemove(fields); + } + + @Override + public int hsize(final String key) { + return redisson.getMap(key, MapByteArrayCodec.instance).size(); + } + + @Override + public List hkeys(final String key) { + return (List) new ArrayList<>(redisson.getMap(key, MapStringCodec.instance).keySet()); + } + + @Override + public long hincr(final String key, String field) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, 1L); + } + + @Override + public long hincr(final String key, String field, long num) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, num); + } + + @Override + public long hdecr(final String key, String field) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, -1L); + } + + @Override + public long hdecr(final String key, String field, long num) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, num); + } + + @Override + public boolean hexists(final String key, String field) { + return redisson.getMap(key, MapByteArrayCodec.instance).containsKey(field); + } + + @Override + public void hset(final String key, final String field, final Convert convert0, final T value) { + if (value == null) return; + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + map.fastPut(field, (convert0 == null ? convert : convert0).convertToBytes(objValueType, value)); + } + + @Override + public void hset(final String key, final String field, final Type type, final T value) { + if (value == null) return; + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + map.fastPut(field, this.convert.convertToBytes(type, value)); + } + + @Override + public void hset(final String key, final String field, final Convert convert0, final Type type, final T value) { + if (value == null) return; + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + map.fastPut(field, (convert0 == null ? convert : convert0).convertToBytes(type, value)); + } + + @Override + public void hsetString(final String key, final String field, final String value) { + if (value == null) return; + RMap map = redisson.getMap(key, MapStringCodec.instance); + map.fastPut(field, value); + } + + @Override + public void hsetLong(final String key, final String field, final long value) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + map.fastPut(field, value); + } + + @Override + public void hmset(final String key, final Serializable... values) { + Map vals = new HashMap<>(); + for (int i = 0; i < values.length; i += 2) { + vals.put(String.valueOf(values[i]), this.convert.convertToBytes(values[i + 1])); + } + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + map.putAll(vals); + } + + @Override + public List hmget(final String key, final Type type, final String... fields) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + Map rs = map.getAll(Set.of(fields)); + List list = new ArrayList<>(fields.length); + for (String field : fields) { + byte[] bs = rs.get(field); + if (bs == null) { + list.add(null); + } else { + list.add(convert.convertFrom(type, bs)); + } + } + return list; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + Iterator it = map.keySet(pattern, offset + limit).iterator(); + final Map rs = new HashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) continue; + if (index >= offset + limit) break; + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) rs.put(field, convert.convertFrom(type, bs)); + } + return rs; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + Iterator it = map.keySet(offset + limit).iterator(); + final Map rs = new HashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) continue; + if (index >= offset + limit) break; + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) rs.put(field, convert.convertFrom(type, bs)); + } + return rs; + } + + @Override + public T hget(final String key, final String field, final Type type) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + byte[] bs = map.get(field); + return bs == null ? null : convert.convertFrom(type, bs); + } + + @Override + public String hgetString(final String key, final String field) { + RMap map = redisson.getMap(key, MapStringCodec.instance); + return map.get(field); + } + + @Override + public long hgetLong(final String key, final String field, long defValue) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + Long rs = map.get(field); + return rs == null ? defValue : rs; + } + + @Override + public CompletableFuture hremoveAsync(final String key, String... fields) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastRemoveAsync(fields).thenApply(r -> r.intValue())); + } + + @Override + public CompletableFuture hsizeAsync(final String key) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.sizeAsync()); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.readAllKeySetAsync().thenApply(set -> set == null ? null : new ArrayList(set))); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, 1L)); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field, long num) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, num)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, -1L)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field, long num) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, -num)); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.containsKeyAsync(field)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert0, final T value) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutAsync(field, (convert0 == null ? convert : convert0).convertToBytes(objValueType, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutAsync(field, convert.convertToBytes(type, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert0, final Type type, final T value) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutAsync(field, (convert0 == null ? convert : convert0).convertToBytes(type, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + if (value == null) return CompletableFuture.completedFuture(null); + RMap map = redisson.getMap(key, MapStringCodec.instance); + return completableFuture(map.fastPutAsync(field, value).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.fastPutAsync(field, value).thenApply(r -> null)); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Serializable... values) { + Map vals = new HashMap<>(); + for (int i = 0; i < values.length; i += 2) { + vals.put(String.valueOf(values[i]), this.convert.convertToBytes(values[i + 1])); + } + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.putAllAsync(vals)); + } + + @Override + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.getAllAsync(Set.of(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(convert.convertFrom(type, bs)); + } + } + return list; + })); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { + return CompletableFuture.supplyAsync(() -> { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + + Iterator it = map.keySet(offset + limit).iterator(); + final Map rs = new HashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) continue; + if (index >= offset + limit) break; + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) rs.put(field, convert.convertFrom(type, bs)); + } + return rs; + }); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { + return CompletableFuture.supplyAsync(() -> { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + + Iterator it = map.keySet(pattern, offset + limit).iterator(); + final Map rs = new HashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) continue; + if (index >= offset + limit) break; + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) rs.put(field, convert.convertFrom(type, bs)); + } + return rs; + }); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + RMap map = redisson.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.getAsync(field).thenApply(r -> r == null ? null : convert.convertFrom(type, r))); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + RMap map = redisson.getMap(key, MapStringCodec.instance); + return completableFuture(map.getAsync(field)); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + RMap map = redisson.getMap(key, MapLongCodec.instance); + return completableFuture(map.getAsync(field).thenApply(r -> r == null ? defValue : r.longValue())); + } + + //--------------------- collection ------------------------------ + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return redisson.getList(key).sizeAsync(); + } else { + return redisson.getSet(key).sizeAsync(); + } + })); + } + + @Override + public int getCollectionSize(String key) { + String type = redisson.getScript().eval(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE); + if (String.valueOf(type).contains("list")) { + return redisson.getList(key).size(); + } else { + return redisson.getSet(key).size(); + } + } + + @Override + @Deprecated + public CompletableFuture> getCollectionAsync(String key) { + return getCollectionAsync(key, objValueType); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) return list; + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(convert.convertFrom(componentType, bs)); + } + } + return rs; + }); + } else { + return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(set -> { + if (set == null || set.isEmpty()) return set; + Set rs = new HashSet<>(); + for (Object item : set) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(convert.convertFrom(componentType, bs)); + } + } + return rs; + }); + } + })); +// return (CompletableFuture) send("TYPE", null, componentType, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { +// if (t == null) return CompletableFuture.completedFuture(null); +// if (new String((byte[]) t).contains("list")) { //list +// return send("LRANGE", CacheEntryType.OBJECT, componentType, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); +// } else { +// return send("SMEMBERS", CacheEntryType.OBJECT, componentType, true, key, key.getBytes(StandardCharsets.UTF_8)); +// } +// }); + } + + @Override + public CompletableFuture> getLongMapAsync(String... keys) { + return completableFuture(redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys)); + } + + @Override + public CompletableFuture getLongArrayAsync(String... keys) { + return completableFuture(redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys).thenApply(map -> { + Long[] rs = new Long[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = (Long) map.get(keys[i]); + } + return rs; + })); + } + + @Override + public CompletableFuture getStringArrayAsync(String... keys) { + return completableFuture(redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).getAsync(keys).thenApply(map -> { + String[] rs = new String[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = (String) map.get(keys[i]); + } + return rs; + })); + } + + @Override + public CompletableFuture> getStringMapAsync(String... keys) { + return completableFuture(redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).getAsync(keys)); + } + + @Override + public CompletableFuture> getMapAsync(final Type componentType, String... keys) { + return completableFuture(redisson.getBuckets(org.redisson.client.codec.ByteArrayCodec.INSTANCE).getAsync(keys).thenApply(map -> { + Map rs = new HashMap(); + map.forEach((k, v) -> rs.put(k, convert.convertFrom(componentType, (byte[]) v))); + return rs; + })); + } + + @Override + public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) return list; + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(convert.convertFrom(componentType, bs)); + } + } + synchronized (map) { + map.put(key, rs); + } + return rs; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) return list; + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(convert.convertFrom(componentType, bs)); + } + } + synchronized (map) { + map.put(key, rs); + } + return rs; + })); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + @Deprecated + public Collection getCollection(String key) { + return getCollection(key, objValueType); + } + + @Override + public Collection getCollection(String key, final Type componentType) { + return (Collection) getCollectionAsync(key, componentType).join(); + } + + @Override + public Map getLongMap(final String... keys) { + return redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); + } + + @Override + public Long[] getLongArray(final String... keys) { + Map map = redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); + Long[] rs = new Long[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = map.get(keys[i]); + } + return rs; + } + + @Override + public Map getStringMap(final String... keys) { + return redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).get(keys); + } + + @Override + public String[] getStringArray(final String... keys) { + Map map = redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).get(keys); + String[] rs = new String[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = map.get(keys[i]); + } + return rs; + } + + @Override + public Map getMap(final Type componentType, final String... keys) { + Map map = redisson.getBuckets(org.redisson.client.codec.ByteArrayCodec.INSTANCE).get(keys); + Map rs = new HashMap(map.size()); + map.forEach((k, v) -> rs.put(k, convert.convertFrom(componentType, v))); + return rs; + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + return (Map) getCollectionMapAsync(set, componentType, keys).join(); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync(); + } else { + return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(s -> s == null ? null : new ArrayList(s)); + } + })); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + synchronized (map) { + map.put(key, (Collection) r); + } + } + return null; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + synchronized (map) { + map.put(key, new ArrayList(r)); + } + } + return null; + })); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Collection getStringCollection(String key) { + return getStringCollectionAsync(key).join(); + } + + @Override + public Map> getStringCollectionMap(final boolean set, String... keys) { + return getStringCollectionMapAsync(set, keys).join(); + } + + @Override + public CompletableFuture> getLongCollectionAsync(String key) { + return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync(); + } else { + return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(s -> s == null ? null : new ArrayList(s)); + } + })); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new HashMap<>(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (!set) { //list + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + synchronized (map) { + map.put(key, (Collection) r); + } + } + return null; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + synchronized (map) { + map.put(key, new ArrayList(r)); + } + } + return null; + })); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Collection getLongCollection(String key) { + return getLongCollectionAsync(key).join(); + } + + @Override + public Map> getLongCollectionMap(final boolean set, String... keys) { + return getLongCollectionMapAsync(set, keys).join(); + } + + //--------------------- getCollectionAndRefresh ------------------------------ + @Override + @Deprecated + public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds) { + return getCollectionAndRefreshAsync(key, expireSeconds, objValueType); + } + + @Override + public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds, final Type componentType) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); + } + + @Override + @Deprecated + public Collection getCollectionAndRefresh(String key, final int expireSeconds) { + return getCollectionAndRefresh(key, expireSeconds, objValueType); + } + + @Override + public Collection getCollectionAndRefresh(String key, final int expireSeconds, final Type componentType) { + return (Collection) getCollectionAndRefreshAsync(key, expireSeconds, componentType).join(); + } + + @Override + public CompletableFuture> getStringCollectionAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); + } + + @Override + public Collection getStringCollectionAndRefresh(String key, final int expireSeconds) { + return getStringCollectionAndRefreshAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture> getLongCollectionAndRefreshAsync(String key, int expireSeconds) { + return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); + } + + @Override + public Collection getLongCollectionAndRefresh(String key, final int expireSeconds) { + return getLongCollectionAndRefreshAsync(key, expireSeconds).join(); + } + + //--------------------- existsItem ------------------------------ + @Override + @Deprecated + public boolean existsSetItem(String key, V value) { + return existsSetItem(key, objValueType, value); + } + + @Override + public boolean existsSetItem(String key, final Type componentType, T value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.contains(convert.convertToBytes(componentType, value)); + } + + @Override + @Deprecated + public CompletableFuture existsSetItemAsync(String key, V value) { + return existsSetItemAsync(key, objValueType, value); + } + + @Override + public CompletableFuture existsSetItemAsync(String key, final Type componentType, T value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.containsAsync(convert.convertToBytes(componentType, value))); + } + + @Override + public boolean existsStringSetItem(String key, String value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return bucket.contains(value); + } + + @Override + public CompletableFuture existsStringSetItemAsync(String key, String value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.containsAsync(value)); + } + + @Override + public boolean existsLongSetItem(String key, long value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return bucket.contains(value); + } + + @Override + public CompletableFuture existsLongSetItemAsync(String key, long value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.containsAsync(value)); + } + + //--------------------- appendListItem ------------------------------ + @Override + @Deprecated + public CompletableFuture appendListItemAsync(String key, V value) { + return appendListItemAsync(key, objValueType, value); + } + + @Override + public CompletableFuture appendListItemAsync(String key, final Type componentType, T value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.addAsync(convert.convertToBytes(componentType, value)).thenApply(r -> null)); + } + + @Override + @Deprecated + public void appendListItem(String key, V value) { + appendListItem(key, objValueType, value); + } + + @Override + public void appendListItem(String key, final Type componentType, T value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.add(convert.convertToBytes(componentType, value)); + } + + @Override + public CompletableFuture appendStringListItemAsync(String key, String value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void appendStringListItem(String key, String value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE); + bucket.add(value); + } + + @Override + public CompletableFuture appendLongListItemAsync(String key, long value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void appendLongListItem(String key, long value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); + bucket.add(value); + } + + //--------------------- removeListItem ------------------------------ + @Override + @Deprecated + public CompletableFuture removeListItemAsync(String key, V value) { + return removeListItemAsync(key, objValueType, value); + } + + @Override + public CompletableFuture removeListItemAsync(String key, final Type componentType, T value) { + return completableFuture(redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).removeAsync(convert.convertToBytes(componentType, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + @Deprecated + public int removeListItem(String key, V value) { + return removeListItem(key, objValueType, value); + } + + @Override + public int removeListItem(String key, final Type componentType, T value) { + final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.remove(convert.convertToBytes(componentType, value)) ? 1 : 0; + } + + @Override + public CompletableFuture removeStringListItemAsync(String key, String value) { + return completableFuture(redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int removeStringListItem(String key, String value) { + return redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).remove(value) ? 1 : 0; + } + + @Override + public CompletableFuture removeLongListItemAsync(String key, long value) { + return completableFuture(redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync((Object) value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int removeLongListItem(String key, long value) { + return redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).remove((Object) value) ? 1 : 0; + } + + //--------------------- appendSetItem ------------------------------ + @Override + @Deprecated + public CompletableFuture appendSetItemAsync(String key, V value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.addAsync(convert.convertToBytes(objValueType, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture appendSetItemAsync(String key, Type componentType, T value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.addAsync(convert.convertToBytes(componentType, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture spopSetItemAsync(String key, Type componentType) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync().thenApply(bs -> bs == null ? null : convert.convertFrom(componentType, bs))); + } + + @Override + public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count).thenApply((Set bslist) -> { + if (bslist == null || bslist.isEmpty()) return new ArrayList<>(); + List rs = new ArrayList<>(); + for (byte[] bs : bslist) { + rs.add(convert.convertFrom(componentType, bs)); + } + return rs; + })); + } + + @Override + public CompletableFuture spopStringSetItemAsync(String key) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync()); + } + + @Override + public CompletableFuture> spopStringSetItemAsync(String key, int count) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count).thenApply(r -> r == null ? null : new ArrayList<>(r))); + } + + @Override + public CompletableFuture spopLongSetItemAsync(String key) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync()); + } + + @Override + public CompletableFuture> spopLongSetItemAsync(String key, int count) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count).thenApply(r -> r == null ? null : new ArrayList<>(r))); + } + + @Override + @Deprecated + public void appendSetItem(String key, V value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.add(convert.convertToBytes(objValueType, value)); + } + + @Override + public void appendSetItem(String key, final Type componentType, T value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.add(convert.convertToBytes(componentType, value)); + } + + @Override + public T spopSetItem(String key, final Type componentType) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + byte[] bs = bucket.removeRandom(); + return bs == null ? null : convert.convertFrom(componentType, bs); + } + + @Override + public List spopSetItem(String key, int count, final Type componentType) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + Set< byte[]> bslist = bucket.removeRandom(count); + List rs = new ArrayList<>(); + if (bslist == null) return rs; + for (byte[] bs : bslist) { + rs.add(convert.convertFrom(componentType, bs)); + } + return rs; + } + + @Override + public String spopStringSetItem(String key) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return bucket.removeRandom(); + } + + @Override + public List spopStringSetItem(String key, int count) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + Set rs = bucket.removeRandom(count); + return rs == null ? null : new ArrayList<>(rs); + } + + @Override + public Long spopLongSetItem(String key) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return bucket.removeRandom(); + } + + @Override + public List spopLongSetItem(String key, int count) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + Set rs = bucket.removeRandom(count); + return rs == null ? null : new ArrayList<>(rs); + } + + @Override + public CompletableFuture appendStringSetItemAsync(String key, String value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void appendStringSetItem(String key, String value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); + bucket.add(value); + } + + @Override + public CompletableFuture appendLongSetItemAsync(String key, long value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void appendLongSetItem(String key, long value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + bucket.add(value); + } + + //--------------------- removeSetItem ------------------------------ + @Override + @Deprecated + public CompletableFuture removeSetItemAsync(String key, V value) { + return removeSetItemAsync(key, objValueType, value); + } + + @Override + public CompletableFuture removeSetItemAsync(String key, final Type componentType, T value) { + return completableFuture(redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).removeAsync(convert.convertToBytes(componentType, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + @Deprecated + public int removeSetItem(String key, V value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.remove(convert.convertToBytes(objValueType, value)) ? 1 : 0; + } + + @Override + public int removeSetItem(String key, final Type componentType, T value) { + final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.remove(convert.convertToBytes(componentType, value)) ? 1 : 0; + } + + @Override + public CompletableFuture removeStringSetItemAsync(String key, String value) { + return completableFuture(redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int removeStringSetItem(String key, String value) { + return redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).remove(value) ? 1 : 0; + } + + @Override + public CompletableFuture removeLongSetItemAsync(String key, long value) { + return completableFuture(redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int removeLongSetItem(String key, long value) { + return redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).remove(value) ? 1 : 0; + } + + //--------------------- queryKeys ------------------------------ + @Override + public List queryKeys() { + return redisson.getKeys().getKeysStream().collect(Collectors.toList()); + } + + @Override + public List queryKeysStartsWith(String startsWith) { + return redisson.getKeys().getKeysStreamByPattern(startsWith + "*").collect(Collectors.toList()); + } + + @Override + public List queryKeysEndsWith(String endsWith) { + return redisson.getKeys().getKeysStreamByPattern("*" + endsWith).collect(Collectors.toList()); + } + + @Override + public byte[] getBytes(final String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return bucket.get(); + } + + @Override + public byte[] getBytesAndRefresh(final String key, final int expireSeconds) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + byte[] bs = bucket.get(); + if (bs == null) return bs; + bucket.expire(expireSeconds, TimeUnit.SECONDS); + return bs; + } + + @Override + public void setBytes(final String key, final byte[] value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set(value); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final byte[] value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set(value); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public void setBytes(final String key, final Convert convert0, final Type type, final T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final Convert convert0, final Type type, final T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); + bucket.expire(expireSeconds, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAsync()); + } + + @Override + public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAsync().thenCompose(bs -> bs == null ? CompletableFuture.completedFuture(null) : bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> bs))); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final byte[] value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(value)); + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(value).thenCompose(r -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> null))); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final Convert convert0, final Type type, final T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenApply(v -> null)); + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert0, final Type type, final T value) { + final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenCompose(r -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> null))); + } + + @Override + public CompletableFuture> queryKeysAsync() { + return CompletableFuture.supplyAsync(() -> queryKeys()); + } + + @Override + public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { + if (startsWith == null) return CompletableFuture.supplyAsync(() -> queryKeys()); + return CompletableFuture.supplyAsync(() -> queryKeysStartsWith(startsWith)); + } + + @Override + public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { + if (endsWith == null) return CompletableFuture.supplyAsync(() -> queryKeys()); + return CompletableFuture.supplyAsync(() -> queryKeysEndsWith(endsWith)); + } + + //--------------------- getKeySize ------------------------------ + @Override + public int getKeySize() { + return (int) redisson.getKeys().count(); + } + + @Override + public CompletableFuture getKeySizeAsync() { + return completableFuture(redisson.getKeys().countAsync().thenApply(r -> r.intValue())); + } + + //--------------------- queryList ------------------------------ + @Override + public List> queryList() { + return queryListAsync().join(); + } + + @Override + public CompletableFuture>> queryListAsync() { + return CompletableFuture.completedFuture(new ArrayList<>()); //不返回数据 + } + + protected static class MapByteArrayCodec extends org.redisson.client.codec.ByteArrayCodec { + + public static final MapByteArrayCodec instance = new MapByteArrayCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); + } + } + + protected static class MapStringCodec extends org.redisson.client.codec.StringCodec { + + public static final MapStringCodec instance = new MapStringCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); + } + } + + protected static class MapLongCodec extends org.redisson.client.codec.LongCodec { + + public static final MapLongCodec instance = new MapLongCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); + } + } +} +*/