code: private void handleIO(final SelectionKey sk) {
      MemcachedNode node = (MemcachedNode) sk.attachment();
  
      try {
        getLogger().debug("Handling IO for:  %s (r=%s, w=%s, c=%s, op=%s)", sk,
          sk.isReadable(), sk.isWritable(), sk.isConnectable(),
          sk.attachment());
        if (sk.isConnectable() && belongsToCluster(node)) {
          getLogger().debug("Connection state changed for %s", sk);
          final SocketChannel channel = node.getChannel();
          if (channel.finishConnect()) {
            finishConnect(sk, node);
          } else {
            assert !channel.isConnected() : "connected";
          }
        } else {
          handleReadsAndWrites(sk, node);
        }
      } catch (ClosedChannelException e) {
        if (!shutDown) {
          getLogger().info("Closed channel and not shutting down. Queueing"
              + " reconnect on %s", node, e);
          lostConnection(node);
        }
      } catch (ConnectException e) {
        getLogger().info("Reconnecting due to failure to connect to %s", node, e);
        queueReconnect(node);
      } catch (OperationException e) {
        node.setupForAuth();
        getLogger().info("Reconnection due to exception handling a memcached "
          + "operation on %s. This may be due to an authentication failure.",
          node, e);
        lostConnection(node);
      } catch (Exception e) {
        node.setupForAuth();
        getLogger().info("Reconnecting due to exception on %s", node, e);
        lostConnection(node);
      }
      node.fixupOps();
    }
docs: Handle IO for a specific selector.
  
  Any IOException will cause a reconnect. Note that this code makes sure
  that the corresponding node is not only able to connect, but also able to
  respond in a correct fashion (if verifyAliveOnConnect is set to true
  through a property). This is handled by issuing a dummy
  version/noop call and making sure it returns in a correct and timely
  fashion.
  
  @param sk the selector to handle IO against.