* Merged recent changes in the trunk to the NIO UDP transport

* Other miscellaneous modifications like typo fix
This commit is contained in:
Trustin Lee 2009-06-11 06:10:46 +00:00
parent e4871f8460
commit 899b16678f
5 changed files with 199 additions and 148 deletions

View File

@ -25,7 +25,9 @@ package org.jboss.netty.channel.socket.nio;
import static org.jboss.netty.channel.Channels.*; import static org.jboss.netty.channel.Channels.*;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.channels.DatagramChannel; import java.nio.channels.DatagramChannel;
import java.util.Queue; import java.util.Queue;
@ -34,16 +36,14 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.AbstractChannel;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelException;
import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.ServerChannel;
import org.jboss.netty.channel.socket.DatagramChannelConfig; import org.jboss.netty.channel.socket.DatagramChannelConfig;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.internal.LinkedTransferQueue; import org.jboss.netty.util.internal.LinkedTransferQueue;
import org.jboss.netty.util.internal.ThreadLocalBoolean; import org.jboss.netty.util.internal.ThreadLocalBoolean;
@ -56,13 +56,8 @@ import org.jboss.netty.util.internal.ThreadLocalBoolean;
* *
* @version $Rev$, $Date$ * @version $Rev$, $Date$
*/ */
public class NioDatagramChannel extends AbstractChannel implements class NioDatagramChannel extends AbstractChannel
ServerChannel { implements org.jboss.netty.channel.socket.DatagramChannel {
/**
* Internal Netty logger.
*/
private static final InternalLogger logger = InternalLoggerFactory
.getInstance(NioDatagramChannel.class);
/** /**
* The {@link DatagramChannelConfig}. * The {@link DatagramChannelConfig}.
@ -77,7 +72,7 @@ public class NioDatagramChannel extends AbstractChannel implements
/** /**
* The {@link DatagramChannel} that this channel uses. * The {@link DatagramChannel} that this channel uses.
*/ */
private final DatagramChannel datagramChannel; private final java.nio.channels.DatagramChannel datagramChannel;
/** /**
* Monitor object to synchronize access to InterestedOps. * Monitor object to synchronize access to InterestedOps.
@ -120,30 +115,17 @@ public class NioDatagramChannel extends AbstractChannel implements
*/ */
MessageEvent currentWriteEvent; MessageEvent currentWriteEvent;
/**
* The current write index.
*/
int currentWriteIndex;
/** /**
* Boolean that indicates that write operation is in progress. * Boolean that indicates that write operation is in progress.
*/ */
volatile boolean inWriteNowLoop; volatile boolean inWriteNowLoop;
/** NioDatagramChannel(final ChannelFactory factory,
*
* @param factory
* @param pipeline
* @param sink
* @param worker
*/
public NioDatagramChannel(final ChannelFactory factory,
final ChannelPipeline pipeline, final ChannelSink sink, final ChannelPipeline pipeline, final ChannelSink sink,
final NioUdpWorker worker) { final NioUdpWorker worker) {
super(null, factory, pipeline, sink); super(null, factory, pipeline, sink);
this.worker = worker; this.worker = worker;
datagramChannel = openNonBlockingChannel(); datagramChannel = openNonBlockingChannel();
setSoTimeout(1000);
config = new DefaultNioDatagramChannelConfig(datagramChannel.socket()); config = new DefaultNioDatagramChannelConfig(datagramChannel.socket());
fireChannelOpen(this); fireChannelOpen(this);
@ -159,27 +141,22 @@ public class NioDatagramChannel extends AbstractChannel implements
} }
} }
private void setSoTimeout(final int timeout) { public InetSocketAddress getLocalAddress() {
try { try {
datagramChannel.socket().setSoTimeout(timeout); return (InetSocketAddress) datagramChannel.socket().getLocalSocketAddress();
} catch (final IOException e) { } catch (Throwable t) {
try { // Sometimes fails on a closed socket in Windows.
datagramChannel.close(); return null;
} catch (final IOException e2) {
logger.warn("Failed to close a partially DatagramSocket.", e2);
}
throw new ChannelException(
"Failed to set the DatagramSocket timeout.", e);
} }
} }
public InetSocketAddress getLocalAddress() { public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) datagramChannel.socket() try {
.getLocalSocketAddress(); return (InetSocketAddress) datagramChannel.socket().getRemoteSocketAddress();
} } catch (Throwable t) {
// Sometimes fails on a closed socket in Windows.
public SocketAddress getRemoteAddress() { return null;
return datagramChannel.socket().getRemoteSocketAddress(); }
} }
public boolean isBound() { public boolean isBound() {
@ -187,7 +164,7 @@ public class NioDatagramChannel extends AbstractChannel implements
} }
public boolean isConnected() { public boolean isConnected() {
return datagramChannel.socket().isBound(); return datagramChannel.socket().isConnected();
} }
@Override @Override
@ -195,11 +172,6 @@ public class NioDatagramChannel extends AbstractChannel implements
return super.setClosed(); return super.setClosed();
} }
@Override
protected ChannelFuture getSucceededFuture() {
return super.getSucceededFuture();
}
public NioDatagramChannelConfig getConfig() { public NioDatagramChannelConfig getConfig() {
return config; return config;
} }
@ -208,6 +180,37 @@ public class NioDatagramChannel extends AbstractChannel implements
return datagramChannel; return datagramChannel;
} }
@Override
public int getInterestOps() {
if (!isOpen()) {
return Channel.OP_WRITE;
}
int interestOps = getRawInterestOps();
int writeBufferSize = this.writeBufferSize.get();
if (writeBufferSize != 0) {
if (highWaterMarkCounter.get() > 0) {
int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
if (writeBufferSize >= lowWaterMark) {
interestOps |= Channel.OP_WRITE;
} else {
interestOps &= ~Channel.OP_WRITE;
}
} else {
int highWaterMark = getConfig().getWriteBufferHighWaterMark();
if (writeBufferSize >= highWaterMark) {
interestOps |= Channel.OP_WRITE;
} else {
interestOps &= ~Channel.OP_WRITE;
}
}
} else {
interestOps &= ~Channel.OP_WRITE;
}
return interestOps;
}
int getRawInterestOps() { int getRawInterestOps() {
return super.getInterestOps(); return super.getInterestOps();
} }
@ -216,6 +219,15 @@ public class NioDatagramChannel extends AbstractChannel implements
super.setInterestOpsNow(interestOps); super.setInterestOpsNow(interestOps);
} }
@Override
public ChannelFuture write(Object message, SocketAddress remoteAddress) {
if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) {
return super.write(message, null);
} else {
return super.write(message, remoteAddress);
}
}
/** /**
* WriteBuffer is an extension of {@link LinkedTransferQueue} that adds * WriteBuffer is an extension of {@link LinkedTransferQueue} that adds
* support for highWaterMark checking of the write buffer size. * support for highWaterMark checking of the write buffer size.
@ -233,21 +245,17 @@ public class NioDatagramChannel extends AbstractChannel implements
* adds support for keeping track of the size of the this write buffer. * adds support for keeping track of the size of the this write buffer.
*/ */
@Override @Override
public boolean offer(final MessageEvent e) { public boolean offer(MessageEvent e) {
final boolean success = super.offer(e); boolean success = super.offer(e);
assert success; assert success;
final int messageSize = ((ChannelBuffer) e.getMessage()) int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes();
.readableBytes(); int newWriteBufferSize = writeBufferSize.addAndGet(messageSize);
int highWaterMark = getConfig().getWriteBufferHighWaterMark();
final int newWriteBufferSize = writeBufferSize
.addAndGet(messageSize);
final int highWaterMark = getConfig().getWriteBufferHighWaterMark();
if (newWriteBufferSize >= highWaterMark) { if (newWriteBufferSize >= highWaterMark) {
if (newWriteBufferSize - messageSize < highWaterMark) { if (newWriteBufferSize - messageSize < highWaterMark) {
highWaterMarkCounter.incrementAndGet(); highWaterMarkCounter.incrementAndGet();
if (!notifying.get()) { if (!notifying.get()) {
notifying.set(Boolean.TRUE); notifying.set(Boolean.TRUE);
fireChannelInterestChanged(NioDatagramChannel.this); fireChannelInterestChanged(NioDatagramChannel.this);
@ -255,7 +263,6 @@ public class NioDatagramChannel extends AbstractChannel implements
} }
} }
} }
return true; return true;
} }
@ -265,18 +272,13 @@ public class NioDatagramChannel extends AbstractChannel implements
*/ */
@Override @Override
public MessageEvent poll() { public MessageEvent poll() {
final MessageEvent e = super.poll(); MessageEvent e = super.poll();
if (e != null) { if (e != null) {
final int messageSize = ((ChannelBuffer) e.getMessage()) int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes();
.readableBytes(); int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize);
final int newWriteBufferSize = writeBufferSize int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
.addAndGet(-messageSize);
final int lowWaterMark = getConfig() if (newWriteBufferSize == 0 || newWriteBufferSize < lowWaterMark) {
.getWriteBufferLowWaterMark();
if (newWriteBufferSize == 0 ||
newWriteBufferSize < lowWaterMark) {
if (newWriteBufferSize + messageSize >= lowWaterMark) { if (newWriteBufferSize + messageSize >= lowWaterMark) {
highWaterMarkCounter.decrementAndGet(); highWaterMarkCounter.decrementAndGet();
if (!notifying.get()) { if (!notifying.get()) {
@ -305,4 +307,22 @@ public class NioDatagramChannel extends AbstractChannel implements
NioUdpWorker.write(NioDatagramChannel.this, false); NioUdpWorker.write(NioDatagramChannel.this, false);
} }
} }
public void joinGroup(InetAddress multicastAddress) {
throw new UnsupportedOperationException();
}
public void joinGroup(InetSocketAddress multicastAddress,
NetworkInterface networkInterface) {
throw new UnsupportedOperationException();
}
public void leaveGroup(InetAddress multicastAddress) {
throw new UnsupportedOperationException();
}
public void leaveGroup(InetSocketAddress multicastAddress,
NetworkInterface networkInterface) {
throw new UnsupportedOperationException();
}
} }

View File

@ -25,14 +25,14 @@ package org.jboss.netty.channel.socket.nio;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ServerChannelFactory; import org.jboss.netty.channel.socket.DatagramChannel;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.util.internal.ExecutorUtil; import org.jboss.netty.util.internal.ExecutorUtil;
/** /**
* A {@link NioDatagramChannelFactory} creates a server-side NIO-based * A {@link NioDatagramChannelFactory} creates a server-side NIO-based
* {@link NioDatagramChannel}. It utilizes the non-blocking I/O mode which * {@link DatagramChannel}. It utilizes the non-blocking I/O mode which
* was introduced with NIO to serve many number of concurrent connections * was introduced with NIO to serve many number of concurrent connections
* efficiently. * efficiently.
* *
@ -59,8 +59,7 @@ import org.jboss.netty.util.internal.ExecutorUtil;
* *
* @version $Rev$, $Date$ * @version $Rev$, $Date$
*/ */
public class NioDatagramChannelFactory implements ChannelFactory, public class NioDatagramChannelFactory implements DatagramChannelFactory {
ServerChannelFactory {
/** /**
* *
*/ */
@ -102,7 +101,7 @@ public class NioDatagramChannelFactory implements ChannelFactory,
sink = new NioDatagramPipelineSink(workerExecutor, workerCount); sink = new NioDatagramPipelineSink(workerExecutor, workerCount);
} }
public NioDatagramChannel newChannel(final ChannelPipeline pipeline) { public DatagramChannel newChannel(final ChannelPipeline pipeline) {
return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker()); return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker());
} }

View File

@ -47,7 +47,7 @@ import org.jboss.netty.channel.MessageEvent;
* *
* @version $Rev$, $Date$ * @version $Rev$, $Date$
*/ */
public class NioDatagramPipelineSink extends AbstractChannelSink { class NioDatagramPipelineSink extends AbstractChannelSink {
private static final AtomicInteger nextId = new AtomicInteger(); private static final AtomicInteger nextId = new AtomicInteger();
@ -74,8 +74,9 @@ public class NioDatagramPipelineSink extends AbstractChannelSink {
/** /**
* Handle downstream event. * Handle downstream event.
* *
* @param pipeline The channelpiple line that passed down the downstream event. * @param pipeline the {@link ChannelPipeline} that passes down the
* @param event The downstream event. * downstream event.
* @param e The downstream event.
*/ */
public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e) public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e)
throws Exception { throws Exception {
@ -98,6 +99,14 @@ public class NioDatagramPipelineSink extends AbstractChannelSink {
NioUdpWorker.close(channel, future); NioUdpWorker.close(channel, future);
} }
break; break;
case CONNECTED:
// TODO Implement me
if (value != null) {
//connect(channel, future, (SocketAddress) value);
} else {
//NioUdpWorker.disconnect(channel, future);
}
break;
case INTEREST_OPS: case INTEREST_OPS:
NioUdpWorker.setInterestOps(channel, future, ((Integer) value) NioUdpWorker.setInterestOps(channel, future, ((Integer) value)
.intValue()); .intValue());

View File

@ -49,6 +49,7 @@ import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelException;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.ReceiveBufferSizePredictor;
import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.ThreadRenamingRunnable;
@ -71,12 +72,6 @@ class NioUdpWorker implements Runnable {
private static final InternalLogger logger = InternalLoggerFactory private static final InternalLogger logger = InternalLoggerFactory
.getInstance(NioUdpWorker.class); .getInstance(NioUdpWorker.class);
/**
* Maximum packate size for UDP packets.
* 65,536-byte maximum size of an IP datagram minus the 20-byte size of the IP header and the 8-byte size of the UDP header.
*/
private static int MAX_PACKET_SIZE = 65507;
/** /**
* This id of this worker. * This id of this worker.
*/ */
@ -321,17 +316,21 @@ class NioUdpWorker implements Runnable {
private static void processSelectedKeys(final Set<SelectionKey> selectedKeys) { private static void processSelectedKeys(final Set<SelectionKey> selectedKeys) {
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) { for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
final SelectionKey key = i.next(); SelectionKey k = i.next();
i.remove(); i.remove();
try { try {
if (key.isReadable()) { int readyOps = k.readyOps();
read(key); if ((readyOps & SelectionKey.OP_READ) != 0) {
if (!read(k)) {
// Connection already closed - no need to handle write.
continue;
}
} }
if (key.isWritable()) { if ((readyOps & SelectionKey.OP_WRITE) != 0) {
write(key); write(k);
} }
} catch (final CancelledKeyException ignore) { } catch (CancelledKeyException e) {
close(key); close(k);
} }
} }
} }
@ -347,40 +346,57 @@ class NioUdpWorker implements Runnable {
* *
* @param key The selection key which contains the Selector registration information. * @param key The selection key which contains the Selector registration information.
*/ */
private static void read(final SelectionKey key) { private static boolean read(final SelectionKey key) {
final NioDatagramChannel nioDatagramChannel = (NioDatagramChannel) key final NioDatagramChannel channel = (NioDatagramChannel) key.attachment();
.attachment(); ReceiveBufferSizePredictor predictor =
channel.getConfig().getReceiveBufferSizePredictor();
final DatagramChannel datagramChannel = (DatagramChannel) key.channel(); final DatagramChannel nioChannel = (DatagramChannel) key.channel();
// Allocating a non-direct buffer with a max udp packge size.
// Would using a direct buffer be more efficient or would this negatively
// effect performance, as direct buffer allocation has a higher upfront cost
// where as a ByteBuffer is heap allocated.
final ByteBuffer byteBuffer = ByteBuffer.allocate(predictor.nextReceiveBufferSize());
boolean failure = true;
SocketAddress remoteAddress = null;
try { try {
// Allocating a non-direct buffer with a max udp packge size. // Receive from the channel in a non blocking mode. We have already been notified that
// Would using a direct buffer be more efficient or would this negatively
// effect performance, as direct buffer allocation has a higher upfront cost
// where as a ByteBuffer is heap allocated.
final ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
// Recieve from the channel in a non blocking mode. We have already been notified that
// the channel is ready to receive. // the channel is ready to receive.
final SocketAddress remoteAddress = datagramChannel remoteAddress = nioChannel.receive(byteBuffer);
.receive(byteBuffer); failure = false;
} catch (AsynchronousCloseException e) {
// Can happen, and does not need a user attention.
} catch (Throwable t) {
fireExceptionCaught(channel, t);
}
if (remoteAddress != null) {
// Flip the buffer so that we can wrap it. // Flip the buffer so that we can wrap it.
byteBuffer.flip(); byteBuffer.flip();
// Create a Netty ChannelByffer by wrapping the ByteBuffer.
final ChannelBuffer channelBuffer = ChannelBuffers
.wrappedBuffer(byteBuffer);
logger.debug("ChannelBuffer : " + channelBuffer + int readBytes = byteBuffer.remaining();
", remoteAdress: " + remoteAddress); if (readBytes > 0) {
// Update the predictor.
predictor.previousReceiveBufferSize(readBytes);
// Notify the interested parties about the newly arrived message (channelBuffer). // Create a Netty ChannelByffer by wrapping the ByteBuffer.
fireMessageReceived(nioDatagramChannel, channelBuffer, final ChannelBuffer channelBuffer = ChannelBuffers
remoteAddress); .wrappedBuffer(byteBuffer);
} catch (final Throwable t) {
if (!nioDatagramChannel.getDatagramChannel().socket().isClosed()) { // Notify the interested parties about the newly arrived message (channelBuffer).
fireExceptionCaught(nioDatagramChannel, t); fireMessageReceived(channel, channelBuffer,
remoteAddress);
} }
} }
if (failure) {
close(key);
return false;
}
return true;
} }
private static void close(SelectionKey k) { private static void close(SelectionKey k) {
@ -393,7 +409,7 @@ class NioUdpWorker implements Runnable {
/* /*
* Note that we are not checking if the channel is connected. Connected has a different * Note that we are not checking if the channel is connected. Connected has a different
* meaning in UDP and means that the channels socket is configured to only send and * meaning in UDP and means that the channels socket is configured to only send and
* recieve from a given remote peer. * receive from a given remote peer.
*/ */
if (!channel.isOpen()) { if (!channel.isOpen()) {
cleanUpWriteBuffer(channel); cleanUpWriteBuffer(channel);
@ -444,7 +460,6 @@ class NioUdpWorker implements Runnable {
MessageEvent evt; MessageEvent evt;
ChannelBuffer buf; ChannelBuffer buf;
int bufIdx;
int writtenBytes = 0; int writtenBytes = 0;
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue; Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
@ -465,33 +480,30 @@ class NioUdpWorker implements Runnable {
} }
buf = (ChannelBuffer) evt.getMessage(); buf = (ChannelBuffer) evt.getMessage();
bufIdx = buf.readerIndex();
} else { } else {
buf = (ChannelBuffer) evt.getMessage(); buf = (ChannelBuffer) evt.getMessage();
bufIdx = channel.currentWriteIndex;
} }
try { try {
int localWrittenBytes = 0;
for (int i = writeSpinCount; i > 0; i --) { for (int i = writeSpinCount; i > 0; i --) {
ChannelBuffer buffer = (ChannelBuffer) evt.getMessage(); localWrittenBytes =
int localWrittenBytes = channel.getDatagramChannel() channel.getDatagramChannel().send(
.send(buffer.toByteBuffer(), buf.toByteBuffer(),
evt.getRemoteAddress()); evt.getRemoteAddress());
if (localWrittenBytes != 0) { if (localWrittenBytes != 0) {
bufIdx += localWrittenBytes;
writtenBytes += localWrittenBytes; writtenBytes += localWrittenBytes;
break; break;
} }
} }
if (bufIdx == buf.writerIndex()) { if (localWrittenBytes > 0) {
// Successful write - proceed to the next message. // Successful write - proceed to the next message.
evt.getFuture().setSuccess(); evt.getFuture().setSuccess();
evt = null; evt = null;
} else { } else {
// Not written fully - perhaps the kernel buffer is full. // Not written at all - perhaps the kernel buffer is full.
channel.currentWriteEvent = evt; channel.currentWriteEvent = evt;
channel.currentWriteIndex = bufIdx;
addOpWrite = true; addOpWrite = true;
break; break;
} }
@ -590,7 +602,7 @@ class NioUdpWorker implements Runnable {
key.cancel(); key.cancel();
} }
boolean connected = channel.isOpen(); boolean connected = channel.isConnected();
boolean bound = channel.isBound(); boolean bound = channel.isBound();
try { try {
channel.getDatagramChannel().close(); channel.getDatagramChannel().close();
@ -615,33 +627,46 @@ class NioUdpWorker implements Runnable {
} }
private static void cleanUpWriteBuffer(final NioDatagramChannel channel) { private static void cleanUpWriteBuffer(final NioDatagramChannel channel) {
// Create the exception only once to avoid the excessive overhead Exception cause = null;
// caused by fillStackTrace.
Exception cause;
if (channel.isOpen()) {
cause = new NotYetConnectedException();
} else {
cause = new ClosedChannelException();
}
// Clean up the stale messages in the write buffer. // Clean up the stale messages in the write buffer.
synchronized (channel.writeLock) { synchronized (channel.writeLock) {
MessageEvent evt = channel.currentWriteEvent; MessageEvent evt = channel.currentWriteEvent;
if (evt != null) { if (evt != null) {
channel.currentWriteEvent = 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); evt.getFuture().setFailure(cause);
fireExceptionCaught(channel, cause); fireExceptionCaught(channel, cause);
} }
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue; Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
for (;;) { if (!writeBuffer.isEmpty()) {
evt = writeBuffer.poll(); // Create the exception only once to avoid the excessive overhead
if (evt == null) { // caused by fillStackTrace.
break; 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(channel, cause);
} }
evt.getFuture().setFailure(cause);
fireExceptionCaught(channel, cause);
} }
} }
} }
@ -767,6 +792,7 @@ class NioUdpWorker implements Runnable {
throw new ChannelException( throw new ChannelException(
"Failed to register a socket to the selector.", e); "Failed to register a socket to the selector.", e);
} }
// XXX
fireChannelConnected(channel, localAddress); fireChannelConnected(channel, localAddress);
} }
} }

View File

@ -29,8 +29,7 @@ import java.net.DatagramPacket;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
@ -39,8 +38,6 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
/** /**
* Unit test for {@link NioDatagramChannel}
*
* @author The Netty Project (netty-dev@lists.jboss.org) * @author The Netty Project (netty-dev@lists.jboss.org)
* @author Daniel Bevenius (dbevenius@jboss.com) * @author Daniel Bevenius (dbevenius@jboss.com)
* @version $Rev$, $Date$ * @version $Rev$, $Date$
@ -54,7 +51,7 @@ public class NioDatagramChannelTest {
public static void setupChannel() { public static void setupChannel() {
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory( final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
Executors.newCachedThreadPool()); Executors.newCachedThreadPool());
final ServerBootstrap sb = new ServerBootstrap(channelFactory); final ConnectionlessBootstrap sb = new ConnectionlessBootstrap(channelFactory);
inetSocketAddress = new InetSocketAddress("localhost", 9999); inetSocketAddress = new InetSocketAddress("localhost", 9999);
sc = sb.bind(inetSocketAddress); sc = sb.bind(inetSocketAddress);
final SimpleHandler handler = new SimpleHandler(); final SimpleHandler handler = new SimpleHandler();
@ -85,7 +82,7 @@ public class NioDatagramChannelTest {
public void clientBootstrap() { public void clientBootstrap() {
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory( final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
Executors.newCachedThreadPool()); Executors.newCachedThreadPool());
final ClientBootstrap bootstrap = new ClientBootstrap(channelFactory); final ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(channelFactory);
bootstrap.getPipeline().addLast("test", new SimpleHandler()); bootstrap.getPipeline().addLast("test", new SimpleHandler());
bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true); bootstrap.setOption("keepAlive", true);