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

orestes.bloomfilter.redis.helper.RedisPool Maven / Gradle / Ivy

Go to download

Library of different Bloom filters in Java with optional Redis-backing, counting and many hashing options.

The newest version!
package orestes.bloomfilter.redis.helper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.util.Pool;

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Encapsulates a Connection Pool and offers convenience methods for safe access through Java 8 Lambdas.
 */
public class RedisPool {
    private static final Logger LOG = LoggerFactory.getLogger(RedisPool.class);

    private final Pool pool;
    private final List slavePools;
    private final Random random;
    private final String host;
    private final int port;

    /**
     * Creates a builder for a standalone RedisPool
     * @return A builder for a standalone redisPool
     */
    public static final RedisStandalonePoolBuilder builder() {
        return new RedisStandalonePoolBuilder();
    }

    /**
     * Creates a builder for a sentinel RedisPool
     * @return A builder for a sentinel redisPool
     */
    public static final RedisSentinelPoolBuilder sentinelBuilder() {
        return new RedisSentinelPoolBuilder();
    }

    protected RedisPool(Pool pool, List slavePools, String host, int port) {
        this.pool = pool;
        this.host = host;
        this.port = port;

        if (slavePools != null && !slavePools.isEmpty()) {
            this.slavePools = slavePools;
            this.random = new Random();
        } else {
            this.slavePools = slavePools;
            this.random = null;
        }
    }

    public Pool getInternalPool() {
        return pool;
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public RedisPool allowingSlaves() {
        if (slavePools == null) {
            return this;
        }
        int index = random.nextInt(slavePools.size());
        return slavePools.get(index);
    }

    public Jedis getResource() {
        return pool.getResource();
    }

    public void safelyDo(Consumer f) {
        safelyReturn(jedis -> {
            f.accept(jedis);
            return null;
        });
    }

    public  T safelyReturn(Function f) {
        try (Jedis jedis = pool.getResource()) {
            return f.apply(jedis);
        }
    }

    public  void safeForEach(Collection collection, BiConsumer f) {
        safelyReturn(jedis -> {
            Pipeline p = jedis.pipelined();
            collection.stream().forEach(e -> f.accept(p, e));
            p.sync();
            return null;
        });
    }

    @SuppressWarnings("unchecked")
    public  List transactionallyDo(Consumer f, String... watch) {
        return (List) safelyReturn(jedis -> {
            Pipeline p = jedis.pipelined();
            if (watch.length != 0) {
                p.watch(watch);
            }
            p.multi();
            f.accept(p);
            Response> exec = p.exec();
            p.sync();
            return exec.get();
        });
    }

    @SuppressWarnings("unchecked")
    public  List transactionallyRetry(Consumer f, String... watch) {
        while (true) {
            List result = transactionallyDo(f, watch);
            if (result != null) {
                return result;
            }
        }
    }


    public Clock getClock() {
        List time = this.safelyReturn(Jedis::time);
        Instant local = Instant.now();
        //Format: [0]: unix ts [1]: microseconds
        Instant redis = Instant.ofEpochSecond(Long.valueOf(time.get(0)), Long.valueOf(time.get(1)) * 1000);
        return Clock.offset(Clock.systemDefaultZone(), Duration.between(local, redis));
    }


    /**
     * Start an automatically reconnecting Thread with a dedicated connection to Redis (e.g. for PubSub or blocking
     * pops)
     *
     * @param redisHost     host
     * @param redisPort     port
     * @param whenConnected executed when the connections is active
     * @param abort         lambda that allows to abort processing when an error occurs
     * @return the started thread
     */
    public static Thread startThread(String redisHost, int redisPort, Consumer whenConnected, Function abort) {
        Thread thread = new Thread(() -> {
            boolean connected = false;
            while (!connected && !Thread.currentThread().isInterrupted()) {
                try (Jedis jedis = new Jedis(redisHost, redisPort)) {
                    //pubsub has its own Redis connection
                    jedis.ping();
                    connected = true;
                    LOG.info("PubSub Redis connection established.");
                    whenConnected.accept(jedis);
                } catch (Exception e) {
                    connected = false;
                    if (abort.apply(e)) {
                        LOG.info("PubSub Redis connection aborted.", e);
                        break;
                    } else {
                        LOG.warn("PubSub Redis connection failed with an exception:", e);
                        //Rate Limit to 4 reconnects per second
                        try {
                            Thread.sleep(250);
                        } catch (InterruptedException e1) {
                            LOG.warn("PubSub Redis connection Interrupted", e1);
                        }
                    }
                }
            }
            LOG.info("PubSub Redis connection closed.");
        });
        thread.start();
        return thread;
    }

    public Thread startThread(Consumer whenConnected) {
        return startThread(whenConnected, (ex) -> false);
    }

    public Thread startThread(Consumer whenConnected, Function abort) {
        return startThread(host, port, whenConnected, abort);
    }

    public void destroy() {
        pool.destroy();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy