Example #1
0
  static void close(NioSocketChannel channel, ChannelFuture future) {
    NioWorker worker = channel.worker;

    boolean connected = channel.isConnected();
    boolean bound = channel.isBound();
    try {
      channel.socket.close();
      worker.cancelledKeys++;

      if (channel.setClosed()) {
        future.setSuccess();
        if (connected) {
          fireChannelDisconnected(channel);
        }
        if (bound) {
          fireChannelUnbound(channel);
        }

        cleanUpWriteBuffer(channel);
        fireChannelClosed(channel);
      } else {
        future.setSuccess();
      }
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
Example #2
0
  private static void clearOpWrite(NioSocketChannel channel) {
    NioWorker worker = channel.worker;
    Selector selector = worker.selector;
    SelectionKey key = channel.socket.keyFor(selector);
    if (key == null) {
      return;
    }
    if (!key.isValid()) {
      close(key);
      return;
    }
    int interestOps;
    boolean changed = false;

    // interestOps can change at any time and at any thread.
    // Acquire a lock to avoid possible race condition.
    synchronized (channel.interestOpsLock) {
      interestOps = channel.getRawInterestOps();
      if ((interestOps & SelectionKey.OP_WRITE) != 0) {
        interestOps &= ~SelectionKey.OP_WRITE;
        key.interestOps(interestOps);
        changed = true;
      }
    }

    if (changed) {
      channel.setRawInterestOpsNow(interestOps);
    }
  }
Example #3
0
  @Override
  protected boolean read(SelectionKey k) {
    final SocketChannel ch = (SocketChannel) k.channel();
    final NioSocketChannel channel = (NioSocketChannel) k.attachment();

    final ReceiveBufferSizePredictor predictor =
        channel.getConfig().getReceiveBufferSizePredictor();
    final int predictedRecvBufSize = predictor.nextReceiveBufferSize();

    int ret = 0;
    int readBytes = 0;
    boolean failure = true;

    ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize);
    try {
      while ((ret = ch.read(bb)) > 0) {
        readBytes += ret;
        if (!bb.hasRemaining()) {
          break;
        }
      }
      failure = false;
    } catch (ClosedChannelException e) {
      // Can happen, and does not need a user attention.
    } catch (Throwable t) {
      fireExceptionCaught(channel, t);
    }

    if (readBytes > 0) {
      bb.flip();

      final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory();
      final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes);
      buffer.setBytes(0, bb);
      buffer.writerIndex(readBytes);

      recvBufferPool.release(bb);

      // Update the predictor.
      predictor.previousReceiveBufferSize(readBytes);

      // Fire the event.
      fireMessageReceived(channel, buffer);
    } else {
      recvBufferPool.release(bb);
    }

    if (ret < 0 || failure) {
      k.cancel(); // Some JDK implementations run into an infinite loop without this.
      close(channel, succeededFuture(channel));
      return false;
    }

    return true;
  }
Example #4
0
  private static void cleanUpWriteBuffer(NioSocketChannel channel) {
    Exception cause = null;
    boolean fireExceptionCaught = false;

    // Clean up the stale messages in the write buffer.
    synchronized (channel.writeLock) {
      MessageEvent evt = channel.currentWriteEvent;
      if (evt != null) {
        channel.currentWriteEvent = null;
        channel.currentWriteIndex = 0;

        // Create the exception only once to avoid the excessive overhead
        // caused by fillStackTrace.
        if (channel.isOpen()) {
          cause = new NotYetConnectedException();
        } else {
          cause = new ClosedChannelException();
        }
        evt.getFuture().setFailure(cause);
        fireExceptionCaught = true;
      }

      Queue<MessageEvent> writeBuffer = channel.writeBuffer;
      if (!writeBuffer.isEmpty()) {
        // Create the exception only once to avoid the excessive overhead
        // caused by fillStackTrace.
        if (cause == null) {
          if (channel.isOpen()) {
            cause = new NotYetConnectedException();
          } else {
            cause = new ClosedChannelException();
          }
        }

        for (; ; ) {
          evt = writeBuffer.poll();
          if (evt == null) {
            break;
          }
          evt.getFuture().setFailure(cause);
          fireExceptionCaught = true;
        }
      }
    }

    if (fireExceptionCaught) {
      fireExceptionCaught(channel, cause);
    }
  }
