users@grizzly.java.net

Re: A correct way of dealing with reads appearing after close

From: Alexei Dets <adets_at_idsk.com>
Date: Mon, 26 Oct 2009 14:20:53 -0400

Hi!
Oleksiy Stashok wrote:
> >> As for memory allocation, ReadFilter tries to use already allocated
> >> buffer, if there is no buffer associated with the current thread - it
> >> really allocates new one. If error occurs during reading bytes from a
> >> channel, the buffer will not be lost, it will be reused during the
> >> next request processing.
> >
> > I think that if you'll get a WorkerThread that is associated with a
> > ThreadAttachment that was reset (in SelectionKeyHandler.cancel) then
> > it'll
> > allocate a new buffer.
> > And after protocol chain execution completes and
> > ParserProtocolFilter attaches ThreadAttachment to SelectionKey in
> > postExecute then ThreadAttachment, SelectionKey, buffer &
> > ProtocolParser
> > will be pending garbage collection. ProtocolParser will be created
> > because
> > ThreadAttachment & SelectionKey were cleared in
> > SelectionKeyHandler.cancel
> > and so ParserProtocolFilter will think that this is a new connection
> > without a protocol parser. BTW, ProtocolParser will also think that
> > this is
> > a new connection and will parse accordingly.
> From you words it definitely looks like a bug!
> Can you pls. just elaborate... As I understand here we're talking
> about situation, when one thread processes parsing, another one is
> doing cancel? Can you pls. provide the steps (one-by-one), when the
> situation above will occur?

Sorry for the long delay, unfortunately some urgent tasks appeared that
require my attention and I was not able to investigate this further :-(
I wanted to write a simple test to illustrate the observed behavior but
don't have enough time right now, sorry :-(

The typical scenario (in our application) is the following: ProtocolParser
in a worker thread parses the data stream and generates parsed protocol
messages that are picked up by the next filter in the chain and processed
in the same thread or, more frequently, asynchronously, in another thread.
Response (if any) is sent asynchronously using AsyncQueueWriter and usually
key is cancelled from AsyncWriteCallbackHandler.onWriteCompleted (it can
also be cancelled from the message processing thread, from the worker
thread or during processing of expired keys).

The problem is that SelectionKeyHandler.cancel destroys any information
about connect (resets ThreadAttachment and sets key attachment to null) so
if protocol chain is re-invoked again and ReadFilter is not invoked (that
will stop the processing on read error) then filters will not be able to
find out what connection they are dealing with (no connection information
remains) and in general will treat it as a fresh connection without buffer,
associated parser etc. and will re-create them. I'm not 100% sure that
buffer is always re-created but protocol parser is. Or processing can just
fail with unexpected exception, usually NullPointerException or
ConcurrentModificationException, if cancelation is going on in exactly the
same time as protocol chain invocation.

An additional problem is that if due to this unexpected close parser fails
then application can't even log anything usefull because connection context
information is gone. The same is parsing successfully completed and parsed
message is ready to be delivered - there is no way to know where it should
be delivered to. Now, I can ignore all exceptions in the protocol chain
(and have problems hiding real errors if they appear) or always log useless
warnings :-(

        Alexei