docs: public static void loop(AuroraListener listener, final GlobalStateInfo globalInfo,
        final List<HostAddress> addresses,
        SearchFilter initialSearchFilter) throws SQLException {
  
      SearchFilter searchFilter = initialSearchFilter;
      AuroraProtocol protocol;
      Deque<HostAddress> loopAddresses = new ArrayDeque<>(addresses);
      if (loopAddresses.isEmpty()) {
        resetHostList(listener, loopAddresses);
      }
  
      int maxConnectionTry = listener.getRetriesAllDown();
      SQLException lastQueryException = null;
      HostAddress probableMasterHost = null;
      boolean firstLoop = true;
      while (!loopAddresses.isEmpty() || (!searchFilter.isFailoverLoop() && maxConnectionTry > 0)) {
        protocol = getNewProtocol(listener.getProxy(), globalInfo, listener.getUrlParser());
  
        if (listener.isExplicitClosed() || (!listener.isSecondaryHostFailReconnect() && !listener
            .isMasterHostFailReconnect())) {
          return;
        }
        maxConnectionTry--;
  
        try {
          HostAddress host = loopAddresses.pollFirst();
          if (host == null) {
            for (HostAddress hostAddress : listener.getUrlParser().getHostAddresses()) {
              if (!hostAddress.equals(listener.getClusterHostAddress())) {
                loopAddresses.add(hostAddress);
              }
            }
            // Use cluster last as backup
            if (listener.getClusterHostAddress() != null
                && listener.getUrlParser().getHostAddresses().size() < 2) {
              loopAddresses.add(listener.getClusterHostAddress());
            }
  
            host = loopAddresses.pollFirst();
          }
          protocol.setHostAddress(host);
          protocol.connect();
  
          if (listener.isExplicitClosed()) {
            protocol.close();
            return;
          }
  
          listener.removeFromBlacklist(protocol.getHostAddress());
  
          if (listener.isMasterHostFailReconnect() && protocol.isMasterConnection()) {
            // Look for secondary when only known endpoint is the cluster endpoint
            if (searchFilter.isFineIfFoundOnlyMaster()
                && listener.getUrlParser().getHostAddresses().size() <= 1
                && protocol.getHostAddress().equals(listener.getClusterHostAddress())) {
              listener.retrieveAllEndpointsAndSet(protocol);
  
              if (listener.getUrlParser().getHostAddresses().size() > 1) {
                //add newly discovered end-point to loop
                loopAddresses.addAll(listener.getUrlParser().getHostAddresses());
                //since there is more than one end point, reactivate connection to a read-only host
                searchFilter = new SearchFilter(false);
              }
            }
  
            if (foundMaster(listener, protocol, searchFilter)) {
              return;
            }
  
          } else if (!protocol.isMasterConnection()) {
            if (listener.isSecondaryHostFailReconnect()) {
              //in case cluster DNS is currently pointing to a slave host
              if (listener.getUrlParser().getHostAddresses().size() <= 1
                  && protocol.getHostAddress().equals(listener.getClusterHostAddress())) {
                listener.retrieveAllEndpointsAndSet(protocol);
  
                if (listener.getUrlParser().getHostAddresses().size() > 1) {
                  //add newly discovered end-point to loop
                  loopAddresses.addAll(listener.getUrlParser().getHostAddresses());
                  //since there is more than one end point, reactivate connection to a read-only host
                  searchFilter = new SearchFilter(false);
                }
              } else {
                if (foundSecondary(listener, protocol, searchFilter)) {
                  return;
                }
              }
  
            } else {
              try {
                if (listener.isSecondaryHostFailReconnect()
                    || (listener.isMasterHostFailReconnect() && probableMasterHost == null)) {
                  probableMasterHost = listener
                      .searchByStartName(protocol, listener.getUrlParser().getHostAddresses());
                  if (probableMasterHost != null) {
                    loopAddresses.remove(probableMasterHost);
                    AuroraProtocol.searchProbableMaster(listener, globalInfo, probableMasterHost);
                    if (listener.isMasterHostFailReconnect() && searchFilter
                        .isFineIfFoundOnlySlave()) {
                      return;
                    }
                  }
                }
              } finally {
                protocol.close();
              }
            }
          } else {
            protocol.close();
          }
  
        } catch (SQLException e) {
          lastQueryException = e;
          listener.addToBlacklist(protocol.getHostAddress());
        }
  
        if (!listener.isMasterHostFailReconnect() && !listener.isSecondaryHostFailReconnect()) {
          return;
        }
  
        //in case master not found but slave is , and allowing master down
        if (loopAddresses.isEmpty()
            && (listener.isMasterHostFailReconnect()
            && listener.urlParser.getOptions().allowMasterDownConnection
            && !listener.isSecondaryHostFailReconnect())) {
          return;
        }
  
        //on connection and all slaves have been tested, use master if on
        if (loopAddresses.isEmpty()
            && searchFilter.isInitialConnection()
            && !listener.isMasterHostFailReconnect()) {
          return;
        }
  
        // if server has try to connect to all host, and there is remaining master or slave that fail
        // add all servers back to continue looping until maxConnectionTry is reached
        if (loopAddresses.isEmpty() && !searchFilter.isFailoverLoop() && maxConnectionTry > 0) {
          resetHostList(listener, loopAddresses);
          if (firstLoop) {
            firstLoop = false;
          } else {
            try {
              //wait 250ms before looping through all connection another time
              Thread.sleep(250);
            } catch (InterruptedException interrupted) {
              //interrupted, continue
            }
          }
  
        }
  
        // Try to connect to the cluster if no other connection is good
        if (maxConnectionTry == 0 && !loopAddresses.contains(listener.getClusterHostAddress())
            && listener.getClusterHostAddress() != null) {
          loopAddresses.add(listener.getClusterHostAddress());
        }
  
      }
  
      if (listener.isMasterHostFailReconnect() || listener.isSecondaryHostFailReconnect()) {
        String error = "No active connection found for replica";
        if (listener.isMasterHostFailReconnect()) {
          error = "No active connection found for master";
        }
        if (lastQueryException != null) {
          throw new SQLException(error, lastQueryException.getSQLState(),
              lastQueryException.getErrorCode(), lastQueryException);
        }
        throw new SQLException(error);
      }
    }