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

org.rx.redis.RedisCache Maven / Gradle / Ivy

package org.rx.redis;

import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.codec.SerializationCodec;
import org.redisson.config.Config;
import org.rx.bean.BiTuple;
import org.rx.codec.CodecUtil;
import org.rx.core.Cache;
import org.rx.core.CachePolicy;
import org.rx.core.RxConfig;
import org.rx.core.Tasks;
import org.rx.util.function.BiFunc;

import java.util.AbstractMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static org.rx.core.Extends.quietly;

@Slf4j
public class RedisCache implements Cache {
    public static RedissonClient create(String redisUrl) {
        return create(redisUrl, false);
    }

    public static RedissonClient create(@NonNull String redisUrl, boolean jdkCodec) {
        BiTuple resolve = resolve(redisUrl);
        log.info("RedissonClient {} -> {}", redisUrl, resolve);
        Config config = new Config();
        config.setExecutor(Tasks.executor());
        if (jdkCodec) {
            config.setCodec(new SerializationCodec());
        }
        int minPoolSize = 2;
        int maxPoolSize = Math.max(minPoolSize, RxConfig.INSTANCE.getNet().getPoolMaxSize());
        config.useSingleServer().setKeepAlive(true).setTcpNoDelay(true)
                .setConnectionMinimumIdleSize(minPoolSize).setConnectionPoolSize(maxPoolSize)
                .setSubscriptionConnectionMinimumIdleSize(minPoolSize).setSubscriptionConnectionPoolSize(maxPoolSize)
                .setAddress(String.format("redis://%s", resolve.left)).setDatabase(resolve.middle).setPassword(resolve.right);
        return Redisson.create(config);
    }

    private static BiTuple resolve(String redisUrl) {
        String pwd = null;
        int database = 0, i;
        if ((i = redisUrl.lastIndexOf("/")) != -1) {
            database = Integer.parseInt(redisUrl.substring(i + 1));
            redisUrl = redisUrl.substring(0, i);
        }
        if ((i = redisUrl.lastIndexOf("@")) != -1) {
            pwd = redisUrl.substring(0, i);
            redisUrl = redisUrl.substring(i + 1);
        }
        return BiTuple.of(redisUrl, database, pwd);
    }

    static final String BASE64_KEY_PREFIX = "B:";
    @Getter
    final RedissonClient client;
    @Getter
    @Setter
    int entrySetLimit = 1000;

    @Override
    public int size() {
        int is = (int) client.getKeys().count();
        if (is < 0) {
            is = Integer.MAX_VALUE;
        }
        return is;
    }

    public RedisCache(String redisUrl) {
        this(create(redisUrl));
    }

    public RedisCache(@NonNull RedissonClient redissonClient) {
        client = redissonClient;
    }

    @Override
    public Set> entrySet() {
        Set> entrySet = new HashSet<>();
        for (String rKey : client.getKeys().getKeysWithLimit(entrySetLimit)) {
            TV val = quietly(() -> client.getBucket(rKey).get());
            if (val == null) {
                continue;
            }
            entrySet.add(new AbstractMap.SimpleEntry<>(transferKey(rKey), val));
        }
        return entrySet;
    }

    protected String transferKey(@NonNull TK k) {
        if (k instanceof String) {
            return k.toString();
        }
        return BASE64_KEY_PREFIX + CodecUtil.serializeToBase64(k);
    }

    protected TK transferKey(@NonNull String k) {
        if (k.startsWith(BASE64_KEY_PREFIX)) {
            return CodecUtil.deserializeFromBase64(k.substring(BASE64_KEY_PREFIX.length()));
        }
        return (TK) k;
    }

    @Override
    public TV put(TK k, @NonNull TV v, CachePolicy policy) {
        long expireMillis = policy != null ? policy.ttl() : -1;
        RBucket bucket = client.getBucket(transferKey(k));
        return expireMillis < 1 ? bucket.getAndSet(v) : bucket.getAndSet(v, expireMillis, TimeUnit.MILLISECONDS);
    }

    @Override
    public TV remove(Object k) {
        return client.getBucket(transferKey((TK) k)).getAndDelete();
    }

    @Override
    public void clear() {
        client.getKeys().flushdb();
    }

    @Override
    public TV get(Object k) {
        return client.getBucket(transferKey((TK) k)).get();
    }

    @Override
    public TV get(TK k, @NonNull BiFunc loadingFunc, CachePolicy policy) {
        RBucket bucket = client.getBucket(transferKey(k));
        TV v = bucket.get();
        if (v != null) {
            if (policy != null && policy.slidingRenew()) {
                long expireMillis = policy.ttl(false);
                if (expireMillis > 0) {
                    bucket.expireAsync(expireMillis, TimeUnit.MILLISECONDS);
                }
            }
            return v;
        }
        put(k, v = loadingFunc.apply(k), policy);
        return v;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy