@Override protected void doWrite(ChannelOutboundBuffer in) throws Exception { for (; ; ) { final int msgCount = in.size(); if (msgCount == 0) { // Wrote all messages. clearEpollOut(); break; } // Do gathering write if: // * the outbound buffer contains more than one messages and // * they are all buffers rather than a file region. if (msgCount > 1) { if (PlatformDependent.hasUnsafe()) { // this means we can cast to EpollChannelOutboundBuffer and write the AdressEntry // directly. EpollChannelOutboundBuffer epollIn = (EpollChannelOutboundBuffer) in; // Ensure the pending writes are made of memoryaddresses only. AddressEntry[] addresses = epollIn.memoryAddresses(); if (addresses != null) { writeBytesMultiple(epollIn, msgCount, addresses); // We do not break the loop here even if the outbound buffer was flushed completely, // because a user might have triggered another write and flush when we notify his or her // listeners. continue; } } else { NioSocketChannelOutboundBuffer nioIn = (NioSocketChannelOutboundBuffer) in; // Ensure the pending writes are made of memoryaddresses only. ByteBuffer[] buffers = nioIn.nioBuffers(); if (buffers != null) { writeBytesMultiple(nioIn, msgCount, buffers); // We do not break the loop here even if the outbound buffer was flushed completely, // because a user might have triggered another write and flush when we notify his or her // listeners. continue; } } } // The outbound buffer contains only one message or it contains a file region. Object msg = in.current(); if (msg instanceof ByteBuf) { ByteBuf buf = (ByteBuf) msg; int readableBytes = buf.readableBytes(); if (readableBytes == 0) { in.remove(); continue; } int expected = buf.readableBytes(); int localFlushedAmount = doWriteBytes(buf, expected); in.progress(localFlushedAmount); if (localFlushedAmount < expected) { setEpollOut(); break; } if (!buf.isReadable()) { in.remove(); } } else if (msg instanceof DefaultFileRegion) { DefaultFileRegion region = (DefaultFileRegion) msg; long expected = region.count() - region.position(); long localFlushedAmount = doWriteFileRegion(region, expected); in.progress(localFlushedAmount); if (localFlushedAmount < expected) { setEpollOut(); break; } if (region.transfered() >= region.count()) { in.remove(); } } else { throw new UnsupportedOperationException( "unsupported message type: " + StringUtil.simpleClassName(msg)); } } }
/** * Write a {@link DefaultFileRegion} * * @param region the {@link DefaultFileRegion} from which the bytes should be written * @return amount the amount of written bytes */ private long doWriteFileRegion(DefaultFileRegion region, long count) throws Exception { return Native.sendfile(fd, region, region.transfered(), count); }