Example #5
0
  static void write(final NioSocketChannel channel, boolean mightNeedWakeup) {
    if (!channel.isConnected()) {
      cleanUpWriteBuffer(channel);
      return;
    }

    if (mightNeedWakeup && scheduleWriteIfNecessary(channel)) {
      return;
    }

    if (channel.inWriteNowLoop) {
      scheduleWriteIfNecessary(channel);
    } else {
      writeNow(channel, channel.getConfig().getWriteSpinCount());
    }
  }
Example #6
0
  private static boolean read(SelectionKey k) {
    ScatteringByteChannel ch = (ScatteringByteChannel) k.channel();
    NioSocketChannel channel = (NioSocketChannel) k.attachment();

    ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor();
    ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory();

    ChannelBuffer buffer = bufferFactory.getBuffer(predictor.nextReceiveBufferSize());

    int ret = 0;
    int readBytes = 0;
    boolean failure = true;
    try {
      while ((ret = buffer.writeBytes(ch, buffer.writableBytes())) > 0) {
        readBytes += ret;
        if (!buffer.writable()) {
          break;
        }
      }
      failure = false;
    } catch (AsynchronousCloseException e) {
      // Can happen, and does not need a user attention.
    } catch (Throwable t) {
      fireExceptionCaught(channel, t);
    }

    if (readBytes > 0) {
      // Update the predictor.
      predictor.previousReceiveBufferSize(readBytes);

      // Fire the event.
      fireMessageReceived(channel, buffer);
    }

    if (ret < 0 || failure) {
      close(k);
      return false;
    }

    return true;
  }
Example #7
0
    public void run() {
      SocketAddress localAddress = channel.getLocalAddress();
      SocketAddress remoteAddress = channel.getRemoteAddress();

      if (localAddress == null || remoteAddress == null) {
        if (future != null) {
          future.setFailure(new ClosedChannelException());
        }
        close(channel, succeededFuture(channel));
        return;
      }

      try {
        if (server) {
          channel.channel.configureBlocking(false);
        }

        synchronized (channel.interestOpsLock) {
          channel.channel.register(selector, channel.getRawInterestOps(), channel);
        }
        if (future != null) {
          channel.setConnected();
          future.setSuccess();
        }

        if (server || !((NioClientSocketChannel) channel).boundManually) {
          fireChannelBound(channel, localAddress);
        }
        fireChannelConnected(channel, remoteAddress);
      } catch (IOException e) {
        if (future != null) {
          future.setFailure(e);
        }
        close(channel, succeededFuture(channel));
        if (!(e instanceof ClosedChannelException)) {
          throw new ChannelException("Failed to register a socket to the selector.", e);
        }
      }
    }
