/** @param futs Futures to complete. */
  private void completeOnNodeLeft(GridNioFuture<?>[] futs) {
    for (GridNioFuture<?> msg : futs) {
      IOException e = new IOException("Failed to send message, node has left: " + node.id());

      ((GridNioFutureImpl) msg).onDone(e);

      if (msg.ackClosure() != null) msg.ackClosure().apply(new IgniteException(e));
    }
  }
  /**
   * @param fut NIO future.
   * @return {@code False} if queue limit is exceeded.
   */
  public boolean add(GridNioFuture<?> fut) {
    assert fut != null;

    if (!fut.skipRecovery()) {
      if (resendCnt == 0) {
        msgFuts.addLast(fut);

        return msgFuts.size() < queueLimit;
      } else resendCnt--;
    }

    return true;
  }
  /** @param rcvCnt Number of messages received by remote node. */
  public void ackReceived(long rcvCnt) {
    if (log.isDebugEnabled())
      log.debug(
          "Handle acknowledgment [acked="
              + acked
              + ", rcvCnt="
              + rcvCnt
              + ", msgFuts="
              + msgFuts.size()
              + ']');

    while (acked < rcvCnt) {
      GridNioFuture<?> fut = msgFuts.pollFirst();

      assert fut != null
          : "Missed message future [rcvCnt=" + rcvCnt + ", acked=" + acked + ", desc=" + this + ']';

      assert fut.isDone() : fut;

      if (fut.ackClosure() != null) fut.ackClosure().apply(null);

      acked++;
    }
  }