@Override
  public int warmUpConnections(List<DataNodeId> dataNodeIds, int connectionWarmUpPercentagePerDataNode,
      long timeForWarmUp, List<ResponseInfo> responseInfoList) {
    logger.info("Connection warm up start.");
    if (dataNodeIds.size() == 0) {
      return 0;
    }
    dataNodeIds.forEach(dataNodeId -> connectionTracker.setMinimumActiveConnectionsPercentage(dataNodeId,
        connectionWarmUpPercentagePerDataNode));
    int expectedConnections = connectionTracker.replenishConnections(this::connect, Integer.MAX_VALUE);

    long startTime = System.currentTimeMillis();
    int successfulConnections = 0;
    int failedConnections = 0;
    while (successfulConnections + failedConnections < expectedConnections) {
      try {
        selector.poll(1000L);
        successfulConnections += selector.connected().size();
        failedConnections += selector.disconnected().size();
        handleSelectorEvents(responseInfoList);
      } catch (IOException e) {
        logger.error("Warm up received unexpected error while polling: ", e);
      }
      if (System.currentTimeMillis() - startTime > timeForWarmUp) {
        break;
      }
    }
    logger.info("Connection warm up done. Tried: {}, Succeeded: {}, Failed: {}, Time elapsed: {} ms",
        expectedConnections, successfulConnections, failedConnections, System.currentTimeMillis() - startTime);

    return successfulConnections;
  }
Warm up connections to dataNodes in a specified time window.
If a connection established successfully, it's a successConnection.
If a connection failed(for example, target dataNode offline), it's a failedConnection.
If a connection breaks after successfully established, it's counted as a failedConnection. This impact the
counting in the method, but this is tolerable as other good/bad connections can be handled in next selector.poll().
If a connection established after this time window of timeForWarmUp, it can be handled in next selector.poll().
<p>
This will also set the minimum number of active connections for each of the data nodes. This means that the
SocketNetworkClient will attempt to keep a percentage of connections ready for use at all times by initiating extra
connections in {@link SocketNetworkClient#sendAndPoll} when a pool drops below this number.
@param dataNodeIds warm up target nodes.
@param connectionWarmUpPercentagePerDataNode percentage of max connections would like to establish in the warmup.
@param timeForWarmUp max time to wait for connections' establish in milliseconds.
@param responseInfoList records responses from disconnected connections.
@return number of connections established successfully.
ambry-network/src/main/java/com/github/ambry/network/SocketNetworkClient.java