private List<NetworkSend> prepareSends(Set<Integer> requestsToDrop, List<ResponseInfo> responseInfoList) {
    List<NetworkSend> sends = new ArrayList<>();
    ListIterator<RequestMetadata> iter = pendingRequests.listIterator();

    /* Drop requests that have waited too long */
    while (iter.hasNext()) {
      RequestMetadata requestMetadata = iter.next();
      if (time.milliseconds() - requestMetadata.requestQueuedAtMs > checkoutTimeoutMs) {
        responseInfoList.add(
            new ResponseInfo(requestMetadata.requestInfo, NetworkClientErrorCode.ConnectionUnavailable, null));
        requestMetadata.requestInfo.getRequest().release();
        logger.trace("Failing request to host {} port {} due to connection unavailability",
            requestMetadata.requestInfo.getHost(), requestMetadata.requestInfo.getPort());
        iter.remove();
        if (requestMetadata.pendingConnectionId != null) {
          pendingConnectionsToAssociatedRequests.remove(requestMetadata.pendingConnectionId);
          requestMetadata.pendingConnectionId = null;
        }
        String connId =
            correlationIdInFlightToConnectionId.get(requestMetadata.requestInfo.getRequest().getCorrelationId());
        if (connId != null) {
          connectionTracker.checkInConnection(connId);
          connectionIdToRequestInFlight.remove(connId);
        }
        networkMetrics.connectionCheckoutTimeoutError.inc();
      } else {
        // Since requests are ordered by time, once the first request that cannot be dropped is found,
        // we let that and the rest be iterated over in the next while loop. Just move the cursor backwards as this
        // element needs to be processed.
        iter.previous();
        break;
      }
    }

    while (iter.hasNext()) {
      RequestMetadata requestMetadata = iter.next();
      try {
        String host = requestMetadata.requestInfo.getHost();
        Port port = requestMetadata.requestInfo.getPort();
        ReplicaId replicaId = requestMetadata.requestInfo.getReplicaId();
        if (replicaId == null) {
          throw new IllegalStateException("ReplicaId in request is null.");
        }
        if (requestsToDrop.contains(requestMetadata.requestInfo.getRequest().getCorrelationId())) {
          responseInfoList.add(
              new ResponseInfo(requestMetadata.requestInfo, NetworkClientErrorCode.ConnectionUnavailable, null));
          requestMetadata.requestInfo.getRequest().release();
          if (requestMetadata.pendingConnectionId != null) {
            pendingConnectionsToAssociatedRequests.remove(requestMetadata.pendingConnectionId);
            requestMetadata.pendingConnectionId = null;
          }
          iter.remove();
        } else {
          String connId = connectionTracker.checkOutConnection(host, port, replicaId.getDataNodeId());
          if (connId == null) {
            networkMetrics.connectionNotAvailable.inc();
            if (requestMetadata.pendingConnectionId == null) {
              if (connectionTracker.mayCreateNewConnection(host, port, replicaId.getDataNodeId())) {
                connId = connectionTracker.connectAndTrack(this::connect, host, port, replicaId.getDataNodeId());
                requestMetadata.pendingConnectionId = connId;
                pendingConnectionsToAssociatedRequests.put(connId, requestMetadata);
                logger.trace("Initiated a connection to host {} port {} ", host, port);
              } else {
                networkMetrics.connectionReachLimit.inc();
              }
            }
          } else {
            if (requestMetadata.pendingConnectionId != null) {
              pendingConnectionsToAssociatedRequests.remove(requestMetadata.pendingConnectionId);
              requestMetadata.pendingConnectionId = null;
            }
            logger.trace("Connection checkout succeeded for {}:{} with connectionId {} ", host, port, connId);
            sends.add(new NetworkSend(connId, requestMetadata.requestInfo.getRequest(), null, time));
            connectionIdToRequestInFlight.put(connId, requestMetadata);
            correlationIdInFlightToConnectionId.put(requestMetadata.requestInfo.getRequest().getCorrelationId(),
                connId);
            iter.remove();
            requestMetadata.onRequestDequeue();
          }
        }
      } catch (IOException e) {
        networkMetrics.networkClientIOError.inc();
        logger.error("Received exception while checking out a connection", e);
      }
    }
    return sends;
  }
Process the requests in the pendingRequestsQueue. Create {@link ResponseInfo} for those requests that have timed
out while waiting in the queue. Then, attempt to prepare {@link NetworkSend}s by checking out connections for
the rest of the requests in the queue.
@param requestsToDrop the list of correlation IDs representing the requests that can be dropped. If any of these
                      correlation IDs match pending requests, those pending requests will not be sent out.
@param responseInfoList the list to populate with responseInfos for requests that timed out waiting for
                        connections.
@return the list of {@link NetworkSend} objects to hand over to the Selector.
ambry-network/src/main/java/com/github/ambry/network/SocketNetworkClient.java