Resolved issue: NETTY-84 Replace ChannelFactory.getExternalResource() with ChannelFactory.releaseExternalResources()

This commit is contained in:
Trustin Lee 2008-11-28 11:18:21 +00:00
parent 3e09a4ee60
commit 0830444fc8
17 changed files with 80 additions and 139 deletions

View File

@ -103,7 +103,7 @@ import org.jboss.netty.channel.SimpleChannelHandler;
* {@link ClientBootstrap} instances as you want to apply different settings
* for different {@link Channel}s.
*
* TODO: Show how to shut down a service using ChannelFactoryResource.release().
* TODO: Show how to shut down a service.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)

View File

@ -137,7 +137,7 @@ import org.jboss.netty.channel.SimpleChannelHandler;
* {@link ServerBootstrap} instances as you want to apply different settings
* for different {@link Channel}s.
*
* TODO: Show how to shut down a service using ChannelFactoryResource.release().
* TODO: Show how to shut down a service.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)

View File

@ -22,6 +22,8 @@
*/
package org.jboss.netty.channel;
import java.util.concurrent.Executor;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
@ -36,7 +38,17 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
* is attached to the new {@link Channel}, and starts to handle all associated
* {@link ChannelEvent}s.
*
* TODO: Document how to shut down a service using ChannelFactoryResource.
* <h3>Graceful shutdown</h3>
* <p>
* To shut down a network application service which is managed by a factory.
* you should follow the following steps:
* <ol>
* <li>close all channels created by the factory and their child channels, and</li>
* <li>call {@link #releaseExternalResources()}.</li>
* </ol>
* <p>
* For detailed transport-specific information on shutting down a factory,
* please refer to the Javadoc of {@link ChannelFactory}'s subtypes.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
@ -62,12 +74,14 @@ public interface ChannelFactory {
Channel newChannel(ChannelPipeline pipeline);
/**
* Returns the external resources that this factory depends on to function.
* Please note that {@link ChannelFactoryResource#release()} can be called
* to release all external resources conveniently when the resources are not
* used by this factory or any other part of your application.
* An unexpected behavior will be resulted in if the returned resources are
* released when there's an open channel which is managed by this factory.
* Releases the external resources that this factory depends on to function.
* An external resource is a resource that this factory didn't create by
* itself. For example, {@link Executor}s that you specified in the factory
* constructor are external resources. You can call this method to release
* all external resources conveniently when the resources are not used by
* this factory or any other part of your application. An unexpected
* behavior will be resulted in if the resources are released when there's
* an open channel which is managed by this factory.
*/
ChannelFactoryResource getExternalResource();
void releaseExternalResources();
}

View File

@ -1,45 +0,0 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.channel;
import java.util.concurrent.ExecutorService;
/**
* The abstract representation of external resources that a
* {@link ChannelFactory} depends on. A user can release the external
* resources such as {@link ExecutorService}s conveniently.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
* @apiviz.exclude
*/
public interface ChannelFactoryResource {
/**
* Releases this resource.
*/
void release();
}

View File

@ -44,8 +44,8 @@ class DefaultNioSocketChannelConfig extends DefaultSocketChannelConfig
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(DefaultNioSocketChannelConfig.class);
private volatile int writeBufferHighWaterMark = 256 * 1024;
private volatile int writeBufferLowWaterMark = 128 * 1024;
private volatile int writeBufferHighWaterMark = 64 * 1024;
private volatile int writeBufferLowWaterMark = 32 * 1024;
private volatile ReceiveBufferSizePredictor predictor =
new DefaultReceiveBufferSizePredictor();
private volatile int writeSpinCount = 16;

View File

@ -24,18 +24,15 @@ package org.jboss.netty.channel.socket.nio;
import java.nio.channels.Selector;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactoryExecutorResource;
import org.jboss.netty.channel.ChannelFactoryResource;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.SocketChannel;
import org.jboss.netty.util.ExecutorShutdownUtil;
/**
* A {@link ClientSocketChannelFactory} which creates a client-side NIO-based
@ -62,7 +59,6 @@ import org.jboss.netty.channel.socket.SocketChannel;
* more {@link Channel}s in a non-blocking mode.
*
* <h3>Life cycle of threads and graceful shutdown</h3>
* TODO: Rewrite this section to recommend a user to call ChannelFactoryResource.release().
* <p>
* All threads are acquired from the {@link Executor}s which were specified
* when a {@link NioClientSocketChannelFactory} was created. A boss thread is
@ -78,11 +74,8 @@ import org.jboss.netty.channel.socket.SocketChannel;
* following:
*
* <ol>
* <li>close all channels created by the factory,</li>
* <li>call {@link ExecutorService#shutdownNow()} or {@link ExecutorService#shutdown()}
* for all executors which were specified to create the factory, and</li>
* <li>call {@link ExecutorService#awaitTermination(long, TimeUnit)}
* until it returns {@code true}.</li>
* <li>close all channels created by the factory, and</li>
* <li>call {@link #releaseExternalResources()}.</li>
* </ol>
*
* Please make sure not to shut down the executor until all channels are
@ -98,7 +91,8 @@ import org.jboss.netty.channel.socket.SocketChannel;
*/
public class NioClientSocketChannelFactory implements ClientSocketChannelFactory {
private final ChannelFactoryResource externalResource;
private final Executor bossExecutor;
private final Executor workerExecutor;
private final ChannelSink sink;
/**
@ -142,7 +136,8 @@ public class NioClientSocketChannelFactory implements ClientSocketChannelFactory
"must be a positive integer.");
}
externalResource = new ChannelFactoryExecutorResource(bossExecutor, workerExecutor);
this.bossExecutor = bossExecutor;
this.workerExecutor = workerExecutor;
sink = new NioClientSocketPipelineSink(bossExecutor, workerExecutor, workerCount);
}
@ -150,7 +145,7 @@ public class NioClientSocketChannelFactory implements ClientSocketChannelFactory
return new NioClientSocketChannel(this, pipeline, sink);
}
public ChannelFactoryResource getExternalResource() {
return externalResource;
public void releaseExternalResources() {
ExecutorShutdownUtil.shutdown(bossExecutor, workerExecutor);
}
}

View File

@ -24,18 +24,15 @@ package org.jboss.netty.channel.socket.nio;
import java.nio.channels.Selector;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactoryExecutorResource;
import org.jboss.netty.channel.ChannelFactoryResource;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.socket.ServerSocketChannel;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
import org.jboss.netty.util.ExecutorShutdownUtil;
/**
* A {@link ServerSocketChannelFactory} which creates a server-side NIO-based
@ -64,7 +61,6 @@ import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
* more {@link Channel}s in a non-blocking mode.
*
* <h3>Life cycle of threads and graceful shutdown</h3>
* TODO: Rewrite this section to recommend a user to call ChannelFactoryResource.release().
* <p>
* All threads are acquired from the {@link Executor}s which were specified
* when a {@link NioServerSocketChannelFactory} was created. Boss threads are
@ -81,11 +77,8 @@ import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
*
* <ol>
* <li>unbind all channels created by the factory,
* <li>close all child channels accepted by the unbound channels,</li>
* <li>call {@link ExecutorService#shutdownNow()} or {@link ExecutorService#shutdown()}
* for all executors which were specified to create the factory, and</li>
* <li>call {@link ExecutorService#awaitTermination(long, TimeUnit)}
* until it returns {@code true}.</li>
* <li>close all child channels accepted by the unbound channels, and</li>
* <li>call {@link #releaseExternalResources()}.</li>
* </ol>
*
* Please make sure not to shut down the executor until all channels are
@ -102,7 +95,7 @@ import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
public class NioServerSocketChannelFactory implements ServerSocketChannelFactory {
final Executor bossExecutor;
private final ChannelFactoryResource externalResource;
private final Executor workerExecutor;
private final ChannelSink sink;
/**
@ -146,7 +139,7 @@ public class NioServerSocketChannelFactory implements ServerSocketChannelFactory
"must be a positive integer.");
}
this.bossExecutor = bossExecutor;
externalResource = new ChannelFactoryExecutorResource(bossExecutor, workerExecutor);
this.workerExecutor = workerExecutor;
sink = new NioServerSocketPipelineSink(workerExecutor, workerCount);
}
@ -154,7 +147,7 @@ public class NioServerSocketChannelFactory implements ServerSocketChannelFactory
return new NioServerSocketChannel(this, pipeline, sink);
}
public ChannelFactoryResource getExternalResource() {
return externalResource;
public void releaseExternalResources() {
ExecutorShutdownUtil.shutdown(bossExecutor, workerExecutor);
}
}

View File

@ -23,16 +23,13 @@
package org.jboss.netty.channel.socket.oio;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactoryExecutorResource;
import org.jboss.netty.channel.ChannelFactoryResource;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.SocketChannel;
import org.jboss.netty.util.ExecutorShutdownUtil;
/**
* A {@link ClientSocketChannelFactory} which creates a client-side blocking
@ -51,7 +48,6 @@ import org.jboss.netty.channel.socket.SocketChannel;
* traditional blocking I/O thread model.
*
* <h3>Life cycle of threads and graceful shutdown</h3>
* TODO: Rewrite this section to recommend a user to call ChannelFactoryResource.release().
* <p>
* Worker threads are acquired from the {@link Executor} which was specified
* when a {@link OioClientSocketChannelFactory} was created (i.e. {@code workerExecutor}.)
@ -64,11 +60,8 @@ import org.jboss.netty.channel.socket.SocketChannel;
* you should do the following:
*
* <ol>
* <li>close all channels created by the factory,</li>
* <li>call {@link ExecutorService#shutdownNow()} for the executor which was
* specified to create the factory, and</li>
* <li>call {@link ExecutorService#awaitTermination(long, TimeUnit)}
* until it returns {@code true}.</li>
* <li>close all channels created by the factory, and</li>
* <li>call {@link #releaseExternalResources()}.</li>
* </ol>
*
* Please make sure not to shut down the executor until all channels are
@ -90,7 +83,7 @@ import org.jboss.netty.channel.socket.SocketChannel;
*/
public class OioClientSocketChannelFactory implements ClientSocketChannelFactory {
private final ChannelFactoryResource externalResource;
private final Executor workerExecutor;
final OioClientSocketPipelineSink sink;
/**
@ -103,7 +96,7 @@ public class OioClientSocketChannelFactory implements ClientSocketChannelFactory
if (workerExecutor == null) {
throw new NullPointerException("workerExecutor");
}
externalResource = new ChannelFactoryExecutorResource(workerExecutor);
this.workerExecutor = workerExecutor;
sink = new OioClientSocketPipelineSink(workerExecutor);
}
@ -111,7 +104,7 @@ public class OioClientSocketChannelFactory implements ClientSocketChannelFactory
return new OioClientSocketChannel(this, pipeline, sink);
}
public ChannelFactoryResource getExternalResource() {
return externalResource;
public void releaseExternalResources() {
ExecutorShutdownUtil.shutdown(workerExecutor);
}
}

View File

@ -28,12 +28,11 @@ import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactoryExecutorResource;
import org.jboss.netty.channel.ChannelFactoryResource;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.socket.ServerSocketChannel;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
import org.jboss.netty.util.ExecutorShutdownUtil;
/**
* A {@link ServerSocketChannelFactory} which creates a server-side blocking
@ -61,7 +60,6 @@ import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
* traditional blocking I/O thread model.
*
* <h3>Life cycle of threads and graceful shutdown</h3>
* TODO: Rewrite this section to recommend a user to call ChannelFactoryResource.release().
* <p>
* All threads are acquired from the {@link Executor}s which were specified
* when a {@link OioServerSocketChannelFactory} was created. Boss threads are
@ -103,7 +101,7 @@ import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
public class OioServerSocketChannelFactory implements ServerSocketChannelFactory {
final Executor bossExecutor;
private final ChannelFactoryResource externalResource;
private final Executor workerExecutor;
private final ChannelSink sink;
/**
@ -123,7 +121,7 @@ public class OioServerSocketChannelFactory implements ServerSocketChannelFactory
throw new NullPointerException("workerExecutor");
}
this.bossExecutor = bossExecutor;
externalResource = new ChannelFactoryExecutorResource(bossExecutor, workerExecutor);
this.workerExecutor = workerExecutor;
sink = new OioServerSocketPipelineSink(workerExecutor);
}
@ -131,7 +129,7 @@ public class OioServerSocketChannelFactory implements ServerSocketChannelFactory
return new OioServerSocketChannel(this, pipeline, sink);
}
public ChannelFactoryResource getExternalResource() {
return externalResource;
public void releaseExternalResources() {
ExecutorShutdownUtil.shutdown(bossExecutor, workerExecutor);
}
}

View File

@ -69,6 +69,7 @@ public class DiscardClient {
ClientBootstrap bootstrap = new ClientBootstrap(factory);
DiscardClientHandler handler = new DiscardClientHandler(firstMessageSize);
//bootstrap.getPipeline().addLast("executor", new ExecutionHandler(new MemoryAwareThreadPoolExecutor(16, 0, 0)));
bootstrap.getPipeline().addLast("handler", handler);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
@ -80,6 +81,6 @@ public class DiscardClient {
future.getChannel().getCloseFuture().awaitUninterruptibly();
// Shut down thread pools to exit.
factory.getExternalResource().release();
factory.releaseExternalResources();
}
}

View File

@ -87,6 +87,6 @@ public class FactorialClient {
"Factorial of %,d is: %,d", count, handler.getFactorial());
// Shut down all thread pools to exit.
factory.getExternalResource().release();
factory.releaseExternalResources();
}
}

View File

@ -82,7 +82,7 @@ public class HttpClient {
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
factory.getExternalResource().release();
factory.releaseExternalResources();
return;
}
@ -95,6 +95,6 @@ public class HttpClient {
channel.getCloseFuture().awaitUninterruptibly();
// Shut down executor threads to exit.
factory.getExternalResource().release();
factory.releaseExternalResources();
}
}

View File

@ -78,7 +78,7 @@ public class SecureChatClient {
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
factory.getExternalResource().release();
factory.releaseExternalResources();
return;
}
@ -103,6 +103,6 @@ public class SecureChatClient {
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
factory.getExternalResource().release();
factory.releaseExternalResources();
}
}

View File

@ -76,7 +76,7 @@ public class TelnetClient {
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
factory.getExternalResource();
factory.releaseExternalResources();
return;
}
@ -103,6 +103,6 @@ public class TelnetClient {
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
factory.getExternalResource().release();
factory.releaseExternalResources();
}
}

View File

@ -20,49 +20,37 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.channel;
package org.jboss.netty.util;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
/**
* A {@link ChannelFactoryResource} whose underlying resource is a list of
* {@link Executor}s. {@link #release()} will shut down all specified
* {@link ExecutorService}s immediately and wait for their termination.
* An {@link Executor} which is not an {@link ExecutorService} will be ignored.
* Shuts down a list of {@link Executor}s. {@link #shutdown(Executor...)} will
* shut down all specified {@link ExecutorService}s immediately and wait for
* their termination. An {@link Executor} which is not an {@link ExecutorService}
* will be ignored silently.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
* @version $Rev$, $Date$
*
* @apiviz.exclude
*/
public class ChannelFactoryExecutorResource implements
ChannelFactoryResource {
private final Executor[] executors;
public class ExecutorShutdownUtil {
/**
* Creates a new instance with the specified executors.
*
* @param executors a list of {@link Executor}s
* Shuts down the specified executors.
*/
public ChannelFactoryExecutorResource(Executor... executors) {
if (executors == null) {
throw new NullPointerException("executors");
}
this.executors = new Executor[executors.length];
public static void shutdown(Executor... executors) {
Executor[] executorsCopy = new Executor[executors.length];
for (int i = 0; i < executors.length; i ++) {
if (executors[i] == null) {
throw new NullPointerException("executors[" + i + "]");
}
this.executors[i] = executors[i];
executorsCopy[i] = executors[i];
}
}
public void release() {
for (Executor e: executors) {
for (Executor e: executorsCopy) {
if (!(e instanceof ExecutorService)) {
continue;
}
@ -80,4 +68,8 @@ public class ChannelFactoryExecutorResource implements
}
}
}
private ExecutorShutdownUtil() {
super();
}
}

View File

@ -85,7 +85,7 @@ public class NioClientSocketShutdownTimeTest {
f.getChannel().close().awaitUninterruptibly();
} finally {
b.getFactory().getExternalResource().release();
b.getFactory().releaseExternalResources();
try {
serverSocket.close();

View File

@ -106,7 +106,7 @@ public class NioServerSocketShutdownTimeTest {
}
}
channel.close().awaitUninterruptibly();
bootstrap.getFactory().getExternalResource().release();
bootstrap.getFactory().releaseExternalResources();
}
long shutdownTime = System.currentTimeMillis() - startTime;