Пример #1
0
 private RedisConnection connect() {
   RedisConnection c = client.connect();
   Promise<RedisConnection> future = manager.newPromise();
   manager.getConnectListener().onConnect(future, c, null, manager.getConfig());
   future.syncUninterruptibly();
   return future.getNow();
 }
Пример #2
0
 public Future<Void> add(final ClientConnectionsEntry entry) {
   final Promise<Void> promise = connectionManager.newPromise();
   promise.addListener(
       new FutureListener<Void>() {
         @Override
         public void operationComplete(Future<Void> future) throws Exception {
           entries.add(entry);
         }
       });
   initConnections(entry, promise, true);
   return promise;
 }
Пример #3
0
 /**
  * Works around some Android {@link SSLEngine} implementations that skip {@link
  * HandshakeStatus#FINISHED} and go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when
  * handshake is finished.
  *
  * @return {@code true} if and only if the workaround has been applied and thus {@link
  *     #handshakeFuture} has been marked as success by this method
  */
 private boolean setHandshakeSuccessIfStillHandshaking() {
   if (!handshakePromise.isDone()) {
     setHandshakeSuccess();
     return true;
   }
   return false;
 }
Пример #4
0
  private void promiseFailure(ClientConnectionsEntry entry, Promise<T> promise, Throwable cause) {
    if (entry.incFailedAttempts() == config.getFailedAttempts()) {
      checkForReconnect(entry);
    }

    promise.tryFailure(cause);
  }
Пример #5
0
 private void promiseSuccessful(ClientConnectionsEntry entry, Promise<T> promise, T conn) {
   entry.resetFailedAttempts();
   if (!promise.trySuccess(conn)) {
     releaseConnection(entry, conn);
     releaseConnection(entry);
   }
 }
Пример #6
0
  @Override
  public void read(ChannelHandlerContext ctx) throws Exception {
    if (!handshakePromise.isDone()) {
      readDuringHandshake = true;
    }

    ctx.read();
  }
  @Override
  public <T> Future<T> invoke(
      EventLoop eventLoop,
      URI uri,
      ClientOptions options,
      ClientCodec codec,
      Method method,
      Object[] args)
      throws Exception {

    final CircuitBreaker circuitBreaker;
    try {
      circuitBreaker = mapping.get(eventLoop, uri, options, codec, method, args);
    } catch (Throwable t) {
      logger.warn("Failed to get a circuit breaker from mapping", t);
      return delegate().invoke(eventLoop, uri, options, codec, method, args);
    }

    if (circuitBreaker.canRequest()) {
      final Future<T> resultFut = delegate().invoke(eventLoop, uri, options, codec, method, args);
      resultFut.addListener(
          future -> {
            if (future.isSuccess()) {
              // reports success event
              circuitBreaker.onSuccess();
            } else {
              circuitBreaker.onFailure(future.cause());
            }
          });
      return resultFut;
    } else {
      // the circuit is tripped

      // prepares a failed resultPromise
      final Promise<T> resultPromise = eventLoop.newPromise();
      resultPromise.setFailure(new FailFastException(circuitBreaker));
      codec.prepareRequest(method, args, resultPromise);

      // returns immediately without calling succeeding remote invokers
      return resultPromise;
    }
  }
Пример #8
0
 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);
   }
 }
Пример #9
0
  private void promiseFailure(ClientConnectionsEntry entry, Promise<T> promise, T conn) {
    int attempts = entry.incFailedAttempts();
    if (attempts == config.getFailedAttempts()) {
      checkForReconnect(entry);
    } else if (attempts < config.getFailedAttempts()) {
      releaseConnection(entry, conn);
    }

    releaseConnection(entry);

    RedisConnectionException cause = new RedisConnectionException(conn + " is not active!");
    promise.tryFailure(cause);
  }
Пример #10
0
  private void initConnections(
      final ClientConnectionsEntry entry, final Promise<Void> initPromise, boolean checkFreezed) {
    final int minimumIdleSize = getMinimumIdleSize(entry);

    if (minimumIdleSize == 0 || (checkFreezed && entry.isFreezed())) {
      initPromise.setSuccess(null);
      return;
    }

    final AtomicInteger initializedConnections = new AtomicInteger(minimumIdleSize);
    int startAmount = Math.min(50, minimumIdleSize);
    final AtomicInteger requests = new AtomicInteger(startAmount);
    for (int i = 0; i < startAmount; i++) {
      createConnection(
          checkFreezed, requests, entry, initPromise, minimumIdleSize, initializedConnections);
    }
  }
Пример #11
0
  /** Notify all the handshake futures about the successfully handshake */
  private void setHandshakeSuccess() {
    // Work around the JVM crash which occurs when a cipher suite with GCM enabled.
    final String cipherSuite = String.valueOf(engine.getSession().getCipherSuite());
    if (!wantsDirectBuffer && (cipherSuite.contains("_GCM_") || cipherSuite.contains("-GCM-"))) {
      wantsInboundHeapBuffer = true;
    }

    handshakePromise.trySuccess(ctx.channel());

    if (logger.isDebugEnabled()) {
      logger.debug("{} HANDSHAKEN: {}", ctx.channel(), engine.getSession().getCipherSuite());
    }
    ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);

    if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
      readDuringHandshake = false;
      ctx.read();
    }
  }