Example #8
0
  static void setInterestOps(NioSocketChannel channel, ChannelFuture future, int interestOps) {
    boolean changed = false;
    try {
      // interestOps can change at any time and at any thread.
      // Acquire a lock to avoid possible race condition.
      synchronized (channel.interestOpsLock) {
        NioWorker worker = channel.worker;
        Selector selector = worker.selector;
        SelectionKey key = channel.socket.keyFor(selector);

        if (key == null || selector == null) {
          // Not registered to the worker yet.
          // Set the rawInterestOps immediately; RegisterTask will pick it up.
          channel.setRawInterestOpsNow(interestOps);
          return;
        }

        // Override OP_WRITE flag - a user cannot change this flag.
        interestOps &= ~Channel.OP_WRITE;
        interestOps |= channel.getRawInterestOps() & Channel.OP_WRITE;

        switch (CONSTRAINT_LEVEL) {
          case 0:
            if (channel.getRawInterestOps() != interestOps) {
              key.interestOps(interestOps);
              if (Thread.currentThread() != worker.thread
                  && worker.wakenUp.compareAndSet(false, true)) {
                selector.wakeup();
              }
              changed = true;
            }
            break;
          case 1:
          case 2:
            if (channel.getRawInterestOps() != interestOps) {
              if (Thread.currentThread() == worker.thread) {
                key.interestOps(interestOps);
                changed = true;
              } else {
                worker.selectorGuard.readLock().lock();
                try {
                  if (worker.wakenUp.compareAndSet(false, true)) {
                    selector.wakeup();
                  }
                  key.interestOps(interestOps);
                  changed = true;
                } finally {
                  worker.selectorGuard.readLock().unlock();
                }
              }
            }
            break;
          default:
            throw new Error();
        }
      }

      future.setSuccess();
      if (changed) {
        channel.setRawInterestOpsNow(interestOps);
        fireChannelInterestChanged(channel);
      }
    } catch (CancelledKeyException e) {
      // setInterestOps() was called on a closed channel.
      ClosedChannelException cce = new ClosedChannelException();
      future.setFailure(cce);
      fireExceptionCaught(channel, cce);
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
Example #9
0
  private static void writeNow(NioSocketChannel channel, int writeSpinCount) {

    boolean open = true;
    boolean addOpWrite = false;
    boolean removeOpWrite = false;

    MessageEvent evt;
    ChannelBuffer buf;
    int bufIdx;
    int writtenBytes = 0;

    Queue<MessageEvent> writeBuffer = channel.writeBuffer;
    synchronized (channel.writeLock) {
      channel.inWriteNowLoop = true;
      evt = channel.currentWriteEvent;
      for (; ; ) {
        if (evt == null) {
          evt = writeBuffer.poll();
          if (evt == null) {
            channel.currentWriteEvent = null;
            removeOpWrite = true;
            break;
          }

          evt = consolidateComposite(evt);
          buf = (ChannelBuffer) evt.getMessage();
          bufIdx = buf.readerIndex();
        } else {
          buf = (ChannelBuffer) evt.getMessage();
          bufIdx = channel.currentWriteIndex;
        }

        try {
          for (int i = writeSpinCount; i > 0; i--) {
            int localWrittenBytes =
                buf.getBytes(bufIdx, channel.socket, buf.writerIndex() - bufIdx);

            if (localWrittenBytes != 0) {
              bufIdx += localWrittenBytes;
              writtenBytes += localWrittenBytes;
              break;
            }
          }

          if (bufIdx == buf.writerIndex()) {
            // Successful write - proceed to the next message.
            channel.currentWriteEvent = null;
            evt.getFuture().setSuccess();
            evt = null;
          } else {
            // Not written fully - perhaps the kernel buffer is full.
            channel.currentWriteEvent = evt;
            channel.currentWriteIndex = bufIdx;
            addOpWrite = true;
            break;
          }
        } catch (AsynchronousCloseException e) {
          // Doesn't need a user attention - ignore.
          channel.currentWriteEvent = evt;
          channel.currentWriteIndex = bufIdx;
        } catch (Throwable t) {
          channel.currentWriteEvent = null;
          evt.getFuture().setFailure(t);
          evt = null;
          fireExceptionCaught(channel, t);
          if (t instanceof IOException) {
            open = false;
            close(channel, succeededFuture(channel));
          }
        }
      }
      channel.inWriteNowLoop = false;
    }

    fireWriteComplete(channel, writtenBytes);

    if (open) {
      if (addOpWrite) {
        setOpWrite(channel);
      } else if (removeOpWrite) {
        clearOpWrite(channel);
      }
    }
  }