diff --git a/src/main/java/org/jboss/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java b/src/main/java/org/jboss/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java index bfdd9fe28a..d144e377be 100644 --- a/src/main/java/org/jboss/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java +++ b/src/main/java/org/jboss/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java @@ -23,6 +23,7 @@ package org.jboss.netty.handler.execution; import java.util.LinkedList; +import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; @@ -68,6 +69,58 @@ import org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; * If you want the events associated with the same channel to be executed * simultaneously, please use {@link MemoryAwareThreadPoolExecutor} instead. * + *
+ * {@link OrderedMemoryAwareThreadPoolExecutor} uses a {@link Channel} as a key + * that is used for maintaining the event execution order, as explained in the + * previous section. Alternatively, you can extend it to change its behavior. + * For example, you can change the key to the remote IP of the peer: + * + *
+ * public class RemoteAddressBasedOMATPE extends OrderedMemoryAwareThreadPoolExecutor { + * ... Constructors ... + * + * protected ConcurrentMap<Object, Executor> new ChildExecutorMap() { + * // The default implementation returns a special ConcurrentMap that + * // is optimized for the case where the key is Channel, so we need to + * // provide more generic implementation. + * return new ConcurrentHashMap<Object, Executor> + * } + * + * protected Object getChildExecutorKey(ChannelEvent e) { + * // Use the IP of the remote peer as a key. + * return ((InetSocketAddress) e.getChannel().getRemoteAddress()).getAddress(); + * } + * + * // Make public so that you can call from anywhere. + * public boolean removeChildExecutor(Object key) { + * super.removeChildExecutor(key); + * } + * } + *+ * + * Please be very careful of memory leak of the child executor map. You must + * call {@link #removeChildExecutor(Object)} when the life cycle of the key + * ends (e.g. all connections from the same IP were closed.) Also, please + * keep in mind that the key can appear again after calling {@link #removeChildExecutor(Object)} + * (e.g. a new connection could come in from the old IP.) If in doubt, prune + * the old unused keys from the child executor map periodically: + * + *
+ * RemoteAddressBasedOMATPE executor = ...; + * + * on every 3 seconds: + * + * for (Object key: executor.getChildExecutorKeySet()) { + * InetAddress ip = (InetAddress) key; + * if (there is no active connection from 'ip' now && + * there has been no incoming connection from 'ip' for last 10 minutes) { + * + * executor.removeChildExecutor(key); + * } + * } + *+ * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @author David M. Lloyd (david.lloyd@redhat.com) @@ -161,6 +214,10 @@ public class OrderedMemoryAwareThreadPoolExecutor extends return e.getChannel(); } + protected Set