@Override public void shutdown() { monitorFuture.cancel(true); super.shutdown(); for (RedisConnection connection : nodeConnections.values()) { connection.getRedisClient().shutdown(); } }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { RedisConnection connection = RedisConnection.getFrom(ctx.channel()); if (!connection.isClosed()) { EventLoopGroup group = ctx.channel().eventLoop().parent(); reconnect(group, connection); } ctx.fireChannelInactive(); }
public void returnConnection(RedisConnection connection) { SubscribesConnectionEntry entry = clients.get(connection.getRedisClient()); if (entry.isFreezed()) { connection.closeAsync(); } else { entry.getConnections().add(connection); } entry.getConnectionsSemaphore().release(); }
@Override public Map<String, String> info() { RedisConnection c = connect(); try { return c.sync(RedisCommands.CLUSTER_INFO); } catch (Exception e) { return null; } finally { c.closeAsync(); } }
@Test public void testBigRequest() throws InterruptedException, ExecutionException { RedisClient c = new RedisClient("localhost", 6379); RedisConnection conn = c.connect(); for (int i = 0; i < 50; i++) { conn.sync(StringCodec.INSTANCE, RedisCommands.HSET, "testmap", i, "2"); } Map<Object, Object> res = conn.sync(StringCodec.INSTANCE, RedisCommands.HGETALL, "testmap"); assertThat(res.size()).isEqualTo(50); conn.sync(RedisCommands.FLUSHDB); }
@Test public void testConnectAsync() throws InterruptedException { RedisClient c = new RedisClient("localhost", 6379); Future<RedisConnection> f = c.connectAsync(); final CountDownLatch l = new CountDownLatch(1); f.addListener( (FutureListener<RedisConnection>) future -> { RedisConnection conn = future.get(); assertThat(conn.sync(RedisCommands.PING)).isEqualTo("PONG"); l.countDown(); }); l.await(10, TimeUnit.SECONDS); }
@Override public boolean ping() { RedisConnection c = null; try { c = connect(); return "PONG".equals(c.sync(RedisCommands.PING)); } catch (Exception e) { return false; } finally { if (c != null) { c.closeAsync(); } } }
@Test public void testPipeline() throws InterruptedException, ExecutionException { RedisClient c = new RedisClient("localhost", 6379); RedisConnection conn = c.connect(); conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0); List<CommandData<?, ?>> commands = new ArrayList<CommandData<?, ?>>(); CommandData<String, String> cmd1 = conn.create(null, RedisCommands.PING); commands.add(cmd1); CommandData<Long, Long> cmd2 = conn.create(null, RedisCommands.INCR, "test"); commands.add(cmd2); CommandData<Long, Long> cmd3 = conn.create(null, RedisCommands.INCR, "test"); commands.add(cmd3); CommandData<String, String> cmd4 = conn.create(null, RedisCommands.PING); commands.add(cmd4); Promise<Void> p = c.getBootstrap().group().next().newPromise(); conn.send(new CommandsData(p, commands)); assertThat(cmd1.getPromise().get()).isEqualTo("PONG"); assertThat(cmd2.getPromise().get()).isEqualTo(1); assertThat(cmd3.getPromise().get()).isEqualTo(2); assertThat(cmd4.getPromise().get()).isEqualTo("PONG"); conn.sync(RedisCommands.FLUSHDB); }
private void tryReconnect( final EventLoopGroup group, final RedisConnection connection, final int attempts) { if (connection.isClosed() || group.isShuttingDown()) { return; } log.debug( "reconnecting {} to {} ", connection, connection.getRedisClient().getAddr(), connection); bootstrap .connect() .addListener( new ChannelFutureListener() { @Override public void operationComplete(final ChannelFuture future) throws Exception { if (connection.isClosed() || group.isShuttingDown()) { return; } try { if (future.isSuccess()) { log.debug( "{} connected to {}", connection, connection.getRedisClient().getAddr()); reconnect(connection, future.channel()); return; } } catch (RedisException e) { log.warn( "Can't connect " + connection + " to " + connection.getRedisClient().getAddr(), e); } int timeout = 2 << attempts; group.schedule( new Runnable() { @Override public void run() { tryReconnect(group, connection, Math.min(BACKOFF_CAP, attempts + 1)); } }, timeout, TimeUnit.MILLISECONDS); } }); }
private void updateClusterState( final ClusterServersConfig cfg, final RedisConnection connection) { Future<String> future = connection.async(RedisCommands.CLUSTER_NODES); future.addListener( new FutureListener<String>() { @Override public void operationComplete(Future<String> future) throws Exception { if (!future.isSuccess()) { log.error( "Can't execute CLUSTER_NODES with " + connection.getRedisClient().getAddr(), future.cause()); scheduleClusterChangeCheck(cfg); return; } String nodesValue = future.getNow(); log.debug( "cluster nodes state from {}:\n{}", connection.getRedisClient().getAddr(), nodesValue); Collection<ClusterPartition> newPartitions = parsePartitions(nodesValue); checkMasterNodesChange(newPartitions); checkSlaveNodesChange(newPartitions); checkSlotsChange(cfg, newPartitions); scheduleClusterChangeCheck(cfg); } }); }
public synchronized Collection<RedisPubSubConnection> freeze(String host, int port) { InetSocketAddress addr = new InetSocketAddress(host, port); for (SubscribesConnectionEntry connectionEntry : clients.values()) { if (connectionEntry.isFreezed() || !connectionEntry.getClient().getAddr().equals(addr)) { continue; } log.debug("{} freezed", addr); connectionEntry.setFreezed(true); // close all connections while (true) { RedisConnection connection = connectionEntry.getConnections().poll(); if (connection == null) { break; } connection.closeAsync(); } // close all pub/sub connections while (true) { RedisPubSubConnection connection = connectionEntry.pollFreeSubscribeConnection(); if (connection == null) { break; } connection.closeAsync(); } boolean allFreezed = true; for (SubscribesConnectionEntry entry : clients.values()) { if (!entry.isFreezed()) { allFreezed = false; break; } } if (allFreezed) { clientsEmpty.close(); } List<RedisPubSubConnection> list = new ArrayList<RedisPubSubConnection>(connectionEntry.getAllSubscribeConnections()); connectionEntry.getAllSubscribeConnections().clear(); return list; } return Collections.emptyList(); }
@Test public void testPipelineBigResponse() throws InterruptedException, ExecutionException { RedisClient c = new RedisClient("localhost", 6379); RedisConnection conn = c.connect(); List<CommandData<?, ?>> commands = new ArrayList<CommandData<?, ?>>(); for (int i = 0; i < 1000; i++) { CommandData<String, String> cmd1 = conn.create(null, RedisCommands.PING); commands.add(cmd1); } Promise<Void> p = c.getBootstrap().group().next().newPromise(); conn.send(new CommandsData(p, commands)); for (CommandData<?, ?> commandData : commands) { commandData.getPromise().get(); } conn.sync(RedisCommands.FLUSHDB); }
public ClusterConnectionManager(ClusterServersConfig cfg, Config config) { super(config); connectListener = new ClusterConnectionListener(cfg.getReadMode() == ReadMode.SLAVE); this.config = create(cfg); init(this.config); Exception lastException = null; for (URI addr : cfg.getNodeAddresses()) { Future<RedisConnection> connectionFuture = connect(cfg, addr); try { RedisConnection connection = connectionFuture.syncUninterruptibly().getNow(); String nodesValue = connection.sync(RedisCommands.CLUSTER_NODES); Collection<ClusterPartition> partitions = parsePartitions(nodesValue); List<Future<Collection<Future<Void>>>> futures = new ArrayList<Future<Collection<Future<Void>>>>(); for (ClusterPartition partition : partitions) { Future<Collection<Future<Void>>> masterFuture = addMasterEntry(partition, cfg); futures.add(masterFuture); } for (Future<Collection<Future<Void>>> masterFuture : futures) { masterFuture.syncUninterruptibly(); for (Future<Void> future : masterFuture.getNow()) { future.syncUninterruptibly(); } } break; } catch (Exception e) { lastException = e; log.warn(e.getMessage()); } } if (lastPartitions.isEmpty()) { throw new RedisConnectionException("Can't connect to servers!", lastException); } scheduleClusterChangeCheck(cfg); }
private void reconnect(final RedisConnection connection, final Channel channel) { if (connection.getReconnectListener() != null) { // new connection used only for channel init RedisConnection rc = new RedisConnection(connection.getRedisClient(), channel); Promise<RedisConnection> connectionFuture = bootstrap.group().next().newPromise(); connection.getReconnectListener().onReconnect(rc, connectionFuture); connectionFuture.addListener( new FutureListener<RedisConnection>() { @Override public void operationComplete(Future<RedisConnection> future) throws Exception { if (future.isSuccess()) { connection.updateChannel(channel); resubscribe(connection); } } }); } else { connection.updateChannel(channel); resubscribe(connection); } }
@Test public void test() throws InterruptedException { RedisClient c = new RedisClient("localhost", 6379); final RedisConnection conn = c.connect(); conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0); ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); for (int i = 0; i < 100000; i++) { pool.execute( () -> { conn.async(StringCodec.INSTANCE, RedisCommands.INCR, "test"); }); } pool.shutdown(); assertThat(pool.awaitTermination(1, TimeUnit.HOURS)).isTrue(); assertThat((Long) conn.sync(LongCodec.INSTANCE, RedisCommands.GET, "test")).isEqualTo(100000); conn.sync(RedisCommands.FLUSHDB); }
private void checkComparator(RedisConnection connection) { String comparatorSign = connection.sync(StringCodec.INSTANCE, RedisCommands.GET, getComparatorKeyName()); if (comparatorSign != null) { String[] vals = comparatorSign.split(":"); String className = vals[0]; if (!comparator.getClass().getName().equals(className)) { // try { loadComparator(connection); // } finally { // connection.sync(RedisCommands.UNWATCH); // } } } }
private void loadComparator(RedisConnection connection) { try { String comparatorSign = connection.sync(StringCodec.INSTANCE, RedisCommands.GET, getComparatorKeyName()); if (comparatorSign != null) { String[] parts = comparatorSign.split(":"); String className = parts[0]; String sign = parts[1]; String result = calcClassSign(className); if (!result.equals(sign)) { throw new IllegalStateException( "Local class signature of " + className + " differs from used by this SortedSet!"); } Class<?> clazz = Class.forName(className); comparator = (Comparator<V>) clazz.newInstance(); } } catch (Exception e) { throw new IllegalStateException(e); } }
public void returnConnection(RedisConnection connection) { ClientConnectionsEntry entry = addr2Entry.get(connection.getRedisClient().getAddr()); entries.returnConnection(entry, connection); }
private V getAtIndex(Codec codec, int index, RedisConnection connection) { return connection.sync(codec, RedisCommands.LINDEX, getName(), index); }
boolean add(V value, Codec codec, RedisConnection connection) { while (true) { connection.sync(RedisCommands.WATCH, getName(), getComparatorKeyName()); checkComparator(connection); Long version = getCurrentVersion(codec, connection); BinarySearchResult<V> res = binarySearch(value, codec, connection); if (res.getIndex() < 0) { // System.out.println("index: " + res.getIndex() + " value: " + value); if (!version.equals(getCurrentVersion(codec, connection))) { connection.sync(RedisCommands.UNWATCH); continue; } // NewScore newScore = calcNewScore(res.getIndex(), connection); // if (!version.equals(getCurrentVersion(simpleConnection))) { // connection.unwatch(); // continue; // } // // String leftScoreKey = getScoreKeyName(newScore.getLeftScore()); // String rightScoreKey = getScoreKeyName(newScore.getRightScore()); // // if (simpleConnection.setnx(leftScoreKey, 1)) { // if (!version.equals(getCurrentVersion(simpleConnection))) { // connection.unwatch(); // // connection.del(leftScoreKey); // continue; // } // if (rightScoreKey != null) { // // if (!simpleConnection.setnx(rightScoreKey, 1)) { // connection.unwatch(); // // connection.del(leftScoreKey); // continue; // } // } // } else { // connection.unwatch(); // continue; // } V pivot = null; boolean before = false; int index = -(res.getIndex() + 1); if (index < size()) { before = true; pivot = connection.sync(codec, RedisCommands.LINDEX, getName(), index); } connection.sync(RedisCommands.MULTI); if (index >= size()) { connection.sync(codec, RedisCommands.RPUSH, getName(), value); } else { connection.sync( codec, RedisCommands.LINSERT, getName(), before ? "BEFORE" : "AFTER", pivot, value); } // System.out.println("adding: " + newScore.getScore() + " " + value); // connection.zadd(getName(), newScore.getScore(), value); // if (rightScoreKey != null) { // connection.del(leftScoreKey, rightScoreKey); // } else { // connection.del(leftScoreKey); // } connection.sync(RedisCommands.INCR, getCurrentVersionKey()); List<Object> re = connection.sync(codec, RedisCommands.EXEC); if (re.size() == 2) { // System.out.println("index: " + index + " value: " + value + " pivot: // " + pivot); return true; // Number val = (Number) re.get(0); // Long delCount = (Long) re.get(1); // if (rightScoreKey != null) { // if (delCount != 2) { // throw new IllegalStateException(); // } // } else { // if (delCount != 1) { // throw new IllegalStateException(); // } // } // return val != null && val.intValue() > 0; } } else { connection.sync(RedisCommands.UNWATCH); return false; } } }
private Long getCurrentVersion(Codec codec, RedisConnection simpleConnection) { return simpleConnection.sync(LongCodec.INSTANCE, RedisCommands.GET, getCurrentVersionKey()); }
private int size(RedisConnection connection) { return connection.sync(RedisCommands.LLEN_INT, getName()).intValue(); }
boolean remove(Object value, Codec codec, RedisConnection conn) { while (true) { conn.sync(RedisCommands.WATCH, getName()); BinarySearchResult<V> res = binarySearch((V) value, codec, conn); if (res.getIndex() < 0) { conn.sync(RedisCommands.UNWATCH); return false; } if (res.getIndex() == 0) { conn.sync(RedisCommands.MULTI); conn.sync(codec, RedisCommands.LPOP, getName()); if (((List<Object>) conn.sync(codec, RedisCommands.EXEC)).size() == 1) { return true; } } List<Object> tail = conn.sync(codec, RedisCommands.LRANGE, getName(), res.getIndex() + 1, size()); conn.sync(RedisCommands.MULTI); conn.sync(RedisCommands.LTRIM, getName(), 0, res.getIndex() - 1); if (tail.isEmpty()) { if (((List<Object>) conn.sync(codec, RedisCommands.EXEC)).size() == 1) { return true; } } else { tail.add(0, getName()); conn.sync(codec, RedisCommands.RPUSH, tail.toArray()); if (((List<Object>) conn.sync(codec, RedisCommands.EXEC)).size() == 2) { return true; } } } }
private void ping(RedisConnection c, final FutureListener<String> pingListener) { Future<String> f = c.async(RedisCommands.PING); f.addListener(pingListener); }