@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);
    }
  }
Exemple #18
0
 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);
 }