Synchronized between 4.1 and master

Motivation:

4 and 5 were diverged long time ago and we recently reverted some of the
early commits in master.  We must make sure 4.1 and master are not very
different now.

Modification:

Fix found differences

Result:

4.1 and master got closer.
This commit is contained in:
Norman Maurer 2014-04-24 20:47:26 +02:00
parent d2614cfc01
commit 7fa861ab70
4 changed files with 76 additions and 59 deletions

View File

@ -36,6 +36,7 @@ import java.util.NoSuchElementException;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/** /**
* The default {@link ChannelPipeline} implementation. It is usually created * The default {@link ChannelPipeline} implementation. It is usually created
@ -49,10 +50,21 @@ final class DefaultChannelPipeline implements ChannelPipeline {
private static final WeakHashMap<Class<?>, String>[] nameCaches = private static final WeakHashMap<Class<?>, String>[] nameCaches =
new WeakHashMap[Runtime.getRuntime().availableProcessors()]; new WeakHashMap[Runtime.getRuntime().availableProcessors()];
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<DefaultChannelPipeline, Map> childInvokersUpdater;
static { static {
for (int i = 0; i < nameCaches.length; i ++) { for (int i = 0; i < nameCaches.length; i ++) {
nameCaches[i] = new WeakHashMap<Class<?>, String>(); nameCaches[i] = new WeakHashMap<Class<?>, String>();
} }
@SuppressWarnings("rawtypes")
AtomicReferenceFieldUpdater<DefaultChannelPipeline, Map> updater;
updater = PlatformDependent.newAtomicReferenceFieldUpdater(DefaultChannelPipeline.class, "childInvokers");
if (updater == null) {
updater = AtomicReferenceFieldUpdater.newUpdater(DefaultChannelPipeline.class, Map.class, "childInvokers");
}
childInvokersUpdater = updater;
} }
final AbstractChannel channel; final AbstractChannel channel;
@ -63,10 +75,15 @@ final class DefaultChannelPipeline implements ChannelPipeline {
private final Map<String, DefaultChannelHandlerContext> name2ctx = private final Map<String, DefaultChannelHandlerContext> name2ctx =
new HashMap<String, DefaultChannelHandlerContext>(4); new HashMap<String, DefaultChannelHandlerContext>(4);
final Map<EventExecutorGroup, ChannelHandlerInvoker> childInvokers = /**
new IdentityHashMap<EventExecutorGroup, ChannelHandlerInvoker>(); * Updated by {@link #childInvokersUpdater}.
*
* @see #findInvoker(EventExecutorGroup)
*/
@SuppressWarnings("UnusedDeclaration")
private volatile Map<EventExecutorGroup, ChannelHandlerInvoker> childInvokers;
public DefaultChannelPipeline(AbstractChannel channel) { DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) { if (channel == null) {
throw new NullPointerException("channel"); throw new NullPointerException("channel");
} }
@ -101,13 +118,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
public ChannelPipeline addFirst(ChannelHandlerInvoker invoker, final String name, ChannelHandler handler) { public ChannelPipeline addFirst(ChannelHandlerInvoker invoker, final String name, ChannelHandler handler) {
synchronized (this) { synchronized (this) {
checkDuplicateName(name); checkDuplicateName(name);
addFirst0(name, new DefaultChannelHandlerContext(this, invoker, name, handler));
DefaultChannelHandlerContext newCtx =
new DefaultChannelHandlerContext(this, invoker, name, handler);
addFirst0(name, newCtx);
} }
return this; return this;
} }
@ -139,13 +151,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
public ChannelPipeline addLast(ChannelHandlerInvoker invoker, final String name, ChannelHandler handler) { public ChannelPipeline addLast(ChannelHandlerInvoker invoker, final String name, ChannelHandler handler) {
synchronized (this) { synchronized (this) {
checkDuplicateName(name); checkDuplicateName(name);
addLast0(name, new DefaultChannelHandlerContext(this, invoker, name, handler));
DefaultChannelHandlerContext newCtx =
new DefaultChannelHandlerContext(this, invoker, name, handler);
addLast0(name, newCtx);
} }
return this; return this;
} }
@ -178,13 +185,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
ChannelHandlerInvoker invoker, String baseName, final String name, ChannelHandler handler) { ChannelHandlerInvoker invoker, String baseName, final String name, ChannelHandler handler) {
synchronized (this) { synchronized (this) {
DefaultChannelHandlerContext ctx = getContextOrDie(baseName); DefaultChannelHandlerContext ctx = getContextOrDie(baseName);
checkDuplicateName(name); checkDuplicateName(name);
addBefore0(name, ctx, new DefaultChannelHandlerContext(this, invoker, name, handler));
DefaultChannelHandlerContext newCtx =
new DefaultChannelHandlerContext(this, invoker, name, handler);
addBefore0(name, ctx, newCtx);
} }
return this; return this;
} }
@ -217,15 +219,9 @@ final class DefaultChannelPipeline implements ChannelPipeline {
ChannelHandlerInvoker invoker, String baseName, final String name, ChannelHandler handler) { ChannelHandlerInvoker invoker, String baseName, final String name, ChannelHandler handler) {
synchronized (this) { synchronized (this) {
DefaultChannelHandlerContext ctx = getContextOrDie(baseName); DefaultChannelHandlerContext ctx = getContextOrDie(baseName);
checkDuplicateName(name); checkDuplicateName(name);
addAfter0(name, ctx, new DefaultChannelHandlerContext(this, invoker, name, handler));
DefaultChannelHandlerContext newCtx =
new DefaultChannelHandlerContext(this, invoker, name, handler);
addAfter0(name, ctx, newCtx);
} }
return this; return this;
} }
@ -308,17 +304,29 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return null; return null;
} }
// Pin one of the child executors once and remember it so that the same child executor // Lazily initialize the data structure that maps an EventExecutorGroup to a ChannelHandlerInvoker.
// is used to fire events for the same channel. Map<EventExecutorGroup, ChannelHandlerInvoker> childInvokers = this.childInvokers;
ChannelHandlerInvoker invoker = childInvokers.get(group); if (childInvokers == null) {
if (invoker == null) { childInvokers = new IdentityHashMap<EventExecutorGroup, ChannelHandlerInvoker>();
EventExecutor executor = group.next(); if (!childInvokersUpdater.compareAndSet(this, null, childInvokers)) {
if (executor instanceof EventLoop) { childInvokers = this.childInvokers;
invoker = ((EventLoop) executor).asInvoker(); }
} else { }
invoker = new DefaultChannelHandlerInvoker(executor);
// Pick one of the child executors and remember its invoker
// so that the same invoker is used to fire events for the same channel.
ChannelHandlerInvoker invoker;
synchronized (childInvokers) {
invoker = childInvokers.get(group);
if (invoker == null) {
EventExecutor executor = group.next();
if (executor instanceof EventLoop) {
invoker = ((EventLoop) executor).asInvoker();
} else {
invoker = new DefaultChannelHandlerInvoker(executor);
}
childInvokers.put(group, invoker);
} }
childInvokers.put(group, invoker);
} }
return invoker; return invoker;
@ -550,7 +558,6 @@ final class DefaultChannelPipeline implements ChannelPipeline {
try { try {
ctx.handler().handlerAdded(ctx); ctx.handler().handlerAdded(ctx);
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace();
boolean removed = false; boolean removed = false;
try { try {
remove(ctx); remove(ctx);
@ -936,7 +943,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelFuture deregister(ChannelPromise promise) { public ChannelFuture deregister(ChannelPromise promise) {
return tail.close(promise); return tail.deregister(promise);
} }
@Override @Override
@ -1043,9 +1050,9 @@ final class DefaultChannelPipeline implements ChannelPipeline {
static final class HeadHandler extends ChannelHandlerAdapter { static final class HeadHandler extends ChannelHandlerAdapter {
protected final Unsafe unsafe; private final Unsafe unsafe;
protected HeadHandler(Unsafe unsafe) { HeadHandler(Unsafe unsafe) {
this.unsafe = unsafe; this.unsafe = unsafe;
} }

View File

@ -109,14 +109,27 @@ public final class NioDatagramChannel
this(newSocket(DEFAULT_SELECTOR_PROVIDER)); this(newSocket(DEFAULT_SELECTOR_PROVIDER));
} }
/**
* Create a new instance using the given {@link SelectorProvider}
* which will use the Operation Systems default {@link InternetProtocolFamily}.
*/
public NioDatagramChannel(SelectorProvider provider) {
this(newSocket(provider));
}
/** /**
* Create a new instance using the given {@link InternetProtocolFamily}. If {@code null} is used it will depend * Create a new instance using the given {@link InternetProtocolFamily}. If {@code null} is used it will depend
* on the Operation Systems default which will be chosen. * on the Operation Systems default which will be chosen.
*/ */
public NioDatagramChannel(InternetProtocolFamily ipFamily) { public NioDatagramChannel(InternetProtocolFamily ipFamily) {
this(DEFAULT_SELECTOR_PROVIDER, ipFamily); this(newSocket(DEFAULT_SELECTOR_PROVIDER, ipFamily));
} }
/**
* Create a new instance using the given {@link SelectorProvider} and {@link InternetProtocolFamily}.
* If {@link InternetProtocolFamily} is {@code null} it will depend on the Operation Systems default
* which will be chosen.
*/
public NioDatagramChannel(SelectorProvider provider, InternetProtocolFamily ipFamily) { public NioDatagramChannel(SelectorProvider provider, InternetProtocolFamily ipFamily) {
this(newSocket(provider, ipFamily)); this(newSocket(provider, ipFamily));
} }

View File

@ -67,11 +67,21 @@ public class NioServerSocketChannel extends AbstractNioMessageChannel
* Create a new instance * Create a new instance
*/ */
public NioServerSocketChannel() { public NioServerSocketChannel() {
this(DEFAULT_SELECTOR_PROVIDER); this(newSocket(DEFAULT_SELECTOR_PROVIDER));
} }
/**
* Create a new instance using the given {@link SelectorProvider}.
*/
public NioServerSocketChannel(SelectorProvider provider) { public NioServerSocketChannel(SelectorProvider provider) {
super(null, newSocket(provider), SelectionKey.OP_ACCEPT); this(newSocket(provider));
}
/**
* Create a new instance using the given {@link ServerSocketChannel}.
*/
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket()); config = new NioServerSocketChannelConfig(this, javaChannel().socket());
} }

View File

@ -23,8 +23,6 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.local.LocalChannel; import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalServerChannel; import io.netty.channel.local.LocalServerChannel;
import java.io.UnsupportedEncodingException;
import static org.junit.Assert.*; import static org.junit.Assert.*;
class BaseChannelTest { class BaseChannelTest {
@ -66,18 +64,6 @@ class BaseChannelTest {
return buf; return buf;
} }
static Object createTestBuf(String string) throws UnsupportedEncodingException {
byte[] buf = string.getBytes("US-ASCII");
return createTestBuf(buf);
}
static Object createTestBuf(byte[] buf) {
ByteBuf ret = createTestBuf(buf.length);
ret.clear();
ret.writeBytes(buf);
return ret;
}
void assertLog(String expected) { void assertLog(String expected) {
String actual = loggingHandler.getLog(); String actual = loggingHandler.getLog();
assertEquals(expected, actual); assertEquals(expected, actual);
@ -90,4 +76,5 @@ class BaseChannelTest {
void setInterest(LoggingHandler.Event... events) { void setInterest(LoggingHandler.Event... events) {
loggingHandler.setInterest(events); loggingHandler.setInterest(events);
} }
} }