Пример #12
0
  @Override
  public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    // Discard bytes of the cumulation buffer if needed.
    discardSomeReadBytes();

    if (needsFlush) {
      needsFlush = false;
      ctx.flush();
    }

    // If handshake is not finished yet, we need more data.
    if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
      // No auto-read used and no message passed through the ChannelPipeline or the handhshake was
      // not complete
      // yet, which means we need to trigger the read to ensure we not encounter any stalls.
      ctx.read();
    }

    firedChannelRead = false;
    ctx.fireChannelReadComplete();
  }
Пример #13
0
 @Override
 public void flush(ChannelHandlerContext ctx) throws Exception {
   // Do not encrypt the first write request if this handler is
   // created with startTLS flag turned on.
   if (startTls && !sentFirstMessage) {
     sentFirstMessage = true;
     pendingUnencryptedWrites.removeAndWriteAll();
     ctx.flush();
     return;
   }
   if (pendingUnencryptedWrites.isEmpty()) {
     // It's important to NOT use a voidPromise here as the user
     // may want to add a ChannelFutureListener to the ChannelPromise later.
     //
     // See https://github.com/netty/netty/issues/3364
     pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
   }
   if (!handshakePromise.isDone()) {
     flushedBeforeHandshake = true;
   }
   wrap(ctx, false);
   ctx.flush();
 }
Пример #14
0
  /**
   * Performs TLS (re)negotiation.
   *
   * @param newHandshakePromise if {@code null}, use the existing {@link #handshakePromise},
   *     assuming that the current negotiation has not been finished. Currently, {@code null} is
   *     expected only for the initial handshake.
   */
  private void handshake(final Promise<Channel> newHandshakePromise) {
    final Promise<Channel> p;
    if (newHandshakePromise != null) {
      final Promise<Channel> oldHandshakePromise = handshakePromise;
      if (!oldHandshakePromise.isDone()) {
        // There's no need to handshake because handshake is in progress already.
        // Merge the new promise into the old one.
        oldHandshakePromise.addListener(
            new FutureListener<Channel>() {
              @Override
              public void operationComplete(Future<Channel> future) throws Exception {
                if (future.isSuccess()) {
                  newHandshakePromise.setSuccess(future.getNow());
                } else {
                  newHandshakePromise.setFailure(future.cause());
                }
              }
            });
        return;
      }

      handshakePromise = p = newHandshakePromise;
    } else {
      // Forced to reuse the old handshake.
      p = handshakePromise;
      assert !p.isDone();
    }

    // Begin handshake.
    final ChannelHandlerContext ctx = this.ctx;
    try {
      engine.beginHandshake();
      wrapNonAppData(ctx, false);
      ctx.flush();
    } catch (Exception e) {
      notifyHandshakeFailure(e);
    }

    // Set timeout if necessary.
    final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
    if (handshakeTimeoutMillis <= 0 || p.isDone()) {
      return;
    }

    final ScheduledFuture<?> timeoutFuture =
        ctx.executor()
            .schedule(
                new Runnable() {
                  @Override
                  public void run() {
                    if (p.isDone()) {
                      return;
                    }
                    notifyHandshakeFailure(HANDSHAKE_TIMED_OUT);
                  }
                },
                handshakeTimeoutMillis,
                TimeUnit.MILLISECONDS);

    // Cancel the handshake timeout when handshake is finished.
    p.addListener(
        new FutureListener<Channel>() {
          @Override
          public void operationComplete(Future<Channel> f) throws Exception {
            timeoutFuture.cancel(false);
          }
        });
  }
Пример #15
0
 private void notifyHandshakeFailure(Throwable cause) {
   if (handshakePromise.tryFailure(cause)) {
     ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
     ctx.close();
   }
 }
Пример #16
0
  private void createConnection(
      final boolean checkFreezed,
      final AtomicInteger requests,
      final ClientConnectionsEntry entry,
      final Promise<Void> initPromise,
      final int minimumIdleSize,
      final AtomicInteger initializedConnections) {

    if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) {
      Throwable cause =
          new RedisConnectionException(
              "Can't init enough connections amount! Only "
                  + (minimumIdleSize - initializedConnections.get())
                  + " from "
                  + minimumIdleSize
                  + " were initialized. Server: "
                  + entry.getClient().getAddr());
      initPromise.tryFailure(cause);
      return;
    }

    Future<T> promise = createConnection(entry);
    promise.addListener(
        new FutureListener<T>() {
          @Override
          public void operationComplete(Future<T> future) throws Exception {
            if (future.isSuccess()) {
              T conn = future.getNow();
              releaseConnection(entry, conn);
            }

            releaseConnection(entry);

            if (!future.isSuccess()) {
              Throwable cause =
                  new RedisConnectionException(
                      "Can't init enough connections amount! Only "
                          + (minimumIdleSize - initializedConnections.get())
                          + " from "
                          + minimumIdleSize
                          + " were initialized. Server: "
                          + entry.getClient().getAddr(),
                      future.cause());
              initPromise.tryFailure(cause);
              return;
            }

            int value = initializedConnections.decrementAndGet();
            if (value == 0) {
              log.info(
                  "{} connections initialized for {}",
                  minimumIdleSize,
                  entry.getClient().getAddr());
              initPromise.setSuccess(null);
            } else if (value > 0 && !initPromise.isDone()) {
              if (requests.incrementAndGet() <= minimumIdleSize) {
                createConnection(
                    checkFreezed,
                    requests,
                    entry,
                    initPromise,
                    minimumIdleSize,
                    initializedConnections);
              }
            }
          }
        });
  }