users@grizzly.java.net

Re: Having trouble with ZipException/File Descriptor leak in Grizzly

From: Marc Novakouski <mnovakouski_at_gmail.com>
Date: Tue, 21 Apr 2009 13:56:26 -0400

Hi Jeanfrancois,

On Tue, Apr 21, 2009 at 1:16 PM, Bill Simons <bill.simons_at_gmail.com> wrote:

> ---------- Forwarded message ----------
> From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_sun.com>
> Date: Tue, Apr 21, 2009 at 11:30 AM
> Subject: Re: Having trouble with ZipException/File Descriptor leak in
> Grizzly
> To: users_at_grizzly.dev.java.net
>
>
> Salut,
>
> Bill Simons wrote:
> >
> > Continuing this thread:
> > http://forums.java.net/jive/thread.jspa?threadID=60501&tstart=0
> >
> > We have two filters in the chain:
> >
> > public class GameProtocolFilter extends ParserProtocolFilter {
> >
> > private GameProtocolParser gameProtocolParser;
> >
> > public GameProtocolFilter(GameProtocolParser gpp) {
> > super();
> > this.gameProtocolParser = gpp;
> > }
> >
> > public ProtocolParser newProtocolParser() {
> > return new ProtocolParser() {
> >
> > private ByteBuffer buffer = null;
> > private boolean expectingMoreData = false;
> > private boolean hasMoreBytesToParse = false;
> > private Action action = null;
> >
> > public boolean isExpectingMoreData() {
> > return expectingMoreData;
> > }
> >
> > public boolean hasMoreBytesToParse() {
> > return hasMoreBytesToParse;
> > }
> >
> > public Object getNextMessage() {
> > return action;
> > }
> >
> > public boolean hasNextMessage() {
> > if (buffer == null) {
> > return false;
> > }
> >
> > ByteBuffer dup = buffer.duplicate();
> >
> > if (buffer.position() == 0) {
> > expectingMoreData = true;
> > return false;
> > }
> >
> > dup.flip();
> > if (dup.remaining() < 4) {
> > expectingMoreData = true;
> > return false;
> > }
> > int size = dup.getInt();
> > if (size == 0 || dup.remaining() < size) {
> > expectingMoreData = true;
> > return false;
> > }
> >
> > byte typeByte = dup.get();
> > dup.position(0);
> > byte[] testData = new byte[size + 4];
> > dup.get(testData);
> >
> > action = gameProtocolParser.parseAction(typeByte,
> testData);
> >
> > hasMoreBytesToParse = dup.hasRemaining();
> > return (action != null);
> > }
> >
> > public void startBuffer(ByteBuffer byteBuffer) {
> > buffer = byteBuffer;
> > }
> >
> > public boolean releaseBuffer() {
> > buffer = null;
> > action = null;
> > expectingMoreData = false;
> > hasMoreBytesToParse = false;
> > return false;
> > }
> > };
> > }
> > }
> >
> >
> > The next filter in our chain dispatches the parsed message to another
> > thread pool:
> > public boolean execute(Context ctx) throws IOException {
> > final Action action = (Action)
> > ctx.removeAttribute(ProtocolParser.MESSAGE);
> > final Context workerContext = ctx;
> > ctx.incrementRefCount();
> > executorService.execute(new Runnable() {
> > public void run() {
> > action.handle(handler, workerContext);
> >
> workerContext.getController().returnContext(workerContext);
> > }
> > });
> > return false;
> > }
> >
> > I think these are pretty straightforward but maybe we're missing some
> > fundamental?
>
> Right, I don't see any issue with the above code except it seems the
> SelectionKey are never set to be canceled like:
>
> ctx.setKeyRegistrationState(
> Context.KeyRegistrationState.CANCEL);
>
> Can you gives more information on how the server is stressed (the tool
> used). Would you be able to share a test case (privately if that
> help). Also, when the exception happens, can you grab a netstat -an |
> grep <port-used>?
>
> Thanks!
>
> -- Jeanfrancois


We stress the server with a custom tool which does the following:
1. The tool creates 50 threads.
2. Each thread opens one SocketChannel to the server and begins
communication.
Note 1: The tool is run on a different computer than the server, so the
communication is over the network instead of local.
3. After roughly 200-300 message/response actions (client thread sends
message, server responds), the thread finishes execution and exits.
Note 2: There is no close operation currently performed when the thread
exits
4. The tool performs steps 1-3 repeatedly until either 2000 threads have run
successfully or the server is unable to finish serving requests for the
existing threads.

The failure case we've observed is that somewhere either in the execution of
threads 850-900 or 900-950 the server starts spewing the aforementioned
error to the log until we run out of disk space.

I'm running the test now, it takes a little while to get to the failure
state. When I see the error occur I'll run the netstat and let you know.

Thanks for your help!



>
>
>
> >
> > We're using a grizzly controller with a DefaultPipeline and
> > BaseSelectionKeyHandler.
> >
> > Thanks for your help.
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> > For additional commands, e-mail: users-help_at_grizzly.dev.java.net
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>