users@grizzly.java.net

Re: LinuxSpinningWorkaround & managing connections

From: Alexei Dets <adets_at_idsk.com>
Date: Thu, 24 Sep 2009 18:21:11 -0400

Hi!
Jeanfrancois Arcand wrote:
> Take a look at the ThreadAttachement API. I'm sure that will meet your
> needs.

Hmm, I didn't look at this because previously some filters (AFAIR as usual
it was ParserProtocolFilter) had a habit of removing ThreadAttachement from
SelectionKey and so there was no way to get the associated info in the
SelectionKeyHandler.cancel (or ConnectionCloseHandler) as they are not
necessary called from the WorkerThread.

I've tried this again now and indeed this approach seems to work now. I'll
describe what I did, please correct me if I forgot something or something
can be simplified (this will be nice).

So, to be able to track connections in Grizzly 1.9.x I had to:
1. Create FooSelectionKeyAttachment extends
SelectionKeyAttachmentWrapper<Object> that adds one private field foo and
one method to get it: getFoo().
2. Create a FooCallbackHandler that in onConnect attaches
FooSelectionKeyAttachment with Foo to SelectionKey. Before attaching, it
does FooSelectionKeyAttachment.setAttachment(key.attachment()) to preserve
existing attachment (i.e. Long or CallbackHandler) and not interfer with
the framework internals.
3. Do the same in the FooSelectorHandler.onAcceptInterest. Unfortunately
this also involves the copying of complete
TCPSelectorHandler.onAcceptInterest method code - there is no analogue to
CallbackHandler.onConnect method and so this seems to be the only way to
get access to the _accepted_ connection's SelectionKey.
4. Create a SaveFooFilter. This filter's job is to copy Foo from
SelectionKey's attachment to the attribute in the WorkerThread's
ThreadAttachment before some other filter will decide to screw everything
and override the SelectionKey's attachment.
6. Put SaveFooFilter first in the protocol chain (otherwise it can be too
late).
5. Create somewhere a method to get connection's Foo that looks like this:

Foo getFoo(SelectionKey key) {
        Foo foo;
        Object attachment = key.attachment();
        if (attachment instanceof FooSelectionKeyAttachment) {
                foo = ((FooSelectionKeyAttachment) attachment).getFoo();
        } else if (attachment instanceof ThreadAttachment) {
                foo = (Foo) ((ThreadAttachment) attachment).getAttribute("FOO");
        } else if (Thread.currentThread() instanceof WorkerThread) {
foo=(Foo((WorkerThread)Thread.currentThread()).getAttachment().getAttribute("FOO");
        } else {
                foo = null;
        }
        return foo;
}

And so far after these six easy and obvious steps it seems to work fine ;-)

However, I have two wishes ;-)

In Grizzly 2.x please add (if not already) some ability to set (and get back
at any time) an application context info to connection without undergoing
all these steps. And teach all filters that this is an _application_-level
info and they shouldn't ever touch it.

I think in order to implement the basis for such support Grizzly should
always attach to SelectionKey only the instances of AttributeHolder or
something like this:
public interface SelectionKeyAttachment {
 getFrameworkAttachment();
 getApplicationAttachment();
}
And all framework code should touch only frameworkAttachment (or its own
attributes). And it should never remove the key attachment (except the case
after the connection is terminated).

        Regards,
                Alexei

PS. Grizzly has a great community and very helpful & friendly developers and
this is its big plus! ;-)