All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.redkalex.cache.RedisCacheSource Maven / Gradle / Ivy

There is a newer version: 2.7.7
Show newest version
/*
 * 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.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import javax.annotation.Resource;
import org.redkale.convert.Convert;
import org.redkale.convert.bson.BsonByteBufferWriter;
import org.redkale.convert.json.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;

/**
 * 详情见: https://redkale.org
 *
 * @param  Value
 *
 * @author zhangjx
 */
@Local
@AutoLoad(false)
@ResourceType(CacheSource.class)
public final 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(null);
            if (new String((byte[]) t).contains("list")) { //list
                return send("LLEN", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8));
            } else {
                return send("SCARD", null, (Type) null, 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);
            if (new String((byte[]) t).contains("list")) { //list
                return send("LRANGE", CacheEntryType.OBJECT, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'});
            } 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) return String.valueOf(value).getBytes(StandardCharsets.UTF_8);
        if (cacheType == CacheEntryType.STRING) return String.valueOf(value).getBytes(StandardCharsets.UTF_8);
        return convert0.convertToBytes(resultType == null ? objValueType : resultType, value);
    }

    private 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);
    }

    private 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 {
                                                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)) ? (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(cacheType == CacheEntryType.BYTES ? rs : (("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);
                                            future.complete(cacheType == CacheEntryType.BYTES ? rs : ("SPOP".equals(command) || command.endsWith("GET") ? (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));
                                                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) {
                                                        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) {
                                    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 {

    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
            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);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy