private void handleSelectorEvents(List<ResponseInfo> responseInfoList) {
    for (String connId : selector.connected()) {
      logger.trace("Checking in connection back to connection tracker for connectionId {} ", connId);
      connectionTracker.checkInConnection(connId);
      pendingConnectionsToAssociatedRequests.remove(connId);
    }

    for (String connId : selector.disconnected()) {
      logger.trace("ConnectionId {} disconnected, removing it from connection tracker", connId);
      DataNodeId dataNodeId = connectionTracker.removeConnection(connId);
      // If this was a pending connection and if there is a request that initiated this connection,
      // mark the corresponding request as failed.
      RequestMetadata requestMetadata = pendingConnectionsToAssociatedRequests.remove(connId);
      if (requestMetadata != null) {
        logger.trace("Pending connectionId {} disconnected", connId);
        pendingRequests.remove(requestMetadata);
        requestMetadata.pendingConnectionId = null;
        responseInfoList.add(new ResponseInfo(requestMetadata.requestInfo, NetworkClientErrorCode.NetworkError, null));
      } else {
        // If this was an established connection and if there is a request in flight on this connection,
        // mark the corresponding request as failed.
        requestMetadata = connectionIdToRequestInFlight.remove(connId);
        if (requestMetadata != null) {
          logger.trace("ConnectionId {} with request in flight disconnected", connId);
          correlationIdInFlightToConnectionId.remove(requestMetadata.requestInfo.getRequest().getCorrelationId());
          responseInfoList.add(
              new ResponseInfo(requestMetadata.requestInfo, NetworkClientErrorCode.NetworkError, null));
        } else {
          logger.debug(
              "ConnectionId {} has been failed previously due to long wait and now associated channel to {} timed out",
              connId, dataNodeId);
          // Explicitly set requestInfo = null in ResponseInfo, the OperationController should detect this and directly
          // notify ResponseHandler without handing it over to PutManager/GetManager/DeleteManager/TtlUpdateManager.
          responseInfoList.add(new ResponseInfo(null, NetworkClientErrorCode.NetworkError, null, dataNodeId, false));
          // No need to call pendingRequests.remove() because it has been removed due to connection unavailability in prepareSends()
        }
      }
      // if request is send completed, its resource has already been released.
      if (requestMetadata != null && !requestMetadata.requestInfo.getRequest().isSendComplete()) {
        requestMetadata.requestInfo.getRequest().release();
      }
      networkMetrics.connectionDisconnected.inc();
    }

    // We don't need to release the completed sends' resources here, since they are already released by selector.

    for (NetworkReceive recv : selector.completedReceives()) {
      String connId = recv.getConnectionId();
      logger.trace("Receive completed for connectionId {} and checking in the connection back to connection tracker",
          connId);
      connectionTracker.checkInConnection(connId);
      RequestMetadata requestMetadata = connectionIdToRequestInFlight.remove(connId);
      correlationIdInFlightToConnectionId.remove(requestMetadata.requestInfo.getRequest().getCorrelationId());
      // This would transfer the ownership of the content from BoundedNettyByteBufReceive to ResponseInfo.
      // Don't use this BoundedNettyByteBufReceive anymore.
      responseInfoList.add(new ResponseInfo(requestMetadata.requestInfo, null, recv.getReceivedBytes().content()));
      requestMetadata.onResponseReceive();
    }
  }
Handle Selector events after a poll: newly established connections, new disconnections, newly completed sends and
receives.
@param responseInfoList the list to populate with {@link ResponseInfo} objects for responses created based on
                        the selector events.
ambry-network/src/main/java/com/github/ambry/network/SocketNetworkClient.java