users@grizzly.java.net

Re: Threading and invocation of Filter.handleXXX methods

From: Oleksiy Stashok <oleksiy.stashok_at_oracle.com>
Date: Wed, 13 Oct 2010 13:05:39 +0200

Hi Matt,

> Basically, in my dumb proxy example, it listens for incoming client
> connections and, on connect, it creates an associated connection
> between the proxy and the remote server. I am creating the
> connection synchronously from within the
> Filter.handleAccept(FilterChainContext) method. Unfortunately my
> example self-deadlocks because the handleAccept method is being
> invoked by a SelectorRunner and the Future that is returned from the
> connection attempt can never be closed, because the selector needs
> to run in order to close it (on my machine there is only one
> SelectorRunner by default).
Ok.

> I'm surprised by this because if I change the implementation a bit
> so that connections are lazily created during invocation of a
> subsequent Filter.handleRead event then everything works ok, simply
> because there are more worker threads than selectors.
Understand.


> Of course, this approach is still flawed and a self-deadlock is
> still possible. E.g. if there are N Grizzly worker threads and each
> performs N synchronous IO operations then there will be no worker
> threads available to service the IO events and close the Futures.
> The correct approach, I assume (correct me if I am wrong) is to hand-
> off work like this to a separate worker thread pool and leave
> Grizzly selectors/workers to service just the IO events.
>
> However, I do find this behavior surprising. I imagined that all
> handleXXX methods would be processed by Grizzly worker threads. Is
> it expected?
It may vary, depending on IOStrategy you may chose
(transport.setStrategy()):

WorkerThreadStrategy (default one) uses worker threads to execute I/O
events, except CONNECT and ACCEPT events (the intent was to make
ACCEPT, CONNECT more optimal, but may be we should change it to be
consistent for all)
If you'll chose SameThreadStrategy *all* the I/O events in a
FilterChain will be processed by Selector threads. This strategy might
be optimal for non-blocking usecases.

In general, IMO it would be good to not use blocking operations inside
the filterchains. Here is the sample code you might want to use for
handleAccept operation [1]

Thanks.

WBR,
Alexey.

[1]
     @Override
     public NextAction handleAccept(final FilterChainContext ctx)
throws IOException {
         final Connection connection = ctx.getConnection();

         final TCPNIOTransport transport =
                 (TCPNIOTransport) connection.getTransport();

         final SocketConnectorHandler connectorHandler =
                 new TCPNIOConnectorHandler(transport);

         connectorHandler.setProcessor(redirectChain);

         connectorHandler.connect(new InetSocketAddress(redirectHost,
redirectPort),
                 new EmptyCompletionHandler<Connection>() {

                     @Override
                     public void completed(Connection peerConnection) {
                         AttrUtil.setPeer(connection, peerConnection);
                         AttrUtil.setPeer(peerConnection, connection);
                         resume();
                     }

                     @Override
                     public void failed(Throwable throwable) {
                         try {
                             connection.close();
                         } catch (IOException ignored) {
                         }

                         resume();
                     }

                     private void resume() {
                         ctx.setFilterIdx(ctx.getFilterIdx() + 1);
                         ctx.resume();
                     }
                 });

         return ctx.getSuspendAction();
     }

>
> Cheers,
>
> Matt
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>