docs: public static void loop(MastersSlavesListener listener, final GlobalStateInfo globalInfo,
        final List<HostAddress> addresses, SearchFilter searchFilter) throws SQLException {
  
      MastersSlavesProtocol protocol;
      ArrayDeque<HostAddress> loopAddresses = new ArrayDeque<>(addresses);
      if (loopAddresses.isEmpty()) {
        resetHostList(listener, loopAddresses);
      }
  
      int maxConnectionTry = listener.getRetriesAllDown();
      SQLException lastQueryException = 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) {
            loopAddresses.addAll(listener.getUrlParser().getHostAddresses());
            host = loopAddresses.pollFirst();
          }
  
          protocol.setHostAddress(host);
  
          protocol.connect();
          if (listener.isExplicitClosed()) {
            protocol.close();
            return;
          }
  
          listener.removeFromBlacklist(protocol.getHostAddress());
  
          if (listener.isMasterHostFailReconnect() && protocol.isMasterConnection()) {
            if (foundMaster(listener, protocol, searchFilter)) {
              return;
            }
          } else if (listener.isSecondaryHostFailReconnect() && !protocol.isMasterConnection()) {
            if (foundSecondary(listener, protocol, searchFilter)) {
              return;
            }
          } 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
            }
          }
        }
  
      }
  
      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.getMessage(),
              lastQueryException.getSQLState(), lastQueryException.getErrorCode(),
              lastQueryException);
        }
        throw new SQLException(error);
      }
  
